Makelore 2.0 initial clean snapshot
This commit is contained in:
685
tests/unit/opencode-message.test.ts
Normal file
685
tests/unit/opencode-message.test.ts
Normal file
@@ -0,0 +1,685 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { applyStreamingPartDeltaToMessage, normalizeOpencodeSessionMessages } from '@/lib/opencode-message';
|
||||
|
||||
describe('opencode message normalization', () => {
|
||||
it('keeps reasoning deltas as thinking content when the full part has not arrived yet', () => {
|
||||
const message = applyStreamingPartDeltaToMessage(null, {
|
||||
sessionID: 'ses_1',
|
||||
messageID: 'msg_assistant',
|
||||
partID: 'part_reasoning',
|
||||
field: 'text',
|
||||
delta: 'Reviewing the project flow.',
|
||||
part: {
|
||||
id: 'part_reasoning',
|
||||
type: 'reasoning',
|
||||
},
|
||||
});
|
||||
|
||||
expect(message).toEqual(expect.objectContaining({
|
||||
id: 'msg_assistant',
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'thinking',
|
||||
id: 'part_reasoning',
|
||||
thinking: 'Reviewing the project flow.',
|
||||
},
|
||||
],
|
||||
}));
|
||||
});
|
||||
|
||||
it('surfaces a completed assistant message with no visible content as an error', () => {
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
{
|
||||
info: {
|
||||
id: 'msg_empty_assistant',
|
||||
role: 'assistant',
|
||||
sessionID: 'ses_1',
|
||||
time: { created: 1747040000000, completed: 1747040001000 },
|
||||
},
|
||||
parts: [
|
||||
{ id: 'step_start', type: 'step-start' },
|
||||
{ id: 'step_finish', type: 'step-finish' },
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'msg_empty_assistant',
|
||||
role: 'assistant',
|
||||
isError: true,
|
||||
errorMessage: '模型没有返回任何内容。请重试,或切换到支持图片输入的模型。',
|
||||
content: [{
|
||||
type: 'text',
|
||||
text: '模型没有返回任何内容。请重试,或切换到支持图片输入的模型。',
|
||||
}],
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('retains bounded runtime tool evidence without exposing raw tool state', () => {
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
{
|
||||
info: {
|
||||
id: 'msg_tool_evidence',
|
||||
role: 'assistant',
|
||||
time: { created: 1747040000000, completed: 1747040001000 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'tool_build',
|
||||
callID: 'call_build',
|
||||
type: 'tool',
|
||||
tool: 'bash',
|
||||
state: {
|
||||
status: 'completed',
|
||||
input: { command: 'pnpm build' },
|
||||
output: 'build completed',
|
||||
metadata: { exit: 0 },
|
||||
time: { start: 1747040000000, end: 1747040000500 },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages[0]?._toolEvidence).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'tool_build',
|
||||
toolCallId: 'call_build',
|
||||
name: 'bash',
|
||||
status: 'completed',
|
||||
inputSummary: expect.stringContaining('pnpm build'),
|
||||
exitCode: 0,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('preserves bounded user runtime context and only the true synthetic bit', () => {
|
||||
const [message] = normalizeOpencodeSessionMessages([{
|
||||
info: {
|
||||
id: 'msg_user',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_000 },
|
||||
agent: 'game-development',
|
||||
model: {
|
||||
providerID: 'niancode-user-models',
|
||||
modelID: 'qwen3.7-plus',
|
||||
variant: 'high',
|
||||
},
|
||||
system: 'SECRET SYSTEM PROMPT',
|
||||
},
|
||||
parts: [
|
||||
{ id: 'part_visible', type: 'text', text: 'Visible request', synthetic: false },
|
||||
{ id: 'part_hidden', type: 'text', text: 'Injected context', synthetic: true },
|
||||
],
|
||||
}]);
|
||||
|
||||
expect(message?._runtimeContext).toEqual({
|
||||
agent: 'game-development',
|
||||
model: 'niancode-user-models/qwen3.7-plus',
|
||||
variant: 'high',
|
||||
});
|
||||
expect(message?.content).toEqual([
|
||||
{ id: 'part_visible', type: 'text', text: 'Visible request' },
|
||||
{ id: 'part_hidden', type: 'text', text: 'Injected context', synthetic: true },
|
||||
]);
|
||||
expect(JSON.stringify(message)).not.toContain('SECRET SYSTEM PROMPT');
|
||||
});
|
||||
|
||||
it('drops oversized runtime identifiers instead of retaining arbitrary metadata', () => {
|
||||
const [message] = normalizeOpencodeSessionMessages([{
|
||||
info: {
|
||||
id: 'msg_user',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_000 },
|
||||
agent: 'a'.repeat(200),
|
||||
model: {
|
||||
providerID: 'provider',
|
||||
modelID: 'model',
|
||||
variant: 'v'.repeat(200),
|
||||
},
|
||||
},
|
||||
parts: [{ type: 'text', text: 'Hello' }],
|
||||
}]);
|
||||
|
||||
expect(message?._runtimeContext).toEqual({ model: 'provider/model' });
|
||||
});
|
||||
|
||||
it('renders only a persisted command invocation and its whitelisted context', () => {
|
||||
const [message] = normalizeOpencodeSessionMessages([{
|
||||
info: {
|
||||
id: 'msg_command',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_000 },
|
||||
agent: 'game-development',
|
||||
model: {
|
||||
providerID: 'niancode-user-models',
|
||||
modelID: 'qwen3.7-plus',
|
||||
},
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_invocation',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: ' raw arguments ',
|
||||
contextPartIDs: ['prt_context', 'prt_image'],
|
||||
},
|
||||
{
|
||||
id: 'prt_template',
|
||||
type: 'text',
|
||||
text: 'PRIVATE EXPANDED TEMPLATE',
|
||||
synthetic: true,
|
||||
},
|
||||
{
|
||||
id: 'prt_context',
|
||||
type: 'text',
|
||||
text: 'Bounded selected path context',
|
||||
synthetic: true,
|
||||
},
|
||||
{
|
||||
id: 'prt_image',
|
||||
type: 'file',
|
||||
mime: 'image/webp',
|
||||
filename: 'screen.webp',
|
||||
url: 'data:image/webp;base64,QUFB',
|
||||
},
|
||||
{
|
||||
id: 'prt_plugin',
|
||||
type: 'text',
|
||||
text: 'PRIVATE PLUGIN TEXT',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
}]);
|
||||
|
||||
expect(message?.content?.[0]).toEqual({
|
||||
id: 'prt_invocation',
|
||||
type: 'text',
|
||||
text: '/Review raw arguments ',
|
||||
});
|
||||
expect(JSON.stringify(message)).toContain('Bounded selected path context');
|
||||
expect(message?._attachedFiles ?? []).toHaveLength(1);
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE EXPANDED TEMPLATE');
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE PLUGIN TEXT');
|
||||
expect(JSON.stringify(message)).not.toContain('contextPartIDs');
|
||||
});
|
||||
|
||||
it('fails closed when a command invocation marker is malformed or duplicated', () => {
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
{
|
||||
info: {
|
||||
id: 'msg_malformed',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_000 },
|
||||
agent: 'game-development',
|
||||
model: { providerID: 'provider', modelID: 'model' },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_bad',
|
||||
type: 'command-invocation',
|
||||
command: '',
|
||||
arguments: '',
|
||||
contextPartIDs: ['not-a-part-id'],
|
||||
},
|
||||
{ id: 'prt_template', type: 'text', text: 'PRIVATE MALFORMED TEMPLATE', synthetic: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
info: {
|
||||
id: 'msg_duplicated',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_001 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_first',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_context'],
|
||||
},
|
||||
{
|
||||
id: 'prt_second',
|
||||
type: 'command-invocation',
|
||||
command: 'Explain',
|
||||
arguments: '',
|
||||
contextPartIDs: [],
|
||||
},
|
||||
{
|
||||
id: 'prt_context',
|
||||
type: 'text',
|
||||
text: 'PRIVATE DUPLICATED TEMPLATE',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
info: {
|
||||
id: 'msg_control',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_002 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_control',
|
||||
type: 'command-invocation',
|
||||
command: 'Review\u0000hidden',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_control_context'],
|
||||
},
|
||||
{
|
||||
id: 'prt_control_context',
|
||||
type: 'text',
|
||||
text: 'PRIVATE CONTROL TEMPLATE',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
info: {
|
||||
id: 'msg_invalid_marker_id',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_000_003 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'arbitrary-renderer-id',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_invalid_id_context'],
|
||||
},
|
||||
{
|
||||
id: 'prt_invalid_id_context',
|
||||
type: 'text',
|
||||
text: 'PRIVATE INVALID ID TEMPLATE',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages).toHaveLength(4);
|
||||
for (const message of messages) {
|
||||
expect(message.content).toEqual([{
|
||||
type: 'text',
|
||||
text: '[Project command metadata unavailable]',
|
||||
}]);
|
||||
expect(message._attachedFiles ?? []).toEqual([]);
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE');
|
||||
}
|
||||
});
|
||||
|
||||
it('fails closed for command markers on every non-user role', () => {
|
||||
const messages = normalizeOpencodeSessionMessages(
|
||||
['assistant', 'system', 'unknown-runtime-role'].map((role, index) => ({
|
||||
info: {
|
||||
id: `msg_non_user_${index}`,
|
||||
role,
|
||||
time: { created: 1_700_000_001_000 + index },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: `prt_marker_${index}`,
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '--private',
|
||||
contextPartIDs: [`prt_private_${index}`, `prt_file_${index}`, `prt_tool_${index}`],
|
||||
},
|
||||
{
|
||||
id: `prt_private_${index}`,
|
||||
type: 'text',
|
||||
text: `PRIVATE_ROLE_${index}`,
|
||||
synthetic: true,
|
||||
},
|
||||
{
|
||||
id: `prt_file_${index}`,
|
||||
type: 'file',
|
||||
mime: 'image/png',
|
||||
filename: 'private.png',
|
||||
url: 'data:image/png;base64,QUFB',
|
||||
},
|
||||
{
|
||||
id: `prt_tool_${index}`,
|
||||
type: 'tool',
|
||||
tool: 'bash',
|
||||
state: { input: { command: 'print-private-data' } },
|
||||
},
|
||||
],
|
||||
})),
|
||||
);
|
||||
|
||||
expect(messages).toHaveLength(3);
|
||||
for (const message of messages) {
|
||||
expect(message.content).toEqual([{
|
||||
type: 'text',
|
||||
text: '[Project command metadata unavailable]',
|
||||
}]);
|
||||
expect(message._attachedFiles ?? []).toEqual([]);
|
||||
expect(message._toolEvidence ?? []).toEqual([]);
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE_ROLE');
|
||||
expect(JSON.stringify(message)).not.toContain('print-private-data');
|
||||
expect(JSON.stringify(message)).not.toContain('--private');
|
||||
}
|
||||
});
|
||||
|
||||
it('never renders tool or reasoning parts referenced by a valid user command marker', () => {
|
||||
const [message] = normalizeOpencodeSessionMessages([{
|
||||
info: {
|
||||
id: 'msg_user_unsafe_context',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_001_500 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_user_unsafe_marker',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: 'safe arguments',
|
||||
contextPartIDs: [
|
||||
'prt_user_safe_text',
|
||||
'prt_user_private_reasoning',
|
||||
'prt_user_private_tool',
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'prt_user_safe_text',
|
||||
type: 'text',
|
||||
text: 'Visible selected context',
|
||||
synthetic: true,
|
||||
},
|
||||
{
|
||||
id: 'prt_user_private_reasoning',
|
||||
type: 'reasoning',
|
||||
text: 'PRIVATE_REASONING',
|
||||
},
|
||||
{
|
||||
id: 'prt_user_private_tool',
|
||||
callID: 'call_user_private_tool',
|
||||
type: 'tool',
|
||||
tool: 'bash',
|
||||
state: {
|
||||
status: 'completed',
|
||||
input: { command: 'PRIVATE_TOOL_INPUT' },
|
||||
},
|
||||
},
|
||||
],
|
||||
}]);
|
||||
|
||||
expect(message?.content).toEqual([
|
||||
{
|
||||
id: 'prt_user_unsafe_marker',
|
||||
type: 'text',
|
||||
text: '/Review safe arguments',
|
||||
},
|
||||
{
|
||||
id: 'prt_user_safe_text',
|
||||
type: 'text',
|
||||
text: 'Visible selected context',
|
||||
synthetic: true,
|
||||
},
|
||||
]);
|
||||
expect(message?._toolEvidence ?? []).toEqual([]);
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE_REASONING');
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE_TOOL_INPUT');
|
||||
});
|
||||
|
||||
it('fails closed for malformed structured-like and legacy command marker shapes', () => {
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
{
|
||||
id: 'msg_missing_info',
|
||||
role: 'user',
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_missing_info',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_missing_info_private'],
|
||||
},
|
||||
{
|
||||
id: 'prt_missing_info_private',
|
||||
type: 'text',
|
||||
text: 'PRIVATE_MISSING_INFO',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
info: {
|
||||
id: 'msg_non_array_parts',
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_002_000 },
|
||||
},
|
||||
parts: {
|
||||
marker: {
|
||||
id: 'prt_non_array',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_non_array_private'],
|
||||
},
|
||||
privatePart: {
|
||||
id: 'prt_non_array_private',
|
||||
type: 'text',
|
||||
text: 'PRIVATE_NON_ARRAY_PARTS',
|
||||
synthetic: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'msg_legacy_array',
|
||||
role: 'user',
|
||||
content: [
|
||||
{
|
||||
id: 'prt_legacy_marker',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_legacy_private'],
|
||||
},
|
||||
{
|
||||
id: 'prt_legacy_private',
|
||||
type: 'text',
|
||||
text: 'PRIVATE_LEGACY_ARRAY',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'msg_array_info',
|
||||
info: [],
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_array_info_marker',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: ['prt_array_info_private'],
|
||||
},
|
||||
{
|
||||
id: 'prt_array_info_private',
|
||||
type: 'text',
|
||||
text: 'PRIVATE_ARRAY_INFO',
|
||||
synthetic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'msg_ordinary_legacy',
|
||||
role: 'assistant',
|
||||
content: 'Ordinary legacy content',
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages).toHaveLength(5);
|
||||
for (const message of messages.slice(0, 4)) {
|
||||
expect(message.content).toEqual([{
|
||||
type: 'text',
|
||||
text: '[Project command metadata unavailable]',
|
||||
}]);
|
||||
expect(message._attachedFiles ?? []).toEqual([]);
|
||||
expect(message._toolEvidence ?? []).toEqual([]);
|
||||
expect(JSON.stringify(message)).not.toContain('PRIVATE');
|
||||
expect(JSON.stringify(message)).not.toContain('command-invocation');
|
||||
}
|
||||
expect(messages[4]?.content).toEqual([{
|
||||
type: 'text',
|
||||
text: 'Ordinary legacy content',
|
||||
}]);
|
||||
});
|
||||
|
||||
it('preserves legacy normalization for structured-like records without a command marker', () => {
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
{
|
||||
id: 'msg_legacy_info',
|
||||
role: 'assistant',
|
||||
text: 'Legacy info content',
|
||||
info: { source: 'legacy-adapter' },
|
||||
},
|
||||
{
|
||||
id: 'msg_legacy_parts',
|
||||
role: 'assistant',
|
||||
text: 'Legacy parts content',
|
||||
parts: { source: 'legacy-adapter' },
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages).toEqual([
|
||||
{
|
||||
id: 'msg_legacy_info',
|
||||
role: 'assistant',
|
||||
timestamp: undefined,
|
||||
content: [{ type: 'text', text: 'Legacy info content' }],
|
||||
},
|
||||
{
|
||||
id: 'msg_legacy_parts',
|
||||
role: 'assistant',
|
||||
timestamp: undefined,
|
||||
content: [{ type: 'text', text: 'Legacy parts content' }],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('requires string arguments and enforces command selector bounds', () => {
|
||||
const invalidArguments: unknown[] = [undefined, null, 42, { private: true }];
|
||||
const messages = normalizeOpencodeSessionMessages([
|
||||
...invalidArguments.map((argumentsValue, index) => ({
|
||||
info: {
|
||||
id: `msg_bad_arguments_${index}`,
|
||||
role: 'user',
|
||||
time: { created: 1_700_000_003_000 + index },
|
||||
},
|
||||
parts: [{
|
||||
id: `prt_bad_arguments_${index}`,
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
...(argumentsValue === undefined ? {} : { arguments: argumentsValue }),
|
||||
contextPartIDs: [],
|
||||
}],
|
||||
})),
|
||||
{
|
||||
info: { id: 'msg_whitespace_command', role: 'user' },
|
||||
parts: [{
|
||||
id: 'prt_whitespace_command',
|
||||
type: 'command-invocation',
|
||||
command: ' Review',
|
||||
arguments: '',
|
||||
contextPartIDs: [],
|
||||
}],
|
||||
},
|
||||
{
|
||||
info: { id: 'msg_leading_slash_command', role: 'user' },
|
||||
parts: [{
|
||||
id: 'prt_leading_slash_command',
|
||||
type: 'command-invocation',
|
||||
command: '/Review',
|
||||
arguments: '',
|
||||
contextPartIDs: [],
|
||||
}],
|
||||
},
|
||||
{
|
||||
info: { id: 'msg_oversized_arguments', role: 'user' },
|
||||
parts: [{
|
||||
id: 'prt_oversized_arguments',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: 'a'.repeat(8_193),
|
||||
contextPartIDs: [],
|
||||
}],
|
||||
},
|
||||
{
|
||||
info: { id: 'msg_too_many_context_ids', role: 'user' },
|
||||
parts: [{
|
||||
id: 'prt_too_many_context_ids',
|
||||
type: 'command-invocation',
|
||||
command: 'Review',
|
||||
arguments: '',
|
||||
contextPartIDs: Array.from({ length: 65 }, (_, index) => `prt_context_${index}`),
|
||||
}],
|
||||
},
|
||||
]);
|
||||
|
||||
expect(messages).toHaveLength(8);
|
||||
for (const message of messages) {
|
||||
expect(message.content).toEqual([{
|
||||
type: 'text',
|
||||
text: '[Project command metadata unavailable]',
|
||||
}]);
|
||||
expect(message._attachedFiles ?? []).toEqual([]);
|
||||
}
|
||||
});
|
||||
|
||||
it('does not mistake a large ordinary tool payload for command metadata', () => {
|
||||
const [message] = normalizeOpencodeSessionMessages([{
|
||||
info: {
|
||||
id: 'msg_large_tool_payload',
|
||||
role: 'assistant',
|
||||
time: { created: 1_700_000_005_000 },
|
||||
},
|
||||
parts: [
|
||||
{
|
||||
id: 'prt_visible_result',
|
||||
type: 'text',
|
||||
text: 'Visible assistant result',
|
||||
},
|
||||
{
|
||||
id: 'prt_large_tool',
|
||||
callID: 'call_large_tool',
|
||||
type: 'tool',
|
||||
tool: 'inspect',
|
||||
state: {
|
||||
status: 'completed',
|
||||
input: Array.from({ length: 4_100 }, (_, index) => ({ index })),
|
||||
output: 'Inspection complete',
|
||||
},
|
||||
},
|
||||
],
|
||||
}]);
|
||||
|
||||
expect(message?.content).toEqual([
|
||||
{
|
||||
id: 'prt_visible_result',
|
||||
type: 'text',
|
||||
text: 'Visible assistant result',
|
||||
},
|
||||
expect.objectContaining({
|
||||
id: 'call_large_tool',
|
||||
type: 'tool_use',
|
||||
name: 'inspect',
|
||||
}),
|
||||
]);
|
||||
expect(message?._toolEvidence).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'prt_large_tool',
|
||||
toolCallId: 'call_large_tool',
|
||||
name: 'inspect',
|
||||
status: 'completed',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user