@f5-sales-demo/pi-agent-core 19.61.1 → 19.61.3
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 +19 -10
- package/src/agent.ts +77 -72
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": "19.61.
|
|
4
|
+
"version": "19.61.3",
|
|
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": "19.61.
|
|
39
|
-
"@f5-sales-demo/pi-utils": "19.61.
|
|
38
|
+
"@f5-sales-demo/pi-ai": "19.61.3",
|
|
39
|
+
"@f5-sales-demo/pi-utils": "19.61.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@sinclair/typebox": "^0.34",
|
package/src/agent-loop.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type ToolResultMessage,
|
|
11
11
|
validateToolArguments,
|
|
12
12
|
} from "@f5-sales-demo/pi-ai";
|
|
13
|
+
import { logger } from "@f5-sales-demo/pi-utils";
|
|
13
14
|
import type {
|
|
14
15
|
AgentContext,
|
|
15
16
|
AgentEvent,
|
|
@@ -218,7 +219,7 @@ async function runLoop(
|
|
|
218
219
|
|
|
219
220
|
// Refresh prompt/tool context from live state before each model call
|
|
220
221
|
if (config.syncContextBeforeModelCall) {
|
|
221
|
-
await config.syncContextBeforeModelCall(currentContext);
|
|
222
|
+
await logger.ttftAttr("ttft.sync-context", () => config.syncContextBeforeModelCall!(currentContext));
|
|
222
223
|
}
|
|
223
224
|
|
|
224
225
|
// Stream assistant response
|
|
@@ -306,18 +307,18 @@ async function streamAssistantResponse(
|
|
|
306
307
|
// Apply context transform if configured (AgentMessage[] → AgentMessage[])
|
|
307
308
|
let messages = context.messages;
|
|
308
309
|
if (config.transformContext) {
|
|
309
|
-
messages = await config.transformContext(messages, signal);
|
|
310
|
+
messages = await logger.ttftAttr("ttft.transform-context", () => config.transformContext!(messages, signal));
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
// Convert to LLM-compatible messages (AgentMessage[] → Message[])
|
|
313
|
-
const llmMessages = await config.convertToLlm(messages);
|
|
314
|
+
const llmMessages = await logger.ttftAttr("ttft.convert-to-llm", () => config.convertToLlm(messages));
|
|
314
315
|
const normalizedMessages = normalizeMessagesForProvider(llmMessages, config.model);
|
|
315
316
|
|
|
316
317
|
// Build LLM context
|
|
317
318
|
const llmContext: Context = {
|
|
318
319
|
systemPrompt: context.systemPrompt,
|
|
319
320
|
messages: normalizedMessages,
|
|
320
|
-
tools: normalizeTools(context.tools, !!config.intentTracing),
|
|
321
|
+
tools: logger.ttftAttr("ttft.normalize-tools", () => normalizeTools(context.tools, !!config.intentTracing)),
|
|
321
322
|
};
|
|
322
323
|
|
|
323
324
|
const streamFunction = streamFn || streamSimple;
|
|
@@ -327,17 +328,25 @@ async function streamAssistantResponse(
|
|
|
327
328
|
(config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
|
|
328
329
|
|
|
329
330
|
const dynamicToolChoice = config.getToolChoice?.();
|
|
330
|
-
const response = await
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
331
|
+
const response = await logger.ttftAttr("ttft.stream-fn", () =>
|
|
332
|
+
streamFunction(config.model, llmContext, {
|
|
333
|
+
...config,
|
|
334
|
+
apiKey: resolvedApiKey,
|
|
335
|
+
toolChoice: dynamicToolChoice ?? config.toolChoice,
|
|
336
|
+
signal,
|
|
337
|
+
}),
|
|
338
|
+
);
|
|
339
|
+
const tAfterStream = performance.now();
|
|
336
340
|
|
|
337
341
|
let partialMessage: AssistantMessage | null = null;
|
|
338
342
|
let addedPartial = false;
|
|
343
|
+
let firstDeltaMarked = false;
|
|
339
344
|
|
|
340
345
|
for await (const event of response) {
|
|
346
|
+
if (!firstDeltaMarked && event.type === "text_delta") {
|
|
347
|
+
firstDeltaMarked = true;
|
|
348
|
+
logger.ttftMark("ttft.first-token-wait", performance.now() - tAfterStream);
|
|
349
|
+
}
|
|
341
350
|
// Check for abort signal before processing each event
|
|
342
351
|
if (signal?.aborted) {
|
|
343
352
|
const errorMessage = "Request was aborted";
|
package/src/agent.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type ToolChoice,
|
|
21
21
|
type ToolResultMessage,
|
|
22
22
|
} from "@f5-sales-demo/pi-ai";
|
|
23
|
+
import { logger } from "@f5-sales-demo/pi-utils";
|
|
23
24
|
import { agentLoop, agentLoopContinue } from "./agent-loop";
|
|
24
25
|
import type {
|
|
25
26
|
AgentContext,
|
|
@@ -711,81 +712,85 @@ export class Agent {
|
|
|
711
712
|
|
|
712
713
|
const reasoning = this.#state.thinkingLevel;
|
|
713
714
|
|
|
714
|
-
const context
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
715
|
+
const { context, config } = logger.ttftAttr("ttft.runloop-setup", () => {
|
|
716
|
+
const context: AgentContext = {
|
|
717
|
+
systemPrompt: this.#state.systemPrompt,
|
|
718
|
+
messages: this.#state.messages.slice(),
|
|
719
|
+
tools: this.#state.tools,
|
|
720
|
+
};
|
|
719
721
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
722
|
+
const cursorOnToolResult =
|
|
723
|
+
this.#cursorExecHandlers || this.#cursorOnToolResult
|
|
724
|
+
? async (message: ToolResultMessage) => {
|
|
725
|
+
let finalMessage = message;
|
|
726
|
+
if (this.#cursorOnToolResult) {
|
|
727
|
+
try {
|
|
728
|
+
const updated = await this.#cursorOnToolResult(message);
|
|
729
|
+
if (updated) {
|
|
730
|
+
finalMessage = updated;
|
|
731
|
+
}
|
|
732
|
+
} catch {}
|
|
733
|
+
}
|
|
734
|
+
// Buffer tool result with current text length for correct ordering later.
|
|
735
|
+
// Cursor executes tools server-side during streaming, so the assistant message
|
|
736
|
+
// already incorporates results. We buffer here and emit in correct order
|
|
737
|
+
// when the assistant message ends.
|
|
738
|
+
const textLength = this.#getAssistantTextLength(this.#state.streamMessage);
|
|
739
|
+
this.#cursorToolResultBuffer.push({ toolResult: finalMessage, textLengthAtCall: textLength });
|
|
740
|
+
return finalMessage;
|
|
731
741
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
742
|
+
: undefined;
|
|
743
|
+
|
|
744
|
+
const getToolChoice = () =>
|
|
745
|
+
this.#getToolChoice?.() ?? refreshToolChoiceForActiveTools(options?.toolChoice, this.#state.tools);
|
|
746
|
+
|
|
747
|
+
const config: AgentLoopConfig = {
|
|
748
|
+
model,
|
|
749
|
+
reasoning,
|
|
750
|
+
temperature: this.#temperature,
|
|
751
|
+
topP: this.#topP,
|
|
752
|
+
topK: this.#topK,
|
|
753
|
+
minP: this.#minP,
|
|
754
|
+
presencePenalty: this.#presencePenalty,
|
|
755
|
+
repetitionPenalty: this.#repetitionPenalty,
|
|
756
|
+
serviceTier: this.#serviceTier,
|
|
757
|
+
interruptMode: this.#interruptMode,
|
|
758
|
+
sessionId: this.#sessionId,
|
|
759
|
+
providerSessionState: this.#providerSessionState,
|
|
760
|
+
thinkingBudgets: this.#thinkingBudgets,
|
|
761
|
+
maxRetryDelayMs: this.#maxRetryDelayMs,
|
|
762
|
+
kimiApiFormat: this.#kimiApiFormat,
|
|
763
|
+
preferWebsockets: this.#preferWebsockets,
|
|
764
|
+
convertToLlm: this.#convertToLlm,
|
|
765
|
+
transformContext: this.#transformContext,
|
|
766
|
+
onPayload: this.#onPayload,
|
|
767
|
+
getApiKey: this.getApiKey,
|
|
768
|
+
getToolContext: this.#getToolContext,
|
|
769
|
+
syncContextBeforeModelCall: async context => {
|
|
770
|
+
if (this.#listeners.size > 0) {
|
|
771
|
+
await Bun.sleep(0);
|
|
739
772
|
}
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
preferWebsockets: this.#preferWebsockets,
|
|
762
|
-
convertToLlm: this.#convertToLlm,
|
|
763
|
-
transformContext: this.#transformContext,
|
|
764
|
-
onPayload: this.#onPayload,
|
|
765
|
-
getApiKey: this.getApiKey,
|
|
766
|
-
getToolContext: this.#getToolContext,
|
|
767
|
-
syncContextBeforeModelCall: async context => {
|
|
768
|
-
if (this.#listeners.size > 0) {
|
|
769
|
-
await Bun.sleep(0);
|
|
770
|
-
}
|
|
771
|
-
context.systemPrompt = this.#state.systemPrompt;
|
|
772
|
-
context.tools = this.#state.tools;
|
|
773
|
-
},
|
|
774
|
-
cursorExecHandlers: this.#cursorExecHandlers,
|
|
775
|
-
cursorOnToolResult,
|
|
776
|
-
transformToolCallArguments: this.#transformToolCallArguments,
|
|
777
|
-
intentTracing: this.#intentTracing,
|
|
778
|
-
onAssistantMessageEvent: this.#onAssistantMessageEvent,
|
|
779
|
-
getToolChoice,
|
|
780
|
-
getSteeringMessages: async () => {
|
|
781
|
-
if (skipInitialSteeringPoll) {
|
|
782
|
-
skipInitialSteeringPoll = false;
|
|
783
|
-
return [];
|
|
784
|
-
}
|
|
785
|
-
return this.#dequeueSteeringMessages();
|
|
786
|
-
},
|
|
787
|
-
getFollowUpMessages: async () => this.#dequeueFollowUpMessages(),
|
|
788
|
-
};
|
|
773
|
+
context.systemPrompt = this.#state.systemPrompt;
|
|
774
|
+
context.tools = this.#state.tools;
|
|
775
|
+
},
|
|
776
|
+
cursorExecHandlers: this.#cursorExecHandlers,
|
|
777
|
+
cursorOnToolResult,
|
|
778
|
+
transformToolCallArguments: this.#transformToolCallArguments,
|
|
779
|
+
intentTracing: this.#intentTracing,
|
|
780
|
+
onAssistantMessageEvent: this.#onAssistantMessageEvent,
|
|
781
|
+
getToolChoice,
|
|
782
|
+
getSteeringMessages: async () => {
|
|
783
|
+
if (skipInitialSteeringPoll) {
|
|
784
|
+
skipInitialSteeringPoll = false;
|
|
785
|
+
return [];
|
|
786
|
+
}
|
|
787
|
+
return this.#dequeueSteeringMessages();
|
|
788
|
+
},
|
|
789
|
+
getFollowUpMessages: async () => this.#dequeueFollowUpMessages(),
|
|
790
|
+
};
|
|
791
|
+
|
|
792
|
+
return { context, config };
|
|
793
|
+
});
|
|
789
794
|
|
|
790
795
|
let partial: AgentMessage | null = null;
|
|
791
796
|
|