@@ -89,61 +89,67 @@ function short(s) {
8989}
9090
9191/**
92- * Interprets the content array of from an OpenAI payload into a string for display.
92+ * Interprets a message- content array into text for display.
9393 * If we're given undefined, returns an empty string.
9494 */
95- function content (contents) {
95+ function contentText (contents) {
9696 if (typeof contents === 'string') return contents;
97+ if (!Array.isArray(contents)) return JSON.stringify(contents ?? '');
9798 let r = [];
9899 for (const c of contents ?? []) {
99100 if (c.type === 'input_text') r.push(c.text);
100101 else if (c.type === 'output_text') r.push(c.text);
102+ else if (c.type === 'text') r.push(c.text);
101103 else r.push(\`[\${c.type}]\`);
102104 }
103105 return r.join('\\n');
104106}
105107
106108/**
107- * Renders a sequence of elements from an OpenAI payload: messages, function_calls, function_call_outputs .
109+ * Renders a sequence of payload elements from either OpenAI or Anthropic payloads .
108110 */
109111function renderPayload(elements) {
112+ if (!Array.isArray(elements)) return [];
110113 const payload = [];
111114 for (const e of elements) {
112115 if (e === '...') {
113116 payload.push({[TITLE]: 'Added...'});
114117 } else if (e === '---') {
115118 payload.push({[TITLE]: 'Removed...'});
116- } else if (e.type === 'message') {
119+ } else if (e.type === 'message' || (e.type === undefined && e.role !== undefined && e.content !== undefined) ) {
117120 payload.push({
118121 [TITLE]: \`\${payload.length}: message(\${esc(e.role)}): \`,
119- [INLINE]: esc(short(content (e.content))),
120- body: content (e.content),
122+ [INLINE]: esc(short(contentText (e.content))),
123+ body: contentText (e.content),
121124 });
122- } else if (e.type === 'input_text' || e.type === 'output_text') {
125+ } else if (e.type === 'input_text' || e.type === 'output_text' || e.type === 'text' ) {
123126 payload.push({
124127 [TITLE]: \`\${payload.length}: \${e.type}: \`,
125128 [INLINE]: esc(short(e.text)),
126129 body: e.text,
127130 });
128131
129- } else if (e.type === 'function_call_output') {
132+ } else if (e.type === 'function_call_output' || e.type === 'tool_result') {
133+ const result = (e.type === 'function_call_output') ?
134+ (typeof e.output === 'string' ? e.output : JSON.stringify(e.output ?? ''))
135+ : typeof e.content === 'string' ? e.content : contentText(e.content);
130136 payload.push({
131137 [TITLE]: \`\${payload.length}: \`,
132- [INLINE]: \`function_call_output : \${esc(short(e.output ))}\`,
138+ [INLINE]: \`\${esc(e.type)} : \${esc(short(result ))}\`,
133139 body: e,
134140 });
135- } else if (e.type === 'function_call') {
136- let arg;
141+ } else if (e.type === 'function_call' || e.type === 'tool_use' ) {
142+ let arg = "" ;
137143 try {
138- const j = JSON.parse(e.arguments);
139- arg = j .cmd ?? j .pattern;
140- arg = \`"\${esc(short(arg))}"\` ;
144+ const raw = e.type === 'function_call' ? JSON.parse(e.arguments) : e.input ;
145+ const rawArg = raw? .cmd ?? raw? .pattern ?? raw ;
146+ arg = typeof rawArg === 'string' ? rawArg : JSON.stringify(rawArg ?? '') ;
141147 } catch (e) {
142148 arg = '...';
143149 }
144150 payload.push({
145151 [TITLE]: \`\${payload.length}: \`,
146- [INLINE]: \`function_call : \${esc(e.name)}(\${esc(short(arg))})\`,
152+ [INLINE]: \`\${esc(e.type)} : \${esc(e.name ?? '???' )}(\${esc(short(arg))})\`,
147153 body: e,
148154 });
149155 } else {
@@ -163,24 +169,13 @@ function renderPayload(elements) {
163169 * Otherwise, renders primtives, objects, arrays in the obvious way.
164170 */
165171function render(data, label) {
172+ const deltaField = (key) => data[key] ?? data[\`\${key}+\`] ?? data[\`\${key}-\`] ?? data[\`*\${key}\`];
166173 const id = data?._id !== undefined ? \` #\${data._id}\` : '';
167174 const purpose = data?._purpose ? \` \${data._purpose}\` : '';
168175 if (data?.[TITLE] !== undefined) {
169176 return data;
170177 } else if (data?._kind === 'request') {
171- const input = data['input'] ?? data['input+'] ?? data['input-'] ?? data['*input'] ?? [];
172- // OpenCode request bodies can mix message wrappers like
173- // \`{role:'user', content:[{type:'input_text', text:'...'}]}\` with already-typed items like
174- // \`{type:'function_call', ...}\`. Flatten wrapper objects to their \`content\` items so \`payload\`
175- // is always a list of typed entries like \`{type:'input_text', ...}\` or \`{type:'function_call', ...}\`.
176- const payload = input.flatMap(e =>
177- e && typeof e === 'object' && !Array.isArray(e) && e.type === undefined && Array.isArray(e.content)
178- ? e.content
179- : e && typeof e === 'object' && !Array.isArray(e) && e.type === undefined && typeof e.content === 'string'
180- ? [{type: 'input_text', text: e.content}]
181- : [e],
182- );
183- const rendered = renderPayload(payload);
178+ const rendered = renderPayload(deltaField('input') ?? deltaField('messages'));
184179 const raw = {...data};
185180 delete raw._kind;
186181 return {
@@ -189,9 +184,7 @@ function render(data, label) {
189184 open: true,
190185 };
191186 } else if (data?._kind === 'response') {
192- const payload = renderPayload(
193- data['output'] ?? data['output+'] ?? data['output-'] ?? data['*output'] ?? [],
194- );
187+ const payload = renderPayload(deltaField('output') ?? deltaField('content'));
195188 const raw = {...data};
196189 delete raw._kind;
197190 return {
0 commit comments