@f5-sales-demo/pi-agent-core 19.88.0 → 19.89.1

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 (2) hide show
  1. package/package.json +3 -3
  2. package/src/agent.ts +36 -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": "19.88.0",
4
+ "version": "19.89.1",
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.88.0",
39
- "@f5-sales-demo/pi-utils": "19.88.0"
38
+ "@f5-sales-demo/pi-ai": "19.89.1",
39
+ "@f5-sales-demo/pi-utils": "19.89.1"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@sinclair/typebox": "^0.34",
package/src/agent.ts CHANGED
@@ -193,6 +193,39 @@ export interface AgentOptions {
193
193
 
194
194
  export interface AgentPromptOptions {
195
195
  toolChoice?: ToolChoice;
196
+ /**
197
+ * Raw provider "server tool" specs to append to THIS turn's request `tools`
198
+ * (e.g. Anthropic's `{type:"web_search_20250305", name:"web_search", max_uses:N}`).
199
+ * Injected via the provider `onPayload` seam so it touches only this turn — every
200
+ * other turn/session is unchanged. Empty/undefined ⇒ no-op.
201
+ */
202
+ serverTools?: Record<string, unknown>[];
203
+ }
204
+
205
+ /**
206
+ * Compose the per-turn `onPayload` seam: run the base (extension) hook first, then
207
+ * append any per-turn server-tool specs to the request `tools`. Returns `undefined`
208
+ * (a true no-op — the provider skips the hook entirely) when there's neither a base
209
+ * hook nor server tools, so the default path is byte-identical to before.
210
+ */
211
+ export function composeOnPayload(
212
+ base: SimpleStreamOptions["onPayload"] | undefined,
213
+ serverTools: Record<string, unknown>[] | undefined,
214
+ ): SimpleStreamOptions["onPayload"] | undefined {
215
+ const hasServerTools = Array.isArray(serverTools) && serverTools.length > 0;
216
+ if (!base && !hasServerTools) return undefined;
217
+ return async (payload, model) => {
218
+ let p = payload;
219
+ if (base) {
220
+ const replaced = await base(p, model);
221
+ if (replaced !== undefined) p = replaced;
222
+ }
223
+ if (hasServerTools && p && typeof p === "object") {
224
+ const params = p as { tools?: unknown[] };
225
+ params.tools = [...(params.tools ?? []), ...serverTools];
226
+ }
227
+ return p;
228
+ };
196
229
  }
197
230
 
198
231
  /** Buffered Cursor tool result with text position at time of call */
@@ -763,7 +796,9 @@ export class Agent {
763
796
  preferWebsockets: this.#preferWebsockets,
764
797
  convertToLlm: this.#convertToLlm,
765
798
  transformContext: this.#transformContext,
766
- onPayload: this.#onPayload,
799
+ // Per-turn: compose the extension hook with any server-tool injection for
800
+ // THIS prompt (e.g. Office "Search the web"). No-op when neither is present.
801
+ onPayload: composeOnPayload(this.#onPayload, options?.serverTools),
767
802
  getApiKey: this.getApiKey,
768
803
  getToolContext: this.#getToolContext,
769
804
  syncContextBeforeModelCall: async context => {