@pasko70/pibo 2.2.4 → 2.2.5
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/dist/agent-runtime/capabilities.js +9 -1
- package/dist/agent-runtimes/codex-native/adapter.js +5 -0
- package/dist/agent-runtimes/omp/adapter.js +5 -0
- package/dist/agent-runtimes/omp/turn.js +2 -0
- package/dist/agent-runtimes/pi/adapter.js +27 -6
- package/dist/agent-runtimes/pi/intent-tracing.js +120 -0
- package/dist/agent-runtimes/pi/routed-session.js +25 -8
- package/dist/agent-runtimes/pi/runtime.js +3 -0
- package/dist/apps/chat/chat-settings-routes.js +44 -3
- package/dist/apps/chat/chat-transcription.js +85 -0
- package/dist/apps/chat/data/chat-data-mappers.js +4 -4
- package/dist/apps/chat/stream.js +23 -9
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/web-app.js +49 -0
- package/dist/apps/chat-ui/assets/{dist-CImWCF2M.js → dist-BCRR_a0Z.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-luJVFsmq.js → dist-BK7eaoLT.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-BFwTuvyi.js → dist-CTUT484B.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-ltfz1vFX.js → dist-fNgdnmyE.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-rf4HYdoa.js → dist-wq3P0LZj.js} +1 -1
- package/dist/apps/chat-ui/assets/{index-nZQXUpxE.css → index-BJ56TREg.css} +1 -1
- package/dist/apps/chat-ui/assets/index-DsFKL_EZ.js +228 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-R4FTxr78.js +43 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.2.5.vsix +0 -0
- package/dist/core/gateway-resource-guard.js +35 -14
- package/dist/core/gateway-settings.js +64 -0
- package/dist/core/session-router.js +5 -1
- package/dist/core/user-settings.js +20 -0
- package/dist/data/ingest-service.js +2 -2
- package/dist/debug/index.js +7 -2
- package/dist/gateway/server.js +2 -0
- package/dist/index.js +5 -0
- package/dist/plugins/builtin.js +4 -2
- package/dist/plugins/openai-chatgpt-transcription.js +12 -0
- package/dist/plugins/openai-transcription.js +12 -0
- package/dist/plugins/registry.js +23 -0
- package/dist/session-ui/terminalRows.js +51 -1
- package/dist/shared/trace-event-projection.js +4 -0
- package/dist/shared/trace-live-reducer.js +4 -0
- package/dist/shared/trace-patch-nodes.js +1 -0
- package/dist/transcription/openai-chatgpt.js +148 -0
- package/dist/transcription/openai.js +72 -0
- package/dist/transcription/types.js +8 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/apps/chat-ui/assets/index-D2Maa2v1.js +0 -226
- package/dist/apps/chat-vscode-web/assets/index-BpurWVnX.js +0 -41
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.2.4.vsix +0 -0
|
@@ -27,6 +27,9 @@ const BOOLEAN_CAPABILITY_PATHS = [
|
|
|
27
27
|
"nativeSubagents.supported",
|
|
28
28
|
"nativeSubagents.configurable",
|
|
29
29
|
"nativeSubagents.enabledByDefault",
|
|
30
|
+
"tools.intentTracing.supported",
|
|
31
|
+
"tools.intentTracing.configurable",
|
|
32
|
+
"tools.intentTracing.enabledByDefault",
|
|
30
33
|
"historyImport",
|
|
31
34
|
"auth.status",
|
|
32
35
|
"auth.cancel",
|
|
@@ -121,7 +124,7 @@ export function validateAgentRuntimeCapabilities(value) {
|
|
|
121
124
|
if (reasoningSupported === false && Array.isArray(reasoningValues) && reasoningValues.length > 0) {
|
|
122
125
|
errors.push("reasoning.values must be omitted or empty when reasoning is unsupported");
|
|
123
126
|
}
|
|
124
|
-
for (const feature of ["contextDiscovery", "nativeSubagents"]) {
|
|
127
|
+
for (const feature of ["contextDiscovery", "nativeSubagents", "tools.intentTracing"]) {
|
|
125
128
|
const supported = readPath(value, `${feature}.supported`);
|
|
126
129
|
const configurable = readPath(value, `${feature}.configurable`);
|
|
127
130
|
const enabledByDefault = readPath(value, `${feature}.enabledByDefault`);
|
|
@@ -243,6 +246,11 @@ export function createMinimalAgentRuntimeCapabilities() {
|
|
|
243
246
|
piboManaged: unavailable,
|
|
244
247
|
nativeToolInspection: unavailable,
|
|
245
248
|
nativeToolYielding: unavailable,
|
|
249
|
+
intentTracing: {
|
|
250
|
+
supported: false,
|
|
251
|
+
configurable: false,
|
|
252
|
+
enabledByDefault: false,
|
|
253
|
+
},
|
|
246
254
|
},
|
|
247
255
|
mcp: {
|
|
248
256
|
externalServers: unavailable,
|
|
@@ -51,6 +51,11 @@ function codexNativeCapabilities(structuredUserInput) {
|
|
|
51
51
|
reason: "Stable Codex App Server 0.147.0 does not expose a complete pre-turn native-tool inventory; Pibo reports selected MCP tools immediately and harness-native tools after stable item notifications prove they are active.",
|
|
52
52
|
},
|
|
53
53
|
nativeToolYielding: unsupportedAgentRuntimeCapability("Codex native tools remain harness-owned and are not wrapped as Pibo yielded tools."),
|
|
54
|
+
intentTracing: {
|
|
55
|
+
supported: false,
|
|
56
|
+
configurable: false,
|
|
57
|
+
enabledByDefault: false,
|
|
58
|
+
},
|
|
54
59
|
},
|
|
55
60
|
mcp: {
|
|
56
61
|
externalServers: { support: "mcp", transports: ["streamable-http", "stdio"] },
|
|
@@ -50,6 +50,11 @@ function ompCapabilities() {
|
|
|
50
50
|
reason: "OMP exposes its native tool inventory via get_state.dumpTools and runtime tool_execution items; a complete pre-turn inventory is only partially exposed through RPC.",
|
|
51
51
|
},
|
|
52
52
|
nativeToolYielding: unsupportedAgentRuntimeCapability("OMP native tools remain harness-owned and are not wrapped as Pibo yielded tools."),
|
|
53
|
+
intentTracing: {
|
|
54
|
+
supported: true,
|
|
55
|
+
configurable: false,
|
|
56
|
+
enabledByDefault: true,
|
|
57
|
+
},
|
|
53
58
|
},
|
|
54
59
|
mcp: {
|
|
55
60
|
externalServers: { support: "unsupported", reason: "OMP manages its own MCP; external MCP delivery is not wired in the initial OMP adapter." },
|
|
@@ -238,11 +238,13 @@ export class OmpRpcTurnController {
|
|
|
238
238
|
return;
|
|
239
239
|
}
|
|
240
240
|
if (frame.type === "tool_execution_start") {
|
|
241
|
+
const intent = typeof frame.intent === "string" ? frame.intent.trim() : "";
|
|
241
242
|
this.emit({
|
|
242
243
|
type: "tool_execution_started",
|
|
243
244
|
toolCallId: frame.toolCallId,
|
|
244
245
|
toolName: frame.toolName,
|
|
245
246
|
args: frame.args,
|
|
247
|
+
...(intent ? { intent } : {}),
|
|
246
248
|
});
|
|
247
249
|
return;
|
|
248
250
|
}
|
|
@@ -10,6 +10,7 @@ import { loadModelCatalog as loadPiModelCatalog, piAgentRuntimeModelCatalog, } f
|
|
|
10
10
|
import { inspectPiAgentRuntimeHistory, readPiAgentRuntimeHistory, } from "./history.js";
|
|
11
11
|
import { PiAgentRuntimeAuthController } from "./auth.js";
|
|
12
12
|
import { importPortableHistoryIntoPi } from "./portable-history.js";
|
|
13
|
+
import { piIntentTracingEnabled } from "./intent-tracing.js";
|
|
13
14
|
const PI_ADAPTER_ID = "pi";
|
|
14
15
|
export const PI_PROTOCOL_VERSION = "0.84.2";
|
|
15
16
|
export const PI_AGENT_RUNTIME_CAPABILITIES = {
|
|
@@ -43,6 +44,11 @@ export const PI_AGENT_RUNTIME_CAPABILITIES = {
|
|
|
43
44
|
piboManaged: { support: "direct" },
|
|
44
45
|
nativeToolInspection: { support: "native" },
|
|
45
46
|
nativeToolYielding: { support: "native" },
|
|
47
|
+
intentTracing: {
|
|
48
|
+
supported: true,
|
|
49
|
+
configurable: true,
|
|
50
|
+
enabledByDefault: false,
|
|
51
|
+
},
|
|
46
52
|
},
|
|
47
53
|
mcp: {
|
|
48
54
|
externalServers: { support: "materialized", modes: ["isolated-pibo-mcp-config"] },
|
|
@@ -165,7 +171,7 @@ function nativeSessionInfoFromPi(runtimeInstanceId, info) {
|
|
|
165
171
|
firstMessage: info.firstMessage,
|
|
166
172
|
};
|
|
167
173
|
}
|
|
168
|
-
function semanticEventFromPibo(event) {
|
|
174
|
+
export function semanticEventFromPibo(event) {
|
|
169
175
|
switch (event.type) {
|
|
170
176
|
case "message_started":
|
|
171
177
|
return { type: "turn_started", turnId: event.eventId };
|
|
@@ -188,6 +194,7 @@ function semanticEventFromPibo(event) {
|
|
|
188
194
|
toolName: event.toolName,
|
|
189
195
|
args: event.args,
|
|
190
196
|
argsComplete: event.argsComplete,
|
|
197
|
+
...(event.intent ? { intent: event.intent } : {}),
|
|
191
198
|
};
|
|
192
199
|
case "tool_execution_started":
|
|
193
200
|
return { ...event, type: "tool_execution_started" };
|
|
@@ -519,12 +526,23 @@ class PiAgentRuntimeAdapter {
|
|
|
519
526
|
message: `Profile "${input.profile.profileName}" selects runtime instance "${input.profile.runtimeInstanceId}", not "${this.instanceId}".`,
|
|
520
527
|
});
|
|
521
528
|
}
|
|
522
|
-
|
|
529
|
+
const runtimeOptionKeys = Object.keys(input.profile.runtimeOptions);
|
|
530
|
+
for (const key of runtimeOptionKeys) {
|
|
531
|
+
if (key === "intentTracing")
|
|
532
|
+
continue;
|
|
533
|
+
diagnostics.push({
|
|
534
|
+
severity: "error",
|
|
535
|
+
code: "pi_runtime_option_unsupported",
|
|
536
|
+
message: `The Pi runtime does not accept profile option "${key}".`,
|
|
537
|
+
path: `runtimeOptions.${key}`,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
if ("intentTracing" in input.profile.runtimeOptions && typeof input.profile.runtimeOptions["intentTracing"] !== "boolean") {
|
|
523
541
|
diagnostics.push({
|
|
524
542
|
severity: "error",
|
|
525
|
-
code: "
|
|
526
|
-
message: "
|
|
527
|
-
path: "runtimeOptions",
|
|
543
|
+
code: "pi_intent_tracing_invalid",
|
|
544
|
+
message: "Pi intentTracing must be a boolean.",
|
|
545
|
+
path: "runtimeOptions.intentTracing",
|
|
528
546
|
});
|
|
529
547
|
}
|
|
530
548
|
const profileProvidesBash = input.profile.toolPackages.runControl === true
|
|
@@ -582,10 +600,12 @@ class PiAgentRuntimeAdapter {
|
|
|
582
600
|
throw new Error("Pi portable history import requires a new native session.");
|
|
583
601
|
}
|
|
584
602
|
const compatibility = input.services?.compatibility;
|
|
603
|
+
const profile = cloneProfileForPiSession(input);
|
|
604
|
+
const intentTracing = piIntentTracingEnabled(profile.runtimeOptions);
|
|
585
605
|
const runtime = await createPiboRuntime({
|
|
586
606
|
cwd: input.workspace,
|
|
587
607
|
persistSession: compatibility?.persistSession,
|
|
588
|
-
profile
|
|
608
|
+
profile,
|
|
589
609
|
thinkingLevel: compatibility?.thinkingLevel,
|
|
590
610
|
retryDefaults: compatibility?.retryDefaults,
|
|
591
611
|
extensionFactories: compatibility?.extensionFactories,
|
|
@@ -631,6 +651,7 @@ class PiAgentRuntimeAdapter {
|
|
|
631
651
|
metadata: {
|
|
632
652
|
...(input.binding?.metadata ?? {}),
|
|
633
653
|
persistent: compatibility?.persistSession !== false,
|
|
654
|
+
intentTracing,
|
|
634
655
|
nativePresenceExpected: compatibility?.persistSession !== false
|
|
635
656
|
&& runtime.session.sessionManager.buildSessionContext().messages.length > 0,
|
|
636
657
|
},
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
export const PI_TOOL_INTENT_FIELD = "i";
|
|
2
|
+
const PI_TOOL_INTENT_FALLBACK_FIELD = "__pibo_intent";
|
|
3
|
+
const intentTracingSessions = new WeakMap();
|
|
4
|
+
const PI_TOOL_INTENT_SCHEMA = {
|
|
5
|
+
type: "string",
|
|
6
|
+
minLength: 1,
|
|
7
|
+
description: "Capitalized 2–6-word present-participle intent describing why this tool is being called; no period.",
|
|
8
|
+
};
|
|
9
|
+
export function piIntentTracingEnabled(runtimeOptions) {
|
|
10
|
+
return runtimeOptions["intentTracing"] === true;
|
|
11
|
+
}
|
|
12
|
+
export function splitPiToolIntentArguments(value, intentField = PI_TOOL_INTENT_FIELD) {
|
|
13
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
14
|
+
return { args: value };
|
|
15
|
+
const record = value;
|
|
16
|
+
const intentValue = record[intentField];
|
|
17
|
+
const intent = typeof intentValue === "string" && intentValue.trim() ? intentValue.trim() : undefined;
|
|
18
|
+
const { [intentField]: _intent, ...args } = record;
|
|
19
|
+
return intent ? { args, intent } : { args };
|
|
20
|
+
}
|
|
21
|
+
export function piToolIntentFieldForSchema(schema) {
|
|
22
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
23
|
+
return PI_TOOL_INTENT_FIELD;
|
|
24
|
+
const record = schema;
|
|
25
|
+
if (record.type !== "object")
|
|
26
|
+
return PI_TOOL_INTENT_FIELD;
|
|
27
|
+
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)
|
|
28
|
+
? record.properties
|
|
29
|
+
: {};
|
|
30
|
+
const required = new Set(Array.isArray(record.required)
|
|
31
|
+
? record.required.filter((name) => typeof name === "string")
|
|
32
|
+
: []);
|
|
33
|
+
const fieldIsUsed = (field) => Object.prototype.hasOwnProperty.call(properties, field) || required.has(field);
|
|
34
|
+
if (!fieldIsUsed(PI_TOOL_INTENT_FIELD))
|
|
35
|
+
return PI_TOOL_INTENT_FIELD;
|
|
36
|
+
let candidate = PI_TOOL_INTENT_FALLBACK_FIELD;
|
|
37
|
+
let suffix = 2;
|
|
38
|
+
while (fieldIsUsed(candidate))
|
|
39
|
+
candidate = `${PI_TOOL_INTENT_FALLBACK_FIELD}_${suffix++}`;
|
|
40
|
+
return candidate;
|
|
41
|
+
}
|
|
42
|
+
export function injectPiToolIntentSchema(schema) {
|
|
43
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema))
|
|
44
|
+
return schema;
|
|
45
|
+
const record = schema;
|
|
46
|
+
if (record.type !== "object")
|
|
47
|
+
return schema;
|
|
48
|
+
const properties = record.properties && typeof record.properties === "object" && !Array.isArray(record.properties)
|
|
49
|
+
? record.properties
|
|
50
|
+
: {};
|
|
51
|
+
const intentField = piToolIntentFieldForSchema(schema);
|
|
52
|
+
const required = Array.isArray(record.required)
|
|
53
|
+
? record.required.filter((name) => typeof name === "string" && name !== intentField)
|
|
54
|
+
: [];
|
|
55
|
+
return {
|
|
56
|
+
...record,
|
|
57
|
+
properties: {
|
|
58
|
+
[intentField]: PI_TOOL_INTENT_SCHEMA,
|
|
59
|
+
...properties,
|
|
60
|
+
},
|
|
61
|
+
required: [intentField, ...required],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
export function piIntentTracingInstalled(session) {
|
|
65
|
+
return intentTracingSessions.has(session);
|
|
66
|
+
}
|
|
67
|
+
export function piToolIntentField(session, toolName) {
|
|
68
|
+
return intentTracingSessions.get(session)?.get(toolName);
|
|
69
|
+
}
|
|
70
|
+
export function installPiIntentTracing(session) {
|
|
71
|
+
if (intentTracingSessions.has(session))
|
|
72
|
+
return;
|
|
73
|
+
const intentFields = new Map();
|
|
74
|
+
const wrappedTools = new WeakMap();
|
|
75
|
+
const wrapActiveTools = () => {
|
|
76
|
+
session.agent.state.tools = session.agent.state.tools.map((tool) => {
|
|
77
|
+
const existing = wrappedTools.get(tool);
|
|
78
|
+
if (existing) {
|
|
79
|
+
intentFields.set(tool.name, existing.intentField);
|
|
80
|
+
return existing.tool;
|
|
81
|
+
}
|
|
82
|
+
const wrapped = wrapPiToolWithIntent(tool);
|
|
83
|
+
wrappedTools.set(tool, wrapped);
|
|
84
|
+
intentFields.set(tool.name, wrapped.intentField);
|
|
85
|
+
return wrapped.tool;
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
const setActiveToolsByName = session.setActiveToolsByName.bind(session);
|
|
89
|
+
session.setActiveToolsByName = (toolNames) => {
|
|
90
|
+
setActiveToolsByName(toolNames);
|
|
91
|
+
wrapActiveTools();
|
|
92
|
+
};
|
|
93
|
+
intentTracingSessions.set(session, intentFields);
|
|
94
|
+
wrapActiveTools();
|
|
95
|
+
}
|
|
96
|
+
function wrapPiToolWithIntent(tool) {
|
|
97
|
+
const prepareArguments = tool.prepareArguments;
|
|
98
|
+
const intentField = piToolIntentFieldForSchema(tool.parameters);
|
|
99
|
+
return {
|
|
100
|
+
intentField,
|
|
101
|
+
tool: {
|
|
102
|
+
...tool,
|
|
103
|
+
parameters: injectPiToolIntentSchema(tool.parameters),
|
|
104
|
+
prepareArguments: (rawArgs) => {
|
|
105
|
+
const { args, intent } = splitPiToolIntentArguments(rawArgs, intentField);
|
|
106
|
+
const prepared = prepareArguments ? prepareArguments(args) : args;
|
|
107
|
+
if (!prepared || typeof prepared !== "object" || Array.isArray(prepared))
|
|
108
|
+
return prepared;
|
|
109
|
+
return {
|
|
110
|
+
...prepared,
|
|
111
|
+
...(intent ? { [intentField]: intent } : {}),
|
|
112
|
+
};
|
|
113
|
+
},
|
|
114
|
+
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
115
|
+
const { args } = splitPiToolIntentArguments(params, intentField);
|
|
116
|
+
return await tool.execute(toolCallId, args, signal, onUpdate);
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -6,6 +6,7 @@ import { expandInlineSkills } from "../../core/skill-expansion.js";
|
|
|
6
6
|
import { PIBO_CONTEXT_GUARD_RESUME_MESSAGE_TYPE, PIBO_CONTEXT_GUARD_RESUME_PROMPT, cancelPiboAssistantContextGuardRecovery, claimPiboAssistantContextGuardRecovery, waitForPiboAssistantContextGuardRecovery, } from "../../core/context-guard.js";
|
|
7
7
|
import { PIBO_PROVIDER_RECOVERY_MESSAGE_TYPE, PIBO_PROVIDER_RECOVERY_PROMPT, PiboProviderRecoveryCancelledError, isRetryablePiboAssistantError, isRetryablePiboProviderError, resolvePiboProviderRecoverySettings, waitForPiboProviderRecovery, } from "../../core/provider-recovery.js";
|
|
8
8
|
import { PiAgentRuntimeAuthController } from "./auth.js";
|
|
9
|
+
import { piIntentTracingInstalled, piToolIntentField, splitPiToolIntentArguments } from "./intent-tracing.js";
|
|
9
10
|
import { loadModelCatalog as loadPiModelCatalog } from "./model-catalog.js";
|
|
10
11
|
import { PIBO_TRANSCRIPT_INTEGRITY_RESUME_MESSAGE_TYPE, PIBO_TRANSCRIPT_INTEGRITY_RESUME_PROMPT, PiboTranscriptIntegrityError, claimPiboTranscriptIntegrityContinuation, settlePiboTranscriptIntegrityContinuation, } from "../../core/transcript-integrity.js";
|
|
11
12
|
const FAST_SERVICE_TIER = "priority";
|
|
@@ -175,45 +176,57 @@ function toolCallFromAssistantEvent(candidate) {
|
|
|
175
176
|
}
|
|
176
177
|
return toolCallFromMessage(candidate.message, candidate.assistantMessageEvent?.contentIndex);
|
|
177
178
|
}
|
|
178
|
-
function normalizeToolCallEvent(piboSessionId, candidate) {
|
|
179
|
+
function normalizeToolCallEvent(piboSessionId, candidate, context) {
|
|
179
180
|
if (candidate.type === "message_update" &&
|
|
180
181
|
(candidate.assistantMessageEvent?.type === "toolcall_start" ||
|
|
181
182
|
candidate.assistantMessageEvent?.type === "toolcall_end")) {
|
|
182
183
|
const toolCall = toolCallFromAssistantEvent(candidate);
|
|
183
184
|
if (!toolCall)
|
|
184
185
|
return undefined;
|
|
186
|
+
const { args, intent } = context?.intentTracing
|
|
187
|
+
? splitPiToolIntentArguments(toolCall.args, context.intentFieldForTool?.(toolCall.name))
|
|
188
|
+
: { args: toolCall.args };
|
|
185
189
|
return {
|
|
186
190
|
type: "tool_call",
|
|
187
191
|
piboSessionId,
|
|
188
192
|
toolCallId: toolCall.id,
|
|
189
193
|
toolName: toolCall.name,
|
|
190
|
-
args
|
|
194
|
+
args,
|
|
191
195
|
argsComplete: candidate.assistantMessageEvent.type === "toolcall_end",
|
|
196
|
+
...(intent ? { intent } : {}),
|
|
192
197
|
};
|
|
193
198
|
}
|
|
194
199
|
return undefined;
|
|
195
200
|
}
|
|
196
|
-
function normalizeToolExecutionEvent(piboSessionId, candidate) {
|
|
201
|
+
function normalizeToolExecutionEvent(piboSessionId, candidate, context) {
|
|
197
202
|
if (typeof candidate.toolCallId !== "string" || typeof candidate.toolName !== "string") {
|
|
198
203
|
return undefined;
|
|
199
204
|
}
|
|
200
205
|
if (candidate.type === "tool_execution_start") {
|
|
206
|
+
const { args, intent } = context?.intentTracing
|
|
207
|
+
? splitPiToolIntentArguments(candidate.args, context.intentFieldForTool?.(candidate.toolName))
|
|
208
|
+
: { args: candidate.args };
|
|
201
209
|
return {
|
|
202
210
|
type: "tool_execution_started",
|
|
203
211
|
piboSessionId,
|
|
204
212
|
toolCallId: candidate.toolCallId,
|
|
205
213
|
toolName: candidate.toolName,
|
|
206
|
-
args
|
|
214
|
+
args,
|
|
215
|
+
...(intent ? { intent } : {}),
|
|
207
216
|
};
|
|
208
217
|
}
|
|
209
218
|
if (candidate.type === "tool_execution_update") {
|
|
219
|
+
const { args, intent } = context?.intentTracing
|
|
220
|
+
? splitPiToolIntentArguments(candidate.args, context.intentFieldForTool?.(candidate.toolName))
|
|
221
|
+
: { args: candidate.args };
|
|
210
222
|
return {
|
|
211
223
|
type: "tool_execution_updated",
|
|
212
224
|
piboSessionId,
|
|
213
225
|
toolCallId: candidate.toolCallId,
|
|
214
226
|
toolName: candidate.toolName,
|
|
215
|
-
args
|
|
227
|
+
args,
|
|
216
228
|
partialResult: candidate.partialResult,
|
|
229
|
+
...(intent ? { intent } : {}),
|
|
217
230
|
};
|
|
218
231
|
}
|
|
219
232
|
if (candidate.type === "tool_execution_end") {
|
|
@@ -332,10 +345,10 @@ export function normalizePiEvent(piboSessionId, event, context) {
|
|
|
332
345
|
? { type: "thinking_finished", piboSessionId, contentIndex: messageContentIndex(candidate) }
|
|
333
346
|
: { type: "thinking_finished", piboSessionId, contentIndex: messageContentIndex(candidate), text };
|
|
334
347
|
}
|
|
335
|
-
const toolCallEvent = normalizeToolCallEvent(piboSessionId, candidate);
|
|
348
|
+
const toolCallEvent = normalizeToolCallEvent(piboSessionId, candidate, context);
|
|
336
349
|
if (toolCallEvent)
|
|
337
350
|
return toolCallEvent;
|
|
338
|
-
const toolExecutionEvent = normalizeToolExecutionEvent(piboSessionId, candidate);
|
|
351
|
+
const toolExecutionEvent = normalizeToolExecutionEvent(piboSessionId, candidate, context);
|
|
339
352
|
if (toolExecutionEvent)
|
|
340
353
|
return toolExecutionEvent;
|
|
341
354
|
if (candidate.type === "message_end") {
|
|
@@ -553,7 +566,11 @@ export class RoutedSession {
|
|
|
553
566
|
this.unsubscribe = session.subscribe((event) => {
|
|
554
567
|
this.onPiEventTelemetry?.(this.piboSessionId, event, { status: this.getStatus(), activeEventId: this.activeMessage?.id ?? this.activeExecutionEvent?.id });
|
|
555
568
|
const model = this.runtime.session.model;
|
|
556
|
-
const normalized = normalizePiEvent(this.piboSessionId, event, {
|
|
569
|
+
const normalized = normalizePiEvent(this.piboSessionId, event, {
|
|
570
|
+
contextWindow: numberValue(model?.contextWindow),
|
|
571
|
+
intentTracing: piIntentTracingInstalled(session),
|
|
572
|
+
intentFieldForTool: (toolName) => piToolIntentField(session, toolName),
|
|
573
|
+
});
|
|
557
574
|
const candidate = event && typeof event === "object" ? event : undefined;
|
|
558
575
|
const assistantMessageEnded = candidate?.type === "message_end" && isAssistantMessage(candidate.message);
|
|
559
576
|
const usageEvent = assistantMessageEnded ? normalizeAssistantUsageEvent(this.piboSessionId, candidate?.message) : undefined;
|
|
@@ -28,6 +28,7 @@ import { compactValidationToolResultForContext } from "../../core/test-output-co
|
|
|
28
28
|
import { installPiboTranscriptIntegrity } from "../../core/transcript-integrity.js";
|
|
29
29
|
import { normalizePiboToolDefinition, } from "../../tools/contract.js";
|
|
30
30
|
import { compilePiboToolForPi } from "./tool-compiler.js";
|
|
31
|
+
import { installPiIntentTracing, piIntentTracingEnabled } from "./intent-tracing.js";
|
|
31
32
|
import { createPiboSessionToolDefinitions, isCodexBrowserToolProfile as isCodexBrowserTool, isEnabledCodexBrowserToolProfile as isEnabledCodexBrowserTool, isEnabledRuntimeToolProfile as isEnabledRuntimeTool, isGeneratedPiboTool, isRuntimeToolProfile as isRuntimeTool, } from "../../tools/session-tool-set.js";
|
|
32
33
|
function hasOwnRetrySetting(settings, key) {
|
|
33
34
|
return settings !== undefined && settings !== null && Object.prototype.hasOwnProperty.call(settings, key);
|
|
@@ -306,6 +307,8 @@ export async function createPiboRuntime(options = {}) {
|
|
|
306
307
|
noTools: profile.builtinTools === "disabled" ? "builtin" : undefined,
|
|
307
308
|
tools: getBuiltinToolAllowlist(profile, piboToolDefinitions),
|
|
308
309
|
});
|
|
310
|
+
if (piIntentTracingEnabled(profile.runtimeOptions))
|
|
311
|
+
installPiIntentTracing(created.session);
|
|
309
312
|
installPiboTranscriptIntegrity(created.session);
|
|
310
313
|
installValidationOutputCompaction(created.session.agent);
|
|
311
314
|
registerPiboAssistantContextGuardRecovery(created.session, contextGuardRecovery);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { readPiboBasePrompt, savePiboCustomBasePrompt, setPiboBasePromptMode } from "../../core/base-prompt.js";
|
|
2
2
|
import { readPiboCompactionPrompt, savePiboCustomCompactionPrompt, setPiboCompactionPromptMode } from "../../core/compaction-prompt.js";
|
|
3
|
+
import { loadPiboGatewaySettings, sanitizeConcurrentYieldedRuns, updatePiboGatewaySettings, } from "../../core/gateway-settings.js";
|
|
3
4
|
import { sanitizeTelemetryRetentionDays, sanitizeTelemetryRetentionSettings } from "../../core/telemetry-retention-settings.js";
|
|
4
|
-
import { loadPiboUserSettings, sanitizeShortcutSettings, sanitizeTimezone, updatePiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
|
|
5
|
+
import { loadPiboUserSettings, sanitizeShortcutSettings, sanitizeTimezone, sanitizeTranscriptionProviderId, updatePiboUserSettings, updateTelemetryRetentionLastPrunedAt } from "../../core/user-settings.js";
|
|
5
6
|
import { PiboWebHttpError, readJsonBody, responseJson } from "../../web/http.js";
|
|
6
7
|
import { CHAT_WEB_API_PREFIX } from "./chat-api-routes.js";
|
|
7
8
|
import { normalizeBasePromptMarkdown, normalizeBasePromptMode, normalizeCompactionPromptMarkdown, normalizeCompactionPromptMode, updateChatModelDefaults, } from "./chat-request-normalizers.js";
|
|
@@ -13,6 +14,10 @@ export function chatSettingsRoute(pathname, method) {
|
|
|
13
14
|
return { kind: "user-settings", action: "read" };
|
|
14
15
|
if (pathname === `${CHAT_WEB_API_PREFIX}/user-settings` && method === "PATCH")
|
|
15
16
|
return { kind: "user-settings", action: "update" };
|
|
17
|
+
if (pathname === `${CHAT_WEB_API_PREFIX}/gateway-settings` && method === "GET")
|
|
18
|
+
return { kind: "gateway-settings", action: "read" };
|
|
19
|
+
if (pathname === `${CHAT_WEB_API_PREFIX}/gateway-settings` && method === "PATCH")
|
|
20
|
+
return { kind: "gateway-settings", action: "update" };
|
|
16
21
|
if (pathname === `${CHAT_WEB_API_PREFIX}/telemetry-retention/prune` && method === "POST")
|
|
17
22
|
return { kind: "telemetry-retention", action: "prune" };
|
|
18
23
|
if (pathname === `${CHAT_WEB_API_PREFIX}/base-prompt` && method === "GET")
|
|
@@ -46,7 +51,13 @@ export async function handleChatSettingsRoute(input) {
|
|
|
46
51
|
if (route.action === "read")
|
|
47
52
|
return responseJson({ userSettings: loadPiboUserSettings() });
|
|
48
53
|
const body = await readJsonBody(request);
|
|
49
|
-
return responseJson({ userSettings: updatePiboUserSettings(userSettingsPatch(body)) });
|
|
54
|
+
return responseJson({ userSettings: updatePiboUserSettings(userSettingsPatch(body, input.transcriptionProviderIds)) });
|
|
55
|
+
}
|
|
56
|
+
if (route.kind === "gateway-settings") {
|
|
57
|
+
if (route.action === "read")
|
|
58
|
+
return responseJson({ gatewaySettings: loadPiboGatewaySettings() });
|
|
59
|
+
const body = await readJsonBody(request);
|
|
60
|
+
return responseJson({ gatewaySettings: updatePiboGatewaySettings(gatewaySettingsPatch(body)) });
|
|
50
61
|
}
|
|
51
62
|
if (route.kind === "telemetry-retention") {
|
|
52
63
|
if (!input.dataStore)
|
|
@@ -77,7 +88,25 @@ export async function handleChatSettingsRoute(input) {
|
|
|
77
88
|
}
|
|
78
89
|
return responseJson({ compactionPrompt: await savePiboCustomCompactionPrompt(normalizeCompactionPromptMarkdown(body.markdown), cwd) });
|
|
79
90
|
}
|
|
80
|
-
function
|
|
91
|
+
function gatewaySettingsPatch(body) {
|
|
92
|
+
const patch = {};
|
|
93
|
+
if (body.maxConcurrentYieldedRuns !== undefined) {
|
|
94
|
+
const value = sanitizeConcurrentYieldedRuns(body.maxConcurrentYieldedRuns);
|
|
95
|
+
if (!value)
|
|
96
|
+
throw new PiboWebHttpError("Invalid gateway yielded-run concurrency", 400);
|
|
97
|
+
patch.maxConcurrentYieldedRuns = value;
|
|
98
|
+
}
|
|
99
|
+
if (body.sessionConcurrentYieldedRuns !== undefined) {
|
|
100
|
+
const value = sanitizeConcurrentYieldedRuns(body.sessionConcurrentYieldedRuns);
|
|
101
|
+
if (!value)
|
|
102
|
+
throw new PiboWebHttpError("Invalid session yielded-run concurrency", 400);
|
|
103
|
+
patch.sessionConcurrentYieldedRuns = value;
|
|
104
|
+
}
|
|
105
|
+
if (Object.keys(patch).length === 0)
|
|
106
|
+
throw new PiboWebHttpError("No gateway settings provided", 400);
|
|
107
|
+
return patch;
|
|
108
|
+
}
|
|
109
|
+
function userSettingsPatch(body, transcriptionProviderIds) {
|
|
81
110
|
const patch = {};
|
|
82
111
|
if (body.timezone !== undefined) {
|
|
83
112
|
const timezone = sanitizeTimezone(body.timezone);
|
|
@@ -87,6 +116,18 @@ function userSettingsPatch(body) {
|
|
|
87
116
|
}
|
|
88
117
|
if (body.shortcuts !== undefined)
|
|
89
118
|
patch.shortcuts = sanitizeShortcutSettings(body.shortcuts);
|
|
119
|
+
if (body.transcription !== undefined) {
|
|
120
|
+
const raw = body.transcription && typeof body.transcription === "object" && !Array.isArray(body.transcription)
|
|
121
|
+
? body.transcription
|
|
122
|
+
: {};
|
|
123
|
+
const providerId = sanitizeTranscriptionProviderId(raw.providerId);
|
|
124
|
+
if (!providerId)
|
|
125
|
+
throw new PiboWebHttpError("Invalid transcription provider", 400);
|
|
126
|
+
if (transcriptionProviderIds && !transcriptionProviderIds.includes(providerId)) {
|
|
127
|
+
throw new PiboWebHttpError(`Unknown transcription provider "${providerId}"`, 400);
|
|
128
|
+
}
|
|
129
|
+
patch.transcription = { providerId };
|
|
130
|
+
}
|
|
90
131
|
if (body.telemetryRetention !== undefined) {
|
|
91
132
|
const current = loadPiboUserSettings().telemetryRetention;
|
|
92
133
|
patch.telemetryRetention = {
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
import { loadPiboUserSettings } from "../../core/user-settings.js";
|
|
3
|
+
import { PiboTranscriptionError, } from "../../transcription/types.js";
|
|
4
|
+
import { PiboWebHttpError, responseJson } from "../../web/http.js";
|
|
5
|
+
export const CHAT_TRANSCRIPTION_MAX_BYTES = 25 * 1024 * 1024;
|
|
6
|
+
export async function responseChatTranscriptionProviders(context) {
|
|
7
|
+
const providers = await requireProviderInfos(context);
|
|
8
|
+
return responseJson({
|
|
9
|
+
providers,
|
|
10
|
+
selectedProviderId: loadPiboUserSettings().transcription.providerId,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
export async function responseChatTranscription(request, context) {
|
|
14
|
+
const transcribe = context.channelContext.transcribe;
|
|
15
|
+
if (!transcribe)
|
|
16
|
+
throw new PiboWebHttpError("Transcription is not available", 503);
|
|
17
|
+
const providerId = loadPiboUserSettings().transcription.providerId;
|
|
18
|
+
const providers = await requireProviderInfos(context);
|
|
19
|
+
if (!providers.some((provider) => provider.id === providerId)) {
|
|
20
|
+
throw new PiboWebHttpError(`Transcription provider "${providerId}" is not registered`, 409);
|
|
21
|
+
}
|
|
22
|
+
const audio = await readTranscriptionAudio(request);
|
|
23
|
+
let result;
|
|
24
|
+
try {
|
|
25
|
+
result = await transcribe(providerId, audio);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (error instanceof PiboTranscriptionError) {
|
|
29
|
+
throw new PiboWebHttpError(error.message, transcriptionErrorStatus(error));
|
|
30
|
+
}
|
|
31
|
+
throw new PiboWebHttpError(error instanceof Error ? error.message : "Transcription failed", 502);
|
|
32
|
+
}
|
|
33
|
+
return responseJson({ transcription: result });
|
|
34
|
+
}
|
|
35
|
+
async function requireProviderInfos(context) {
|
|
36
|
+
const getProviderInfos = context.channelContext.getTranscriptionProviderInfos;
|
|
37
|
+
if (!getProviderInfos)
|
|
38
|
+
throw new PiboWebHttpError("Transcription providers are not available", 503);
|
|
39
|
+
return await getProviderInfos();
|
|
40
|
+
}
|
|
41
|
+
async function readTranscriptionAudio(request) {
|
|
42
|
+
const form = await request.formData();
|
|
43
|
+
const file = form.get("file");
|
|
44
|
+
if (!isUploadedAudioFile(file))
|
|
45
|
+
throw new PiboWebHttpError("An audio file is required", 400);
|
|
46
|
+
if (file.size === 0)
|
|
47
|
+
throw new PiboWebHttpError("The audio recording is empty", 400);
|
|
48
|
+
if (file.size > CHAT_TRANSCRIPTION_MAX_BYTES) {
|
|
49
|
+
throw new PiboWebHttpError("The audio recording exceeds the 25 MiB limit", 413);
|
|
50
|
+
}
|
|
51
|
+
const filename = sanitizeAudioFilename(file.name);
|
|
52
|
+
return {
|
|
53
|
+
audio: {
|
|
54
|
+
bytes: new Uint8Array(await file.arrayBuffer()),
|
|
55
|
+
filename,
|
|
56
|
+
mimeType: file.type || "application/octet-stream",
|
|
57
|
+
},
|
|
58
|
+
clientUserAgent: sanitizeClientUserAgent(request.headers.get("user-agent")),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function isUploadedAudioFile(value) {
|
|
62
|
+
return typeof value === "object"
|
|
63
|
+
&& value !== null
|
|
64
|
+
&& typeof value.name === "string"
|
|
65
|
+
&& typeof value.size === "number"
|
|
66
|
+
&& typeof value.type === "string"
|
|
67
|
+
&& typeof value.arrayBuffer === "function";
|
|
68
|
+
}
|
|
69
|
+
function sanitizeAudioFilename(value) {
|
|
70
|
+
const filename = basename(value).replace(/[\u0000-\u001f\u007f]/g, "").trim();
|
|
71
|
+
return filename && !/^\.+$/.test(filename) ? filename : `recording-${Date.now()}.webm`;
|
|
72
|
+
}
|
|
73
|
+
function sanitizeClientUserAgent(value) {
|
|
74
|
+
if (!value)
|
|
75
|
+
return undefined;
|
|
76
|
+
const userAgent = value.replace(/[\u0000-\u001f\u007f]/g, "").trim();
|
|
77
|
+
return userAgent ? userAgent.slice(0, 512) : undefined;
|
|
78
|
+
}
|
|
79
|
+
function transcriptionErrorStatus(error) {
|
|
80
|
+
if (error.code === "invalid_audio")
|
|
81
|
+
return 400;
|
|
82
|
+
if (error.code === "not_configured")
|
|
83
|
+
return 409;
|
|
84
|
+
return 502;
|
|
85
|
+
}
|
|
@@ -46,13 +46,13 @@ function outputPayloadFromV2Row(row, attributes, persistedPayload) {
|
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
if (row.type === "tool_call")
|
|
49
|
-
return { ...base, type: "tool_call", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: inlinePayload ?? null, argsComplete: booleanAttribute(attributes, "argsComplete") ?? true };
|
|
49
|
+
return compactObject({ ...base, type: "tool_call", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: inlinePayload ?? null, argsComplete: booleanAttribute(attributes, "argsComplete") ?? true, intent: stringAttribute(attributes, "intent") });
|
|
50
50
|
if (row.type === "tool_execution_started")
|
|
51
|
-
return { ...base, type: "tool_execution_started", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: inlinePayload ?? null };
|
|
51
|
+
return compactObject({ ...base, type: "tool_execution_started", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: inlinePayload ?? null, intent: stringAttribute(attributes, "intent") });
|
|
52
52
|
if (row.type === "tool_execution_updated")
|
|
53
|
-
return { ...base, type: "tool_execution_updated", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: null, partialResult: inlinePayload ?? null };
|
|
53
|
+
return compactObject({ ...base, type: "tool_execution_updated", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", args: null, partialResult: inlinePayload ?? null, intent: stringAttribute(attributes, "intent") });
|
|
54
54
|
if (row.type === "tool_execution_finished")
|
|
55
|
-
return { ...base, type: "tool_execution_finished", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", result: inlinePayload ?? null, isError: booleanAttribute(attributes, "isError") ?? false };
|
|
55
|
+
return compactObject({ ...base, type: "tool_execution_finished", toolCallId: stringAttribute(attributes, "toolCallId") ?? row.event_id ?? `tool_${row.stream_id}`, toolName: row.preview_text ?? stringAttribute(attributes, "toolName") ?? "tool", result: inlinePayload ?? null, isError: booleanAttribute(attributes, "isError") ?? false, intent: stringAttribute(attributes, "intent") });
|
|
56
56
|
if (row.type === "subagent_session") {
|
|
57
57
|
const toolName = stringAttribute(attributes, "toolName");
|
|
58
58
|
const subagentName = stringAttribute(attributes, "subagentName");
|
package/dist/apps/chat/stream.js
CHANGED
|
@@ -58,36 +58,49 @@ export function chatStreamFramesFromOutputEvent(event, state, options = {}) {
|
|
|
58
58
|
}
|
|
59
59
|
break;
|
|
60
60
|
case "tool_call":
|
|
61
|
-
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, eventId);
|
|
61
|
+
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, event.intent, eventId);
|
|
62
62
|
frames.push({
|
|
63
63
|
type: "TOOL_CALL_ARGS",
|
|
64
64
|
toolCallId: event.toolCallId,
|
|
65
65
|
toolName: event.toolName,
|
|
66
66
|
args: event.args,
|
|
67
67
|
argsComplete: event.argsComplete,
|
|
68
|
+
...(event.intent ? { intent: event.intent } : {}),
|
|
68
69
|
runId: eventId,
|
|
69
70
|
sourceEventType: "tool_call",
|
|
70
71
|
});
|
|
71
72
|
break;
|
|
72
|
-
case "tool_execution_started":
|
|
73
|
-
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, eventId);
|
|
73
|
+
case "tool_execution_started": {
|
|
74
|
+
const started = ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, event.intent, eventId);
|
|
75
|
+
if (!started && event.intent) {
|
|
76
|
+
frames.push({
|
|
77
|
+
type: "TOOL_CALL_START",
|
|
78
|
+
toolCallId: event.toolCallId,
|
|
79
|
+
toolName: event.toolName,
|
|
80
|
+
args: event.args,
|
|
81
|
+
intent: event.intent,
|
|
82
|
+
runId: eventId,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
74
85
|
break;
|
|
86
|
+
}
|
|
75
87
|
case "tool_execution_updated":
|
|
76
|
-
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, eventId);
|
|
88
|
+
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, event.args, event.intent, eventId);
|
|
77
89
|
frames.push({
|
|
78
90
|
type: "TOOL_CALL_ARGS",
|
|
79
91
|
toolCallId: event.toolCallId,
|
|
80
92
|
toolName: event.toolName,
|
|
81
93
|
args: event.args,
|
|
82
94
|
argsComplete: true,
|
|
95
|
+
...(event.intent ? { intent: event.intent } : {}),
|
|
83
96
|
runId: eventId,
|
|
84
97
|
partialResult: event.partialResult,
|
|
85
98
|
sourceEventType: "tool_execution_updated",
|
|
86
99
|
});
|
|
87
100
|
break;
|
|
88
101
|
case "tool_execution_finished":
|
|
89
|
-
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, undefined, eventId);
|
|
90
|
-
frames.push({ type: "TOOL_CALL_RESULT", toolCallId: event.toolCallId, toolName: event.toolName, result: event.result, isError: event.isError, runId: eventId });
|
|
102
|
+
ensureToolCallStarted(frames, state, event.toolCallId, event.toolName, undefined, event.intent, eventId);
|
|
103
|
+
frames.push({ type: "TOOL_CALL_RESULT", toolCallId: event.toolCallId, toolName: event.toolName, result: event.result, isError: event.isError, ...(event.intent ? { intent: event.intent } : {}), runId: eventId });
|
|
91
104
|
break;
|
|
92
105
|
case "subagent_session":
|
|
93
106
|
frames.push({
|
|
@@ -149,9 +162,10 @@ function ensureReasoningStarted(frames, state, messageId, runId) {
|
|
|
149
162
|
state.reasoningMessageIds.add(messageId);
|
|
150
163
|
frames.push({ type: "REASONING_MESSAGE_START", messageId, runId });
|
|
151
164
|
}
|
|
152
|
-
function ensureToolCallStarted(frames, state, toolCallId, toolName, args, runId) {
|
|
165
|
+
function ensureToolCallStarted(frames, state, toolCallId, toolName, args, intent, runId) {
|
|
153
166
|
if (state.toolCallIds.has(toolCallId))
|
|
154
|
-
return;
|
|
167
|
+
return false;
|
|
155
168
|
state.toolCallIds.add(toolCallId);
|
|
156
|
-
frames.push({ type: "TOOL_CALL_START", toolCallId, toolName, args, runId });
|
|
169
|
+
frames.push({ type: "TOOL_CALL_START", toolCallId, toolName, args, ...(intent ? { intent } : {}), runId });
|
|
170
|
+
return true;
|
|
157
171
|
}
|