@oh-my-pi/pi-agent-core 17.0.0 → 17.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/types/agent-loop.d.ts +8 -1
- package/dist/types/agent.d.ts +2 -0
- package/dist/types/proxy.d.ts +5 -1
- package/package.json +9 -9
- package/src/agent-loop.ts +30 -20
- package/src/agent.ts +75 -14
- package/src/proxy.ts +11 -0
- package/src/telemetry.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [17.0.2] - 2026-07-17
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Improved error visibility in interactive clients by surfacing provider stream failures through the assistant message lifecycle, preventing silent loading spinners.
|
|
10
|
+
- Fixed an issue where Cursor provider contexts omitted host-supplied MCP tools from main and side-channel requests.
|
|
11
|
+
|
|
5
12
|
## [17.0.0] - 2026-07-15
|
|
6
13
|
|
|
7
14
|
### Breaking Changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Agent loop that works with AgentMessage throughout.
|
|
3
3
|
* Transforms to Message[] only at the LLM call boundary.
|
|
4
4
|
*/
|
|
5
|
-
import { type Context, EventStream } from "@oh-my-pi/pi-ai";
|
|
5
|
+
import { type AssistantMessage, type Context, EventStream, type ToolResultMessage } from "@oh-my-pi/pi-ai";
|
|
6
6
|
import { type Dialect } from "@oh-my-pi/pi-ai/dialect";
|
|
7
7
|
import { type AgentRunCoverage, type AgentRunSummary } from "./run-collector.js";
|
|
8
8
|
import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types.js";
|
|
@@ -111,3 +111,10 @@ export interface SyntheticToolResultDetails {
|
|
|
111
111
|
executed: false;
|
|
112
112
|
upstreamError?: string;
|
|
113
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Create the persisted synthetic result for a tool call that was emitted by
|
|
116
|
+
* the assistant but never invoked locally.
|
|
117
|
+
*/
|
|
118
|
+
export declare function createSyntheticToolResultMessage(toolCall: Extract<AssistantMessage["content"][number], {
|
|
119
|
+
type: "toolCall";
|
|
120
|
+
}>, reason: "aborted" | "error" | "skipped" | "length", errorMessage?: string): ToolResultMessage<SyntheticToolResultDetails>;
|
package/dist/types/agent.d.ts
CHANGED
|
@@ -157,6 +157,8 @@ export interface AgentOptions {
|
|
|
157
157
|
* Cursor exec handlers for local tool execution.
|
|
158
158
|
*/
|
|
159
159
|
cursorExecHandlers?: CursorExecHandlers;
|
|
160
|
+
/** Additional tools Cursor executes through its MCP request-context bridge, resolved before each provider call. */
|
|
161
|
+
getCursorTools?: () => AgentTool[];
|
|
160
162
|
/**
|
|
161
163
|
* Cursor tool result callback for exec tool responses.
|
|
162
164
|
*/
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Proxy stream function for apps that route LLM calls through a server.
|
|
3
3
|
* The server manages auth and proxies requests to LLM providers.
|
|
4
4
|
*/
|
|
5
|
-
import { type AssistantMessage, type AssistantMessageEvent, type Context, EventStream, type FetchImpl, type Model, type SimpleStreamOptions, type StopReason } from "@oh-my-pi/pi-ai";
|
|
5
|
+
import { type AssistantMessage, type AssistantMessageEvent, type Context, EventStream, type FetchImpl, type ImageContent, type Model, type SimpleStreamOptions, type StopReason } from "@oh-my-pi/pi-ai";
|
|
6
6
|
export declare class ProxyMessageEventStream extends EventStream<AssistantMessageEvent, AssistantMessage> {
|
|
7
7
|
constructor();
|
|
8
8
|
}
|
|
@@ -33,6 +33,10 @@ export type ProxyAssistantMessageEvent = {
|
|
|
33
33
|
type: "thinking_end";
|
|
34
34
|
contentIndex: number;
|
|
35
35
|
contentSignature?: string;
|
|
36
|
+
} | {
|
|
37
|
+
type: "image_end";
|
|
38
|
+
contentIndex: number;
|
|
39
|
+
content: ImageContent;
|
|
36
40
|
} | {
|
|
37
41
|
type: "toolcall_start";
|
|
38
42
|
contentIndex: number;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-agent-core",
|
|
4
|
-
"version": "17.0.
|
|
4
|
+
"version": "17.0.2",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,17 +35,17 @@
|
|
|
35
35
|
"fmt": "biome format --write ."
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@oh-my-pi/pi-ai": "17.0.
|
|
39
|
-
"@oh-my-pi/pi-catalog": "17.0.
|
|
40
|
-
"@oh-my-pi/pi-natives": "17.0.
|
|
41
|
-
"@oh-my-pi/pi-utils": "17.0.
|
|
42
|
-
"@oh-my-pi/pi-wire": "17.0.
|
|
43
|
-
"@oh-my-pi/snapcompact": "17.0.
|
|
38
|
+
"@oh-my-pi/pi-ai": "17.0.2",
|
|
39
|
+
"@oh-my-pi/pi-catalog": "17.0.2",
|
|
40
|
+
"@oh-my-pi/pi-natives": "17.0.2",
|
|
41
|
+
"@oh-my-pi/pi-utils": "17.0.2",
|
|
42
|
+
"@oh-my-pi/pi-wire": "17.0.2",
|
|
43
|
+
"@oh-my-pi/snapcompact": "17.0.2",
|
|
44
44
|
"@opentelemetry/api": "^1.9.1"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@opentelemetry/context-async-hooks": "^2.
|
|
48
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
47
|
+
"@opentelemetry/context-async-hooks": "^2.9.0",
|
|
48
|
+
"@opentelemetry/sdk-trace-base": "^2.9.0",
|
|
49
49
|
"@types/bun": "^1.3.14"
|
|
50
50
|
},
|
|
51
51
|
"engines": {
|
package/src/agent-loop.ts
CHANGED
|
@@ -183,6 +183,7 @@ type AssistantToolCallBlock = Extract<AssistantContentBlock, { type: "toolCall"
|
|
|
183
183
|
function snapshotAssistantContentBlock(block: AssistantContentBlock): AssistantContentBlock {
|
|
184
184
|
switch (block.type) {
|
|
185
185
|
case "text":
|
|
186
|
+
case "image":
|
|
186
187
|
return { ...block };
|
|
187
188
|
case "thinking":
|
|
188
189
|
return { ...block };
|
|
@@ -224,6 +225,7 @@ function snapshotAssistantMessageEvent(
|
|
|
224
225
|
case "text_start":
|
|
225
226
|
case "text_delta":
|
|
226
227
|
case "text_end":
|
|
228
|
+
case "image_end":
|
|
227
229
|
case "thinking_start":
|
|
228
230
|
case "thinking_delta":
|
|
229
231
|
case "thinking_end":
|
|
@@ -1525,6 +1527,7 @@ async function streamAssistantResponse(
|
|
|
1525
1527
|
case "text_start":
|
|
1526
1528
|
case "text_delta":
|
|
1527
1529
|
case "text_end":
|
|
1530
|
+
case "image_end":
|
|
1528
1531
|
case "thinking_start":
|
|
1529
1532
|
case "thinking_delta":
|
|
1530
1533
|
case "thinking_end":
|
|
@@ -2289,18 +2292,14 @@ function syntheticDetailsFor(
|
|
|
2289
2292
|
}
|
|
2290
2293
|
|
|
2291
2294
|
/**
|
|
2292
|
-
* Create
|
|
2293
|
-
* never invoked locally.
|
|
2294
|
-
* provider API requires, and tags {@link SyntheticToolResultDetails} so
|
|
2295
|
-
* consumers can distinguish this from a real local tool failure without
|
|
2296
|
-
* string-matching the content (#4321).
|
|
2295
|
+
* Create the persisted synthetic result for a tool call that was emitted by
|
|
2296
|
+
* the assistant but never invoked locally.
|
|
2297
2297
|
*/
|
|
2298
|
-
function
|
|
2298
|
+
export function createSyntheticToolResultMessage(
|
|
2299
2299
|
toolCall: Extract<AssistantMessage["content"][number], { type: "toolCall" }>,
|
|
2300
|
-
stream: EventStream<AgentEvent, AgentMessage[]>,
|
|
2301
2300
|
reason: "aborted" | "error" | "skipped" | "length",
|
|
2302
2301
|
errorMessage?: string,
|
|
2303
|
-
): ToolResultMessage {
|
|
2302
|
+
): ToolResultMessage<SyntheticToolResultDetails> {
|
|
2304
2303
|
const message =
|
|
2305
2304
|
reason === "aborted"
|
|
2306
2305
|
? "Tool execution was aborted"
|
|
@@ -2310,9 +2309,31 @@ function createAbortedToolResult(
|
|
|
2310
2309
|
? "Tool call was not executed because the assistant ended its turn"
|
|
2311
2310
|
: "Tool call was not executed because the provider stream ended with an error before the tool could run";
|
|
2312
2311
|
const details = syntheticDetailsFor(reason, errorMessage);
|
|
2313
|
-
|
|
2312
|
+
return {
|
|
2313
|
+
role: "toolResult",
|
|
2314
|
+
toolCallId: toolCall.id,
|
|
2315
|
+
toolName: toolCall.name,
|
|
2314
2316
|
content: [{ type: "text", text: errorMessage ? `${message}: ${errorMessage}` : `${message}.` }],
|
|
2315
2317
|
details,
|
|
2318
|
+
isError: true,
|
|
2319
|
+
timestamp: Date.now(),
|
|
2320
|
+
};
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
/**
|
|
2324
|
+
* Create and emit a tool result for a tool call that was emitted by the
|
|
2325
|
+
* assistant but never invoked locally.
|
|
2326
|
+
*/
|
|
2327
|
+
function createAbortedToolResult(
|
|
2328
|
+
toolCall: Extract<AssistantMessage["content"][number], { type: "toolCall" }>,
|
|
2329
|
+
stream: EventStream<AgentEvent, AgentMessage[]>,
|
|
2330
|
+
reason: "aborted" | "error" | "skipped" | "length",
|
|
2331
|
+
errorMessage?: string,
|
|
2332
|
+
): ToolResultMessage {
|
|
2333
|
+
const toolResultMessage = createSyntheticToolResultMessage(toolCall, reason, errorMessage);
|
|
2334
|
+
const result: AgentToolResult<SyntheticToolResultDetails> = {
|
|
2335
|
+
content: toolResultMessage.content,
|
|
2336
|
+
details: toolResultMessage.details,
|
|
2316
2337
|
};
|
|
2317
2338
|
|
|
2318
2339
|
stream.push({
|
|
@@ -2329,17 +2350,6 @@ function createAbortedToolResult(
|
|
|
2329
2350
|
result,
|
|
2330
2351
|
isError: true,
|
|
2331
2352
|
});
|
|
2332
|
-
|
|
2333
|
-
const toolResultMessage: ToolResultMessage<SyntheticToolResultDetails> = {
|
|
2334
|
-
role: "toolResult",
|
|
2335
|
-
toolCallId: toolCall.id,
|
|
2336
|
-
toolName: toolCall.name,
|
|
2337
|
-
content: result.content,
|
|
2338
|
-
details,
|
|
2339
|
-
isError: true,
|
|
2340
|
-
timestamp: Date.now(),
|
|
2341
|
-
};
|
|
2342
|
-
|
|
2343
2353
|
stream.push({ type: "message_start", message: toolResultMessage });
|
|
2344
2354
|
stream.push({ type: "message_end", message: toolResultMessage });
|
|
2345
2355
|
|
package/src/agent.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
abortReasonText,
|
|
32
32
|
agentLoop,
|
|
33
33
|
agentLoopContinue,
|
|
34
|
+
createSyntheticToolResultMessage,
|
|
34
35
|
normalizeMessagesForProvider,
|
|
35
36
|
normalizeTools,
|
|
36
37
|
resolveOwnedDialectFromEnv,
|
|
@@ -64,12 +65,6 @@ function defaultConvertToLlm(messages: AgentMessage[]): Message[] {
|
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
const ANTHROPIC_OUTPUT_BLOCKED_PREFIX = "Output blocked by conten";
|
|
68
|
-
|
|
69
|
-
function isAnthropicOutputBlockedError(message: string): boolean {
|
|
70
|
-
return message.includes(ANTHROPIC_OUTPUT_BLOCKED_PREFIX);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
68
|
function refreshToolChoiceForActiveTools(
|
|
74
69
|
toolChoice: ToolChoice | undefined,
|
|
75
70
|
tools: AgentContext["tools"] = [],
|
|
@@ -267,6 +262,8 @@ export interface AgentOptions {
|
|
|
267
262
|
* Cursor exec handlers for local tool execution.
|
|
268
263
|
*/
|
|
269
264
|
cursorExecHandlers?: CursorExecHandlers;
|
|
265
|
+
/** Additional tools Cursor executes through its MCP request-context bridge, resolved before each provider call. */
|
|
266
|
+
getCursorTools?: () => AgentTool[];
|
|
270
267
|
|
|
271
268
|
/**
|
|
272
269
|
* Cursor tool result callback for exec tool responses.
|
|
@@ -368,6 +365,7 @@ export class Agent {
|
|
|
368
365
|
#maxRetryDelayMs?: number;
|
|
369
366
|
#getToolContext?: (toolCall?: ToolCallContext) => AgentToolContext | undefined;
|
|
370
367
|
#cursorExecHandlers?: CursorExecHandlers;
|
|
368
|
+
#getCursorTools?: () => AgentTool[];
|
|
371
369
|
#cursorOnToolResult?: CursorToolResultHandler;
|
|
372
370
|
#cwd?: string;
|
|
373
371
|
#cwdResolver?: () => string | undefined;
|
|
@@ -450,6 +448,7 @@ export class Agent {
|
|
|
450
448
|
this.#onSseEvent = opts.onSseEvent;
|
|
451
449
|
this.#getToolContext = opts.getToolContext;
|
|
452
450
|
this.#cursorExecHandlers = opts.cursorExecHandlers;
|
|
451
|
+
this.#getCursorTools = opts.getCursorTools;
|
|
453
452
|
this.#cursorOnToolResult = opts.cursorOnToolResult;
|
|
454
453
|
this.#cwd = opts.cwd;
|
|
455
454
|
this.#cwdResolver = opts.cwdResolver;
|
|
@@ -694,6 +693,22 @@ export class Agent {
|
|
|
694
693
|
this.#appendOnlyContext = manager;
|
|
695
694
|
}
|
|
696
695
|
|
|
696
|
+
#toolsForModel(model: Model): AgentTool[] {
|
|
697
|
+
if (model.api !== "cursor-agent" || !this.#getCursorTools) return this.#state.tools;
|
|
698
|
+
const cursorTools = this.#getCursorTools();
|
|
699
|
+
if (cursorTools.length === 0) return this.#state.tools;
|
|
700
|
+
|
|
701
|
+
const names = new Set(this.#state.tools.map(tool => tool.name));
|
|
702
|
+
let merged: AgentTool[] | undefined;
|
|
703
|
+
for (const tool of cursorTools) {
|
|
704
|
+
if (names.has(tool.name)) continue;
|
|
705
|
+
merged ??= this.#state.tools.slice();
|
|
706
|
+
merged.push(tool);
|
|
707
|
+
names.add(tool.name);
|
|
708
|
+
}
|
|
709
|
+
return merged ?? this.#state.tools;
|
|
710
|
+
}
|
|
711
|
+
|
|
697
712
|
/**
|
|
698
713
|
* Assemble the provider Context for a side-channel (no-loop) request, mirroring
|
|
699
714
|
* the main loop's prefix (system + normalized tools) so it shares the prompt
|
|
@@ -718,7 +733,7 @@ export class Agent {
|
|
|
718
733
|
const tools = ownedDialect
|
|
719
734
|
? []
|
|
720
735
|
: (normalizeTools(
|
|
721
|
-
this.#
|
|
736
|
+
this.#toolsForModel(model),
|
|
722
737
|
this.#intentTracing,
|
|
723
738
|
preferredDialect(model.id),
|
|
724
739
|
this.#pruneToolDescriptions,
|
|
@@ -1152,7 +1167,7 @@ export class Agent {
|
|
|
1152
1167
|
await Bun.sleep(0);
|
|
1153
1168
|
}
|
|
1154
1169
|
context.systemPrompt = this.#state.systemPrompt;
|
|
1155
|
-
context.tools = this.#state.
|
|
1170
|
+
context.tools = this.#toolsForModel(this.#state.model ?? model);
|
|
1156
1171
|
},
|
|
1157
1172
|
cursorExecHandlers: this.#cursorExecHandlers,
|
|
1158
1173
|
cursorOnToolResult,
|
|
@@ -1205,6 +1220,7 @@ export class Agent {
|
|
|
1205
1220
|
};
|
|
1206
1221
|
|
|
1207
1222
|
let partial: AgentMessage | null = null;
|
|
1223
|
+
const completedToolCallIds = new Set<string>();
|
|
1208
1224
|
|
|
1209
1225
|
try {
|
|
1210
1226
|
const stream = messages
|
|
@@ -1222,6 +1238,9 @@ export class Agent {
|
|
|
1222
1238
|
case "message_update":
|
|
1223
1239
|
partial = event.message;
|
|
1224
1240
|
this.#state.streamMessage = event.message;
|
|
1241
|
+
if (event.assistantMessageEvent.type === "toolcall_end") {
|
|
1242
|
+
completedToolCallIds.add(event.assistantMessageEvent.toolCall.id);
|
|
1243
|
+
}
|
|
1225
1244
|
break;
|
|
1226
1245
|
|
|
1227
1246
|
case "message_end":
|
|
@@ -1283,12 +1302,22 @@ export class Agent {
|
|
|
1283
1302
|
: err instanceof Error
|
|
1284
1303
|
? err.message
|
|
1285
1304
|
: String(err);
|
|
1286
|
-
const
|
|
1305
|
+
const shouldEmitVisibleError = !stoppedForAbort;
|
|
1287
1306
|
const assistantPartial = partial?.role === "assistant" ? partial : undefined;
|
|
1288
1307
|
const hadAssistantStart = assistantPartial !== undefined;
|
|
1308
|
+
const bufferedCursorResults = this.#cursorToolResultBuffer.map(({ toolResult }) => toolResult);
|
|
1309
|
+
const retainedToolCallIds = new Set(completedToolCallIds);
|
|
1310
|
+
for (const { toolCallId } of bufferedCursorResults) retainedToolCallIds.add(toolCallId);
|
|
1289
1311
|
const errorMsg: AssistantMessage =
|
|
1290
|
-
|
|
1291
|
-
? {
|
|
1312
|
+
shouldEmitVisibleError && assistantPartial
|
|
1313
|
+
? {
|
|
1314
|
+
...assistantPartial,
|
|
1315
|
+
content: assistantPartial.content.filter(
|
|
1316
|
+
block => block.type !== "toolCall" || retainedToolCallIds.has(block.id),
|
|
1317
|
+
),
|
|
1318
|
+
stopReason: "error",
|
|
1319
|
+
errorMessage,
|
|
1320
|
+
}
|
|
1292
1321
|
: {
|
|
1293
1322
|
role: "assistant",
|
|
1294
1323
|
content: [{ type: "text", text: "" }],
|
|
@@ -1308,7 +1337,7 @@ export class Agent {
|
|
|
1308
1337
|
timestamp: Date.now(),
|
|
1309
1338
|
};
|
|
1310
1339
|
|
|
1311
|
-
if (
|
|
1340
|
+
if (shouldEmitVisibleError) {
|
|
1312
1341
|
if (!hadAssistantStart) {
|
|
1313
1342
|
this.#state.streamMessage = errorMsg;
|
|
1314
1343
|
this.#emit({ type: "message_start", message: errorMsg });
|
|
@@ -1317,8 +1346,40 @@ export class Agent {
|
|
|
1317
1346
|
this.appendMessage(errorMsg);
|
|
1318
1347
|
this.#state.error = errorMessage;
|
|
1319
1348
|
this.#emit({ type: "message_end", message: errorMsg });
|
|
1320
|
-
|
|
1321
|
-
this.#
|
|
1349
|
+
const toolResults: ToolResultMessage[] = [];
|
|
1350
|
+
this.#cursorToolResultBuffer = [];
|
|
1351
|
+
const bufferedCursorToolCallIds = new Set(bufferedCursorResults.map(({ toolCallId }) => toolCallId));
|
|
1352
|
+
for (const toolResult of bufferedCursorResults) {
|
|
1353
|
+
this.appendMessage(toolResult);
|
|
1354
|
+
this.#emit({ type: "message_start", message: toolResult });
|
|
1355
|
+
this.#emit({ type: "message_end", message: toolResult });
|
|
1356
|
+
toolResults.push(toolResult);
|
|
1357
|
+
}
|
|
1358
|
+
for (const block of errorMsg.content) {
|
|
1359
|
+
if (block.type !== "toolCall") continue;
|
|
1360
|
+
if (bufferedCursorToolCallIds.has(block.id)) continue;
|
|
1361
|
+
const toolResult = createSyntheticToolResultMessage(block, "error", errorMessage);
|
|
1362
|
+
this.#emit({
|
|
1363
|
+
type: "tool_execution_start",
|
|
1364
|
+
toolCallId: block.id,
|
|
1365
|
+
toolName: block.name,
|
|
1366
|
+
args: block.arguments,
|
|
1367
|
+
intent: block.intent,
|
|
1368
|
+
});
|
|
1369
|
+
this.#emit({
|
|
1370
|
+
type: "tool_execution_end",
|
|
1371
|
+
toolCallId: block.id,
|
|
1372
|
+
toolName: block.name,
|
|
1373
|
+
result: { content: toolResult.content, details: toolResult.details },
|
|
1374
|
+
isError: true,
|
|
1375
|
+
});
|
|
1376
|
+
this.appendMessage(toolResult);
|
|
1377
|
+
this.#emit({ type: "message_start", message: toolResult });
|
|
1378
|
+
this.#emit({ type: "message_end", message: toolResult });
|
|
1379
|
+
toolResults.push(toolResult);
|
|
1380
|
+
}
|
|
1381
|
+
this.#emit({ type: "turn_end", message: errorMsg, toolResults });
|
|
1382
|
+
this.#emit({ type: "agent_end", messages: [errorMsg, ...toolResults] });
|
|
1322
1383
|
} else {
|
|
1323
1384
|
this.appendMessage(errorMsg);
|
|
1324
1385
|
this.#state.error = errorMessage;
|
package/src/proxy.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type Context,
|
|
9
9
|
EventStream,
|
|
10
10
|
type FetchImpl,
|
|
11
|
+
type ImageContent,
|
|
11
12
|
type Model,
|
|
12
13
|
type SimpleStreamOptions,
|
|
13
14
|
type StopReason,
|
|
@@ -47,6 +48,7 @@ export type ProxyAssistantMessageEvent =
|
|
|
47
48
|
| { type: "thinking_start"; contentIndex: number }
|
|
48
49
|
| { type: "thinking_delta"; contentIndex: number; delta: string }
|
|
49
50
|
| { type: "thinking_end"; contentIndex: number; contentSignature?: string }
|
|
51
|
+
| { type: "image_end"; contentIndex: number; content: ImageContent }
|
|
50
52
|
| { type: "toolcall_start"; contentIndex: number; id: string; toolName: string }
|
|
51
53
|
| { type: "toolcall_delta"; contentIndex: number; delta: string }
|
|
52
54
|
| { type: "toolcall_end"; contentIndex: number }
|
|
@@ -315,6 +317,15 @@ function processProxyEvent(
|
|
|
315
317
|
throw new Error("Received thinking_end for non-thinking content");
|
|
316
318
|
}
|
|
317
319
|
|
|
320
|
+
case "image_end":
|
|
321
|
+
partial.content[proxyEvent.contentIndex] = proxyEvent.content;
|
|
322
|
+
return {
|
|
323
|
+
type: "image_end",
|
|
324
|
+
contentIndex: proxyEvent.contentIndex,
|
|
325
|
+
content: proxyEvent.content,
|
|
326
|
+
partial,
|
|
327
|
+
};
|
|
328
|
+
|
|
318
329
|
case "toolcall_start":
|
|
319
330
|
partial.content[proxyEvent.contentIndex] = {
|
|
320
331
|
type: "toolCall",
|
package/src/telemetry.ts
CHANGED
|
@@ -957,6 +957,9 @@ function assistantContentToOtelParts(content: AssistantMessage["content"]): Otel
|
|
|
957
957
|
case "text":
|
|
958
958
|
parts.push({ type: "text", content: part.text });
|
|
959
959
|
break;
|
|
960
|
+
case "image":
|
|
961
|
+
parts.push({ type: "blob", modality: "image", mime_type: part.mimeType, content: part.data });
|
|
962
|
+
break;
|
|
960
963
|
case "thinking":
|
|
961
964
|
parts.push({ type: "reasoning", content: part.thinking });
|
|
962
965
|
break;
|