@oh-my-pi/pi-agent-core 12.12.3 → 12.14.0
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/package.json +4 -4
- package/src/agent-loop.ts +72 -5
- package/src/agent.ts +6 -0
- package/src/types.ts +7 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-agent-core",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.14.0",
|
|
4
4
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -24,9 +24,9 @@
|
|
|
24
24
|
"test": "bun test"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@oh-my-pi/pi-ai": "12.
|
|
28
|
-
"@oh-my-pi/pi-tui": "12.
|
|
29
|
-
"@oh-my-pi/pi-utils": "12.
|
|
27
|
+
"@oh-my-pi/pi-ai": "12.14.0",
|
|
28
|
+
"@oh-my-pi/pi-tui": "12.14.0",
|
|
29
|
+
"@oh-my-pi/pi-utils": "12.14.0"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|
|
32
32
|
"ai",
|
package/src/agent-loop.ts
CHANGED
|
@@ -123,6 +123,58 @@ function normalizeMessagesForProvider(
|
|
|
123
123
|
return changed ? normalized : messages;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
export const INTENT_FIELD = "agent__intent";
|
|
127
|
+
|
|
128
|
+
function injectIntentIntoSchema(schema: unknown): unknown {
|
|
129
|
+
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return schema;
|
|
130
|
+
const schemaRecord = schema as Record<string, unknown>;
|
|
131
|
+
const propertiesValue = schemaRecord.properties;
|
|
132
|
+
const properties =
|
|
133
|
+
propertiesValue && typeof propertiesValue === "object" && !Array.isArray(propertiesValue)
|
|
134
|
+
? (propertiesValue as Record<string, unknown>)
|
|
135
|
+
: {};
|
|
136
|
+
const requiredValue = schemaRecord.required;
|
|
137
|
+
const required = Array.isArray(requiredValue)
|
|
138
|
+
? requiredValue.filter((item): item is string => typeof item === "string")
|
|
139
|
+
: [];
|
|
140
|
+
if (INTENT_FIELD in properties) {
|
|
141
|
+
if (required.includes(INTENT_FIELD)) return schema;
|
|
142
|
+
return {
|
|
143
|
+
...schemaRecord,
|
|
144
|
+
required: [...required, INTENT_FIELD],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
...schemaRecord,
|
|
149
|
+
properties: {
|
|
150
|
+
...properties,
|
|
151
|
+
[INTENT_FIELD]: {
|
|
152
|
+
type: "string",
|
|
153
|
+
description:
|
|
154
|
+
"Describe intent as one sentence in present participle form (e.g., Inserting comment before the function) with no trailing period",
|
|
155
|
+
},
|
|
156
|
+
},
|
|
157
|
+
required: [...required, INTENT_FIELD],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function injectIntentIntoTools(tools: Context["tools"]): Context["tools"] {
|
|
162
|
+
return tools?.map(tool => ({
|
|
163
|
+
...tool,
|
|
164
|
+
parameters: injectIntentIntoSchema(tool.parameters) as typeof tool.parameters,
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function extractIntent(args: Record<string, unknown>): { intent?: string; strippedArgs: Record<string, unknown> } {
|
|
169
|
+
const intent = args[INTENT_FIELD];
|
|
170
|
+
if (typeof intent !== "string") {
|
|
171
|
+
return { strippedArgs: args };
|
|
172
|
+
}
|
|
173
|
+
const { [INTENT_FIELD]: _ignored, ...strippedArgs } = args;
|
|
174
|
+
const trimmed = intent.trim();
|
|
175
|
+
return { intent: trimmed.length > 0 ? trimmed : undefined, strippedArgs };
|
|
176
|
+
}
|
|
177
|
+
|
|
126
178
|
/**
|
|
127
179
|
* Main loop logic shared by agentLoop and agentLoopContinue.
|
|
128
180
|
*/
|
|
@@ -199,6 +251,7 @@ async function runLoop(
|
|
|
199
251
|
config.getToolContext,
|
|
200
252
|
config.interruptMode,
|
|
201
253
|
config.transformToolCallArguments,
|
|
254
|
+
config.intentTracing,
|
|
202
255
|
);
|
|
203
256
|
toolResults.push(...toolExecution.toolResults);
|
|
204
257
|
steeringAfterTools = toolExecution.steeringMessages ?? null;
|
|
@@ -261,7 +314,7 @@ async function streamAssistantResponse(
|
|
|
261
314
|
const llmContext: Context = {
|
|
262
315
|
systemPrompt: context.systemPrompt,
|
|
263
316
|
messages: normalizedMessages,
|
|
264
|
-
tools: context.tools,
|
|
317
|
+
tools: config.intentTracing ? injectIntentIntoTools(context.tools) : context.tools,
|
|
265
318
|
};
|
|
266
319
|
|
|
267
320
|
const streamFunction = streamFn || streamSimple;
|
|
@@ -373,6 +426,7 @@ async function executeToolCalls(
|
|
|
373
426
|
getToolContext?: AgentLoopConfig["getToolContext"],
|
|
374
427
|
interruptMode: AgentLoopConfig["interruptMode"] = "immediate",
|
|
375
428
|
transformToolCallArguments?: AgentLoopConfig["transformToolCallArguments"],
|
|
429
|
+
intentTracing?: AgentLoopConfig["intentTracing"],
|
|
376
430
|
): Promise<{ toolResults: ToolResultMessage[]; steeringMessages?: AgentMessage[] }> {
|
|
377
431
|
type ToolCallContent = Extract<AssistantMessage["content"][number], { type: "toolCall" }>;
|
|
378
432
|
const toolCalls = assistantMessage.content.filter((c): c is ToolCallContent => c.type === "toolCall");
|
|
@@ -412,6 +466,7 @@ async function executeToolCalls(
|
|
|
412
466
|
const records = toolCalls.map(toolCall => ({
|
|
413
467
|
toolCall,
|
|
414
468
|
tool: tools?.find(t => t.name === toolCall.name),
|
|
469
|
+
args: toolCall.arguments as Record<string, unknown>,
|
|
415
470
|
started: false,
|
|
416
471
|
result: undefined as AgentToolResult<any> | undefined,
|
|
417
472
|
isError: false,
|
|
@@ -425,12 +480,22 @@ async function executeToolCalls(
|
|
|
425
480
|
}
|
|
426
481
|
|
|
427
482
|
const { toolCall, tool } = record;
|
|
483
|
+
let argsForExecution = toolCall.arguments as Record<string, unknown>;
|
|
484
|
+
if (intentTracing) {
|
|
485
|
+
const { intent, strippedArgs } = extractIntent(toolCall.arguments);
|
|
486
|
+
argsForExecution = strippedArgs;
|
|
487
|
+
if (intent) {
|
|
488
|
+
toolCall.intent = intent;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
record.args = argsForExecution;
|
|
428
492
|
record.started = true;
|
|
429
493
|
stream.push({
|
|
430
494
|
type: "tool_execution_start",
|
|
431
495
|
toolCallId: toolCall.id,
|
|
432
496
|
toolName: toolCall.name,
|
|
433
|
-
args:
|
|
497
|
+
args: argsForExecution,
|
|
498
|
+
intent: toolCall.intent,
|
|
434
499
|
});
|
|
435
500
|
|
|
436
501
|
let result: AgentToolResult<any>;
|
|
@@ -439,7 +504,7 @@ async function executeToolCalls(
|
|
|
439
504
|
try {
|
|
440
505
|
if (!tool) throw new Error(`Tool ${toolCall.name} not found`);
|
|
441
506
|
|
|
442
|
-
const validatedArgs = validateToolArguments(tool, toolCall);
|
|
507
|
+
const validatedArgs = validateToolArguments(tool, { ...toolCall, arguments: argsForExecution });
|
|
443
508
|
const toolContext = getToolContext
|
|
444
509
|
? getToolContext({
|
|
445
510
|
batchId,
|
|
@@ -458,7 +523,7 @@ async function executeToolCalls(
|
|
|
458
523
|
type: "tool_execution_update",
|
|
459
524
|
toolCallId: toolCall.id,
|
|
460
525
|
toolName: toolCall.name,
|
|
461
|
-
args:
|
|
526
|
+
args: argsForExecution,
|
|
462
527
|
partialResult,
|
|
463
528
|
});
|
|
464
529
|
},
|
|
@@ -512,7 +577,8 @@ async function executeToolCalls(
|
|
|
512
577
|
type: "tool_execution_start",
|
|
513
578
|
toolCallId: toolCall.id,
|
|
514
579
|
toolName: toolCall.name,
|
|
515
|
-
args:
|
|
580
|
+
args: record.args,
|
|
581
|
+
intent: toolCall.intent,
|
|
516
582
|
});
|
|
517
583
|
}
|
|
518
584
|
stream.push({
|
|
@@ -568,6 +634,7 @@ function createAbortedToolResult(
|
|
|
568
634
|
toolCallId: toolCall.id,
|
|
569
635
|
toolName: toolCall.name,
|
|
570
636
|
args: toolCall.arguments,
|
|
637
|
+
intent: toolCall.intent,
|
|
571
638
|
});
|
|
572
639
|
stream.push({
|
|
573
640
|
type: "tool_execution_end",
|
package/src/agent.ts
CHANGED
|
@@ -137,6 +137,9 @@ export interface AgentOptions {
|
|
|
137
137
|
*/
|
|
138
138
|
transformToolCallArguments?: (args: Record<string, unknown>, toolName: string) => Record<string, unknown>;
|
|
139
139
|
|
|
140
|
+
/** Enable intent tracing schema injection/stripping in the harness. */
|
|
141
|
+
intentTracing?: boolean;
|
|
142
|
+
|
|
140
143
|
/**
|
|
141
144
|
* Cursor exec handlers for local tool execution.
|
|
142
145
|
*/
|
|
@@ -193,6 +196,7 @@ export class Agent {
|
|
|
193
196
|
#kimiApiFormat?: "openai" | "anthropic";
|
|
194
197
|
#preferWebsockets?: boolean;
|
|
195
198
|
#transformToolCallArguments?: (args: Record<string, unknown>, toolName: string) => Record<string, unknown>;
|
|
199
|
+
#intentTracing: boolean;
|
|
196
200
|
|
|
197
201
|
/** Buffered Cursor tool results with text length at time of call (for correct ordering) */
|
|
198
202
|
#cursorToolResultBuffer: CursorToolResultEntry[] = [];
|
|
@@ -220,6 +224,7 @@ export class Agent {
|
|
|
220
224
|
this.#kimiApiFormat = opts.kimiApiFormat;
|
|
221
225
|
this.#preferWebsockets = opts.preferWebsockets;
|
|
222
226
|
this.#transformToolCallArguments = opts.transformToolCallArguments;
|
|
227
|
+
this.#intentTracing = opts.intentTracing === true;
|
|
223
228
|
}
|
|
224
229
|
|
|
225
230
|
/**
|
|
@@ -641,6 +646,7 @@ export class Agent {
|
|
|
641
646
|
cursorExecHandlers: this.#cursorExecHandlers,
|
|
642
647
|
cursorOnToolResult,
|
|
643
648
|
transformToolCallArguments: this.#transformToolCallArguments,
|
|
649
|
+
intentTracing: this.#intentTracing,
|
|
644
650
|
getSteeringMessages: async () => {
|
|
645
651
|
if (skipInitialSteeringPoll) {
|
|
646
652
|
skipInitialSteeringPoll = false;
|
package/src/types.ts
CHANGED
|
@@ -117,6 +117,12 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
117
117
|
* Use for deobfuscating secrets or rewriting arguments.
|
|
118
118
|
*/
|
|
119
119
|
transformToolCallArguments?: (args: Record<string, unknown>, toolName: string) => Record<string, unknown>;
|
|
120
|
+
/**
|
|
121
|
+
* Enable intent tracing for tool calls.
|
|
122
|
+
* When enabled, the harness injects a `_intent: string` field into tool schemas sent to the model,
|
|
123
|
+
* then strips `_intent` from arguments before executing tools.
|
|
124
|
+
*/
|
|
125
|
+
intentTracing?: boolean;
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
export interface ToolCallContext {
|
|
@@ -265,6 +271,6 @@ export type AgentEvent =
|
|
|
265
271
|
| { type: "message_update"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }
|
|
266
272
|
| { type: "message_end"; message: AgentMessage }
|
|
267
273
|
// Tool execution lifecycle
|
|
268
|
-
| { type: "tool_execution_start"; toolCallId: string; toolName: string; args: any }
|
|
274
|
+
| { type: "tool_execution_start"; toolCallId: string; toolName: string; args: any; intent?: string }
|
|
269
275
|
| { type: "tool_execution_update"; toolCallId: string; toolName: string; args: any; partialResult: any }
|
|
270
276
|
| { type: "tool_execution_end"; toolCallId: string; toolName: string; result: any; isError?: boolean };
|