@f5-sales-demo/pi-agent-core 21.25.0 → 21.27.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 +3 -3
- package/src/agent-loop.ts +23 -5
- package/src/agent.ts +10 -0
- package/src/index.ts +2 -0
- package/src/tool-error.ts +12 -0
- package/src/types.ts +22 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/pi-agent-core",
|
|
4
|
-
"version": "21.
|
|
4
|
+
"version": "21.27.0",
|
|
5
5
|
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"fmt": "biome format --write ."
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@f5-sales-demo/pi-ai": "21.
|
|
39
|
-
"@f5-sales-demo/pi-utils": "21.
|
|
38
|
+
"@f5-sales-demo/pi-ai": "21.27.0",
|
|
39
|
+
"@f5-sales-demo/pi-utils": "21.27.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@sinclair/typebox": "0.34.52",
|
package/src/agent-loop.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from "@f5-sales-demo/pi-ai";
|
|
13
13
|
import { logger } from "@f5-sales-demo/pi-utils";
|
|
14
14
|
import emptyToolSuccess from "./prompts/empty-tool-success.md" with { type: "text" };
|
|
15
|
+
import { AgentToolError } from "./tool-error";
|
|
15
16
|
import type {
|
|
16
17
|
AgentContext,
|
|
17
18
|
AgentEvent,
|
|
@@ -21,6 +22,7 @@ import type {
|
|
|
21
22
|
AgentToolResult,
|
|
22
23
|
StreamFn,
|
|
23
24
|
} from "./types";
|
|
25
|
+
import { getToolExecutionKind } from "./types";
|
|
24
26
|
|
|
25
27
|
/**
|
|
26
28
|
* Start an agent loop with a new prompt message.
|
|
@@ -224,7 +226,7 @@ async function runLoop(
|
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
// Stream assistant response
|
|
227
|
-
const message = await streamAssistantResponse(currentContext, config, signal, stream, streamFn);
|
|
229
|
+
const message = await streamAssistantResponse(currentContext, newMessages, config, signal, stream, streamFn);
|
|
228
230
|
newMessages.push(message);
|
|
229
231
|
let steeringMessagesFromExecution: AgentMessage[] | undefined;
|
|
230
232
|
|
|
@@ -300,6 +302,7 @@ async function runLoop(
|
|
|
300
302
|
*/
|
|
301
303
|
async function streamAssistantResponse(
|
|
302
304
|
context: AgentContext,
|
|
305
|
+
newMessages: AgentMessage[],
|
|
303
306
|
config: AgentLoopConfig,
|
|
304
307
|
signal: AbortSignal | undefined,
|
|
305
308
|
stream: EventStream<AgentEvent, AgentMessage[]>,
|
|
@@ -310,6 +313,14 @@ async function streamAssistantResponse(
|
|
|
310
313
|
if (config.transformContext) {
|
|
311
314
|
messages = await logger.ttftAttr("ttft.transform-context", () => config.transformContext!(messages, signal));
|
|
312
315
|
}
|
|
316
|
+
const injected = signal?.aborted ? [] : (config.getContextMessages?.(messages) ?? []);
|
|
317
|
+
for (const message of injected) {
|
|
318
|
+
context.messages.push(message);
|
|
319
|
+
newMessages.push(message);
|
|
320
|
+
stream.push({ type: "message_start", message });
|
|
321
|
+
stream.push({ type: "message_end", message });
|
|
322
|
+
}
|
|
323
|
+
if (injected.length > 0 && messages !== context.messages) messages = [...messages, ...injected];
|
|
313
324
|
|
|
314
325
|
// Convert to LLM-compatible messages (AgentMessage[] → Message[])
|
|
315
326
|
const llmMessages = await logger.ttftAttr("ttft.convert-to-llm", () => config.convertToLlm(messages));
|
|
@@ -504,12 +515,14 @@ async function executeToolCalls(
|
|
|
504
515
|
const normalizedResult = normalizeToolResult(result, isError);
|
|
505
516
|
const { toolCall } = record;
|
|
506
517
|
if (!record.started) {
|
|
518
|
+
const executionKind = getToolExecutionKind(record.tool, record.args);
|
|
507
519
|
stream.push({
|
|
508
520
|
type: "tool_execution_start",
|
|
509
521
|
toolCallId: toolCall.id,
|
|
510
522
|
toolName: toolCall.name,
|
|
511
523
|
args: record.args,
|
|
512
524
|
intent: toolCall.intent,
|
|
525
|
+
...(executionKind ? { executionKind } : {}),
|
|
513
526
|
});
|
|
514
527
|
}
|
|
515
528
|
const isWarning = Boolean(normalizedResult.isWarning);
|
|
@@ -559,12 +572,14 @@ async function executeToolCalls(
|
|
|
559
572
|
}
|
|
560
573
|
record.args = argsForExecution;
|
|
561
574
|
record.started = true;
|
|
575
|
+
const executionKind = getToolExecutionKind(tool, argsForExecution);
|
|
562
576
|
stream.push({
|
|
563
577
|
type: "tool_execution_start",
|
|
564
578
|
toolCallId: toolCall.id,
|
|
565
579
|
toolName: toolCall.name,
|
|
566
580
|
args: argsForExecution,
|
|
567
581
|
intent: toolCall.intent,
|
|
582
|
+
...(executionKind ? { executionKind } : {}),
|
|
568
583
|
});
|
|
569
584
|
|
|
570
585
|
let result: AgentToolResult<any>;
|
|
@@ -607,10 +622,13 @@ async function executeToolCalls(
|
|
|
607
622
|
toolContext,
|
|
608
623
|
);
|
|
609
624
|
} catch (e) {
|
|
610
|
-
result =
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
625
|
+
result =
|
|
626
|
+
e instanceof AgentToolError
|
|
627
|
+
? e.result
|
|
628
|
+
: {
|
|
629
|
+
content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }],
|
|
630
|
+
details: {},
|
|
631
|
+
};
|
|
614
632
|
isError = true;
|
|
615
633
|
}
|
|
616
634
|
|
package/src/agent.ts
CHANGED
|
@@ -257,6 +257,7 @@ export class Agent {
|
|
|
257
257
|
#listeners = new Set<(e: AgentEvent) => void>();
|
|
258
258
|
#abortController?: AbortController;
|
|
259
259
|
#convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
|
|
260
|
+
#contextMessages?: AgentLoopConfig["getContextMessages"];
|
|
260
261
|
#transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
|
|
261
262
|
#steeringQueue: AgentMessage[] = [];
|
|
262
263
|
#followUpQueue: AgentMessage[] = [];
|
|
@@ -534,6 +535,14 @@ export class Agent {
|
|
|
534
535
|
this.#state.messages = ms.slice();
|
|
535
536
|
}
|
|
536
537
|
|
|
538
|
+
/** Install the owning session's model-context provider. It must not start work. */
|
|
539
|
+
setContextMessagesProvider(provider?: AgentLoopConfig["getContextMessages"]): () => void {
|
|
540
|
+
this.#contextMessages = provider;
|
|
541
|
+
return () => {
|
|
542
|
+
if (this.#contextMessages === provider) this.#contextMessages = undefined;
|
|
543
|
+
};
|
|
544
|
+
}
|
|
545
|
+
|
|
537
546
|
appendMessage(m: AgentMessage) {
|
|
538
547
|
this.#state.messages = [...this.#state.messages, m];
|
|
539
548
|
}
|
|
@@ -804,6 +813,7 @@ export class Agent {
|
|
|
804
813
|
kimiApiFormat: this.#kimiApiFormat,
|
|
805
814
|
preferWebsockets: this.#preferWebsockets,
|
|
806
815
|
convertToLlm: this.#convertToLlm,
|
|
816
|
+
getContextMessages: messages => this.#contextMessages?.(messages) ?? [],
|
|
807
817
|
transformContext: this.#transformContext,
|
|
808
818
|
// Per-turn: compose the extension hook with any server-tool injection for
|
|
809
819
|
// THIS prompt (e.g. Office "Search the web"). No-op when neither is present.
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AgentToolResult } from "./types";
|
|
2
|
+
|
|
3
|
+
/** A failed execution whose structured result must survive the tool/agent boundary. */
|
|
4
|
+
export class AgentToolError<T = unknown> extends Error {
|
|
5
|
+
constructor(
|
|
6
|
+
message: string,
|
|
7
|
+
readonly result: AgentToolResult<T>,
|
|
8
|
+
) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "AgentToolError";
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -64,6 +64,9 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|
|
64
64
|
*/
|
|
65
65
|
convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
|
|
66
66
|
|
|
67
|
+
/** Session-owned context updates after pruning; emitted and retained like other messages. */
|
|
68
|
+
getContextMessages?: (messages: readonly AgentMessage[]) => AgentMessage[];
|
|
69
|
+
|
|
67
70
|
/**
|
|
68
71
|
* Optional transform applied to the context before `convertToLlm`.
|
|
69
72
|
*
|
|
@@ -242,6 +245,10 @@ export interface AgentTool<TParameters extends TSchema = TSchema, TDetails = any
|
|
|
242
245
|
extends Tool<TParameters> {
|
|
243
246
|
// A human-readable label for the tool to be displayed in UI
|
|
244
247
|
label: string;
|
|
248
|
+
/** Host presentation of the actual executor; absent for ordinary dynamic tools. */
|
|
249
|
+
executionKind?: "command" | "fileChange";
|
|
250
|
+
/** Pure per-call classification; returning undefined preserves ordinary dynamic-tool presentation. */
|
|
251
|
+
getExecutionKind?: (params: unknown) => "command" | "fileChange" | undefined;
|
|
245
252
|
/** If true, tool is excluded unless explicitly listed in --tools or agent's tools field */
|
|
246
253
|
hidden?: boolean;
|
|
247
254
|
/** If true, tool can stage a pending action that requires explicit resolution via the resolve tool. */
|
|
@@ -293,7 +300,14 @@ export type AgentEvent =
|
|
|
293
300
|
| { type: "message_update"; message: AgentMessage; assistantMessageEvent: AssistantMessageEvent }
|
|
294
301
|
| { type: "message_end"; message: AgentMessage }
|
|
295
302
|
// Tool execution lifecycle
|
|
296
|
-
| {
|
|
303
|
+
| {
|
|
304
|
+
type: "tool_execution_start";
|
|
305
|
+
toolCallId: string;
|
|
306
|
+
toolName: string;
|
|
307
|
+
args: any;
|
|
308
|
+
intent?: string;
|
|
309
|
+
executionKind?: "command" | "fileChange";
|
|
310
|
+
}
|
|
297
311
|
| { type: "tool_execution_update"; toolCallId: string; toolName: string; args: any; partialResult: any }
|
|
298
312
|
| {
|
|
299
313
|
type: "tool_execution_end";
|
|
@@ -303,3 +317,10 @@ export type AgentEvent =
|
|
|
303
317
|
isError?: boolean;
|
|
304
318
|
isWarning?: boolean;
|
|
305
319
|
};
|
|
320
|
+
|
|
321
|
+
export function getToolExecutionKind(
|
|
322
|
+
tool: AgentTool | undefined,
|
|
323
|
+
params: unknown,
|
|
324
|
+
): "command" | "fileChange" | undefined {
|
|
325
|
+
return tool?.getExecutionKind ? tool.getExecutionKind(params) : tool?.executionKind;
|
|
326
|
+
}
|