@f5-sales-demo/pi-agent-core 20.2.4 → 20.2.6

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/README.md +67 -67
  3. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -3,6 +3,7 @@
3
3
  ## [Unreleased]
4
4
 
5
5
  ## [14.0.1] - 2026-04-08
6
+
6
7
  ### Added
7
8
 
8
9
  - Added `onAssistantMessageEvent` callback option to inspect assistant streaming events before they are emitted, enabling abort decisions before buffered events continue flowing
@@ -25,6 +26,7 @@
25
26
  - Fixed stale forced toolChoice being passed to provider after tools are refreshed mid-turn
26
27
 
27
28
  ## [13.9.16] - 2026-03-10
29
+
28
30
  ### Added
29
31
 
30
32
  - Added `onPayload` option to `AgentOptions` to inspect or replace provider payloads before they are sent
@@ -43,11 +45,13 @@
43
45
  - Updated `setThinkingLevel()` method to accept `Effort | undefined` instead of `ThinkingLevel` string
44
46
 
45
47
  ## [13.4.0] - 2026-03-01
48
+
46
49
  ### Added
47
50
 
48
51
  - Added `getToolChoice` option to dynamically override tool choice per LLM call
49
52
 
50
53
  ## [13.3.8] - 2026-02-28
54
+
51
55
  ### Changed
52
56
 
53
57
  - Changed intent field name from `agent__intent` to `_i` in tool schemas
@@ -55,12 +59,15 @@
55
59
  ### Fixed
56
60
 
57
61
  - Fixed synthetic tool result text formatting so aborted/error tool results no longer emit `Tool execution was aborted.: Request was aborted` style punctuation.
62
+
58
63
  ## [13.3.7] - 2026-02-27
64
+
59
65
  ### Added
60
66
 
61
67
  - Added `lenientArgValidation` option to tools to allow graceful handling of argument validation errors by passing raw arguments to execute() instead of returning an error to the LLM
62
68
 
63
69
  ## [13.3.1] - 2026-02-26
70
+
64
71
  ### Added
65
72
 
66
73
  - Added `topP`, `topK`, `minP`, `presencePenalty`, and `repetitionPenalty` options to `AgentOptions` for fine-grained sampling control
@@ -71,7 +78,9 @@
71
78
  ### Changed
72
79
 
73
80
  - Removed per-tool `agent__intent` field description from injected schema to reduce token usage; intent format is now documented once in the system prompt instead of repeated in every tool definition
81
+
74
82
  ## [12.19.0] - 2026-02-22
83
+
75
84
  ### Changed
76
85
 
77
86
  - Updated tool result messages to include error details when tool execution fails
@@ -316,4 +325,4 @@ Initial release under @oh-my-pi scope. See previous releases at [badlogic/pi-mon
316
325
 
317
326
  - `Agent` constructor now has all options optional (empty options use defaults).
318
327
 
319
- - `queueMessage()` is now synchronous (no longer returns a Promise).
328
+ - `queueMessage()` is now synchronous (no longer returns a Promise).
package/README.md CHANGED
@@ -15,17 +15,17 @@ import { Agent } from "@f5-sales-demo/pi-agent";
15
15
  import { getModel } from "@f5-sales-demo/pi-ai";
16
16
 
17
17
  const agent = new Agent({
18
- initialState: {
19
- systemPrompt: "You are a helpful assistant.",
20
- model: getModel("anthropic", "claude-sonnet-4-20250514"),
21
- },
18
+ initialState: {
19
+ systemPrompt: "You are a helpful assistant.",
20
+ model: getModel("anthropic", "claude-sonnet-4-20250514"),
21
+ },
22
22
  });
23
23
 
24
24
  agent.subscribe((event) => {
25
- if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
26
- // Stream just the new text chunk
27
- process.stdout.write(event.assistantMessageEvent.delta);
28
- }
25
+ if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
26
+ // Stream just the new text chunk
27
+ process.stdout.write(event.assistantMessageEvent.delta);
28
+ }
29
29
  });
30
30
 
31
31
  await agent.prompt("Hello!");
@@ -163,15 +163,15 @@ const agent = new Agent({
163
163
 
164
164
  ```typescript
165
165
  interface AgentState {
166
- systemPrompt: string;
167
- model: Model;
168
- thinkingLevel: ThinkingLevel;
169
- tools: AgentTool<any>[];
170
- messages: AgentMessage[];
171
- isStreaming: boolean;
172
- streamMessage: AgentMessage | null; // Current partial during streaming
173
- pendingToolCalls: Set<string>;
174
- error?: string;
166
+ systemPrompt: string;
167
+ model: Model;
168
+ thinkingLevel: ThinkingLevel;
169
+ tools: AgentTool<any>[];
170
+ messages: AgentMessage[];
171
+ isStreaming: boolean;
172
+ streamMessage: AgentMessage | null; // Current partial during streaming
173
+ pendingToolCalls: Set<string>;
174
+ error?: string;
175
175
  }
176
176
  ```
177
177
 
@@ -219,7 +219,7 @@ await agent.waitForIdle(); // Wait for completion
219
219
 
220
220
  ```typescript
221
221
  const unsubscribe = agent.subscribe((event) => {
222
- console.log(event.type);
222
+ console.log(event.type);
223
223
  });
224
224
  unsubscribe();
225
225
  ```
@@ -234,16 +234,16 @@ agent.setInterruptMode("immediate");
234
234
 
235
235
  // While agent is running tools
236
236
  agent.steer({
237
- role: "user",
238
- content: "Stop! Do this instead.",
239
- timestamp: Date.now(),
237
+ role: "user",
238
+ content: "Stop! Do this instead.",
239
+ timestamp: Date.now(),
240
240
  });
241
241
 
242
242
  // Queue a follow-up to run after the current turn completes
243
243
  agent.followUp({
244
- role: "user",
245
- content: "After that, summarize the changes.",
246
- timestamp: Date.now(),
244
+ role: "user",
245
+ content: "After that, summarize the changes.",
246
+ timestamp: Date.now(),
247
247
  });
248
248
  ```
249
249
 
@@ -256,9 +256,9 @@ Extend `AgentMessage` via declaration merging:
256
256
 
257
257
  ```typescript
258
258
  declare module "@f5-sales-demo/pi-agent" {
259
- interface CustomAgentMessages {
260
- notification: { role: "notification"; text: string; timestamp: number };
261
- }
259
+ interface CustomAgentMessages {
260
+ notification: { role: "notification"; text: string; timestamp: number };
261
+ }
262
262
  }
263
263
 
264
264
  // Now valid
@@ -269,11 +269,11 @@ Handle custom types in `convertToLlm`:
269
269
 
270
270
  ```typescript
271
271
  const agent = new Agent({
272
- convertToLlm: (messages) =>
273
- messages.flatMap((m) => {
274
- if (m.role === "notification") return []; // Filter out
275
- return [m];
276
- }),
272
+ convertToLlm: (messages) =>
273
+ messages.flatMap((m) => {
274
+ if (m.role === "notification") return []; // Filter out
275
+ return [m];
276
+ }),
277
277
  });
278
278
  ```
279
279
 
@@ -285,23 +285,23 @@ Define tools using `AgentTool`:
285
285
  import { Type } from "@sinclair/typebox";
286
286
 
287
287
  const readFileTool: AgentTool = {
288
- name: "read_file",
289
- label: "Read File", // For UI display
290
- description: "Read a file's contents",
291
- parameters: Type.Object({
292
- path: Type.String({ description: "File path" }),
293
- }),
294
- execute: async (toolCallId, params, signal, onUpdate, context) => {
295
- const content = await fs.readFile(params.path, "utf-8");
296
-
297
- // Optional: stream progress
298
- onUpdate?.({ content: [{ type: "text", text: "Reading..." }], details: {} });
299
-
300
- return {
301
- content: [{ type: "text", text: content }],
302
- details: { path: params.path, size: content.length },
303
- };
304
- },
288
+ name: "read_file",
289
+ label: "Read File", // For UI display
290
+ description: "Read a file's contents",
291
+ parameters: Type.Object({
292
+ path: Type.String({ description: "File path" }),
293
+ }),
294
+ execute: async (toolCallId, params, signal, onUpdate, context) => {
295
+ const content = await fs.readFile(params.path, "utf-8");
296
+
297
+ // Optional: stream progress
298
+ onUpdate?.({ content: [{ type: "text", text: "Reading..." }], details: {} });
299
+
300
+ return {
301
+ content: [{ type: "text", text: content }],
302
+ details: { path: params.path, size: content.length },
303
+ };
304
+ },
305
305
  };
306
306
 
307
307
  agent.setTools([readFileTool]);
@@ -313,11 +313,11 @@ agent.setTools([readFileTool]);
313
313
 
314
314
  ```typescript
315
315
  execute: async (toolCallId, params, signal, onUpdate) => {
316
- if (!fs.existsSync(params.path)) {
317
- throw new Error(`File not found: ${params.path}`);
318
- }
319
- // Return content only on success
320
- return { content: [{ type: "text", text: "..." }] };
316
+ if (!fs.existsSync(params.path)) {
317
+ throw new Error(`File not found: ${params.path}`);
318
+ }
319
+ // Return content only on success
320
+ return { content: [{ type: "text", text: "..." }] };
321
321
  };
322
322
  ```
323
323
 
@@ -331,12 +331,12 @@ For browser apps that proxy through a backend:
331
331
  import { Agent, streamProxy } from "@f5-sales-demo/pi-agent";
332
332
 
333
333
  const agent = new Agent({
334
- streamFn: (model, context, options) =>
335
- streamProxy(model, context, {
336
- ...options,
337
- authToken: "...",
338
- proxyUrl: "https://your-server.com",
339
- }),
334
+ streamFn: (model, context, options) =>
335
+ streamProxy(model, context, {
336
+ ...options,
337
+ authToken: "...",
338
+ proxyUrl: "https://your-server.com",
339
+ }),
340
340
  });
341
341
  ```
342
342
 
@@ -348,25 +348,25 @@ For direct control without the Agent class:
348
348
  import { agentLoop, agentLoopContinue } from "@f5-sales-demo/pi-agent";
349
349
 
350
350
  const context: AgentContext = {
351
- systemPrompt: "You are helpful.",
352
- messages: [],
353
- tools: [],
351
+ systemPrompt: "You are helpful.",
352
+ messages: [],
353
+ tools: [],
354
354
  };
355
355
 
356
356
  const config: AgentLoopConfig = {
357
- model: getModel("openai", "gpt-4o"),
358
- convertToLlm: (msgs) => msgs.filter((m) => ["user", "assistant", "toolResult"].includes(m.role)),
357
+ model: getModel("openai", "gpt-4o"),
358
+ convertToLlm: (msgs) => msgs.filter((m) => ["user", "assistant", "toolResult"].includes(m.role)),
359
359
  };
360
360
 
361
361
  const userMessage = { role: "user", content: "Hello", timestamp: Date.now() };
362
362
 
363
363
  for await (const event of agentLoop([userMessage], context, config)) {
364
- console.log(event.type);
364
+ console.log(event.type);
365
365
  }
366
366
 
367
367
  // Continue from existing context
368
368
  for await (const event of agentLoopContinue(context, config)) {
369
- console.log(event.type);
369
+ console.log(event.type);
370
370
  }
371
371
  ```
372
372
 
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": "20.2.4",
4
+ "version": "20.2.6",
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": "20.2.4",
39
- "@f5-sales-demo/pi-utils": "20.2.4"
38
+ "@f5-sales-demo/pi-ai": "20.2.6",
39
+ "@f5-sales-demo/pi-utils": "20.2.6"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@sinclair/typebox": "^0.34",