@ai-setting/roy-agent-core 1.7.53 → 1.7.56

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 (124) hide show
  1. package/dist/config/index.js +7 -7
  2. package/dist/env/agent/agent-component.d.ts +30 -0
  3. package/dist/env/agent/index.js +13 -12
  4. package/dist/env/commands/index.js +7 -7
  5. package/dist/env/context/index.js +3 -3
  6. package/dist/env/debug/index.js +7 -7
  7. package/dist/env/environment.d.ts +7 -0
  8. package/dist/env/error-reply.d.ts +184 -0
  9. package/dist/env/event-source/event-source-handlers.d.ts +9 -23
  10. package/dist/env/event-source/index.js +17 -17
  11. package/dist/env/hook/index.js +5 -5
  12. package/dist/env/index.js +41 -40
  13. package/dist/env/llm/adapter-ai-sdk.d.ts +6 -0
  14. package/dist/env/llm/adapter-pi-ai.d.ts +152 -2
  15. package/dist/env/llm/adapter.d.ts +21 -1
  16. package/dist/env/llm/index.js +10 -10
  17. package/dist/env/llm/invoke.d.ts +74 -2
  18. package/dist/env/llm/llm.d.ts +38 -0
  19. package/dist/env/llm/outbound-defense.d.ts +140 -0
  20. package/dist/env/llm/reasoning-defense.d.ts +104 -0
  21. package/dist/env/llm/types.d.ts +26 -0
  22. package/dist/env/log-trace/decorator.d.ts +46 -3
  23. package/dist/env/log-trace/index.d.ts +1 -0
  24. package/dist/env/log-trace/index.js +33 -7
  25. package/dist/env/log-trace/trace-filters.d.ts +127 -0
  26. package/dist/env/mcp/index.js +7 -7
  27. package/dist/env/memory/index.js +7 -7
  28. package/dist/env/plugin/index.js +7 -7
  29. package/dist/env/prompt/index.js +8 -8
  30. package/dist/env/prompt/prompts-index.d.ts +1 -1
  31. package/dist/env/session/index.js +11 -10
  32. package/dist/env/session/session-component.d.ts +4 -0
  33. package/dist/env/session/storage/index.js +5 -3
  34. package/dist/env/skill/index.js +7 -7
  35. package/dist/env/task/backend/index.js +0 -2
  36. package/dist/env/task/backend/types.d.ts +0 -11
  37. package/dist/env/task/delegate/index.js +8 -8
  38. package/dist/env/task/index.js +13 -13
  39. package/dist/env/task/plugins/card-chat-routing.d.ts +42 -89
  40. package/dist/env/task/plugins/index.js +10 -10
  41. package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +0 -51
  42. package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +14 -31
  43. package/dist/env/task/plugins/per-task-group-chat-plugin.d.ts +4 -4
  44. package/dist/env/task/storage/index.js +2 -2
  45. package/dist/env/task/tools/index.js +3 -3
  46. package/dist/env/tool/built-in/index.js +3 -3
  47. package/dist/env/tool/index.js +9 -9
  48. package/dist/env/workflow/engine/engine.d.ts +65 -0
  49. package/dist/env/workflow/engine/index.js +12 -12
  50. package/dist/env/workflow/hooks/index.js +7 -7
  51. package/dist/env/workflow/index.js +23 -22
  52. package/dist/env/workflow/nodes/index.js +2 -2
  53. package/dist/env/workflow/nodes/tool-node.d.ts +6 -0
  54. package/dist/env/workflow/plugins/index.js +8 -8
  55. package/dist/env/workflow/service/index.js +2 -2
  56. package/dist/env/workflow/storage/index.js +3 -3
  57. package/dist/env/workflow/tools/index.js +15 -14
  58. package/dist/env/workflow/tools/workflow-validate-tool.d.ts +11 -2
  59. package/dist/env/workflow/types/run.d.ts +19 -0
  60. package/dist/env/workflow/utils/agent-session-metadata.d.ts +13 -0
  61. package/dist/env/workflow/utils/index.js +5 -5
  62. package/dist/env/workflow/utils/redact-command-secrets.d.ts +70 -0
  63. package/dist/env/workflow/utils/shell-dialect-lint.d.ts +75 -0
  64. package/dist/env/workflow/utils/validate-workflow-definition.d.ts +22 -0
  65. package/dist/index.d.ts +1 -1
  66. package/dist/index.js +82 -56
  67. package/dist/shared/@ai-setting/{roy-agent-core-k25gv86p.js → roy-agent-core-0b3fdnn3.js} +1 -1
  68. package/dist/shared/@ai-setting/{roy-agent-core-vvxb9522.js → roy-agent-core-0bmk44ye.js} +71 -10
  69. package/dist/shared/@ai-setting/{roy-agent-core-k8b440n3.js → roy-agent-core-16t0zfbk.js} +1 -1
  70. package/dist/shared/@ai-setting/{roy-agent-core-4z3rq5gw.js → roy-agent-core-1pnfkspm.js} +2 -2
  71. package/dist/shared/@ai-setting/{roy-agent-core-na73mym1.js → roy-agent-core-202v00x4.js} +213 -2
  72. package/dist/shared/@ai-setting/{roy-agent-core-ph5qbqcx.js → roy-agent-core-2044fbsd.js} +471 -134
  73. package/dist/shared/@ai-setting/{roy-agent-core-fs36xgcs.js → roy-agent-core-3dkzqqsd.js} +1 -1
  74. package/dist/shared/@ai-setting/{roy-agent-core-qm9jda8p.js → roy-agent-core-3kz6934b.js} +1 -1
  75. package/dist/shared/@ai-setting/{roy-agent-core-tjg71zqp.js → roy-agent-core-3mc6vmvj.js} +1 -1
  76. package/dist/shared/@ai-setting/{roy-agent-core-tdbv7ff4.js → roy-agent-core-40xzbjtm.js} +2 -2
  77. package/dist/shared/@ai-setting/{roy-agent-core-athdr2m0.js → roy-agent-core-4zy2v3br.js} +10 -2
  78. package/dist/shared/@ai-setting/{roy-agent-core-t37wbysj.js → roy-agent-core-5gw6w424.js} +4 -4
  79. package/dist/shared/@ai-setting/{roy-agent-core-978b6wfx.js → roy-agent-core-5psjwd08.js} +1 -1
  80. package/dist/shared/@ai-setting/{roy-agent-core-7evvpfwc.js → roy-agent-core-5rxs0ra3.js} +1 -1
  81. package/dist/shared/@ai-setting/{roy-agent-core-gdsqp6j8.js → roy-agent-core-6masakz4.js} +45 -0
  82. package/dist/shared/@ai-setting/{roy-agent-core-stnddvx9.js → roy-agent-core-6qgq7h1g.js} +4 -4
  83. package/dist/shared/@ai-setting/{roy-agent-core-6167phd4.js → roy-agent-core-833t16n1.js} +3 -3
  84. package/dist/shared/@ai-setting/{roy-agent-core-2k4xffaa.js → roy-agent-core-8cgtwytv.js} +3 -3
  85. package/dist/shared/@ai-setting/{roy-agent-core-rx16h2m1.js → roy-agent-core-97eyghsp.js} +2 -2
  86. package/dist/shared/@ai-setting/{roy-agent-core-fvs48d38.js → roy-agent-core-98aa9r0x.js} +12 -7
  87. package/dist/shared/@ai-setting/{roy-agent-core-3tv1q6f2.js → roy-agent-core-9nv586rw.js} +57 -19
  88. package/dist/shared/@ai-setting/roy-agent-core-b599jgyd.js +578 -0
  89. package/dist/shared/@ai-setting/{roy-agent-core-yd21n6c7.js → roy-agent-core-bwzy00t2.js} +12 -5
  90. package/dist/shared/@ai-setting/{roy-agent-core-dwx9hjwx.js → roy-agent-core-c6at31ra.js} +1 -1
  91. package/dist/shared/@ai-setting/{roy-agent-core-1cv9j4dg.js → roy-agent-core-d14h726p.js} +3 -3
  92. package/dist/shared/@ai-setting/{roy-agent-core-4sx6sdb2.js → roy-agent-core-d4jpn06f.js} +22 -9
  93. package/dist/shared/@ai-setting/{roy-agent-core-39xejr39.js → roy-agent-core-e0wbq0qq.js} +7 -7
  94. package/dist/shared/@ai-setting/{roy-agent-core-vrsxhw9e.js → roy-agent-core-e677am8e.js} +1 -1
  95. package/dist/shared/@ai-setting/{roy-agent-core-hch2geta.js → roy-agent-core-ezsyyjxw.js} +21 -190
  96. package/dist/shared/@ai-setting/{roy-agent-core-ne2t1pay.js → roy-agent-core-f8sp1txg.js} +2 -2
  97. package/dist/shared/@ai-setting/{roy-agent-core-ak4dc3kg.js → roy-agent-core-gn8f4rhs.js} +1 -1
  98. package/dist/shared/@ai-setting/{roy-agent-core-qcspfszy.js → roy-agent-core-gngjkw3b.js} +1 -1
  99. package/dist/shared/@ai-setting/{roy-agent-core-9jzysq50.js → roy-agent-core-heft3j4c.js} +2 -2
  100. package/dist/shared/@ai-setting/{roy-agent-core-5apmk4qw.js → roy-agent-core-jszgaevt.js} +1 -1
  101. package/dist/shared/@ai-setting/{roy-agent-core-nde5gzta.js → roy-agent-core-m8n0dffe.js} +1 -1
  102. package/dist/shared/@ai-setting/{roy-agent-core-x8n1r7h4.js → roy-agent-core-n3b7ztms.js} +189 -8
  103. package/dist/shared/@ai-setting/{roy-agent-core-4vpk40ss.js → roy-agent-core-nhk0dsxr.js} +13 -13
  104. package/dist/shared/@ai-setting/{roy-agent-core-j8e92gj8.js → roy-agent-core-nntphgww.js} +1 -60
  105. package/dist/shared/@ai-setting/{roy-agent-core-8s9jd2qy.js → roy-agent-core-nra8vfrs.js} +1 -1
  106. package/dist/shared/@ai-setting/{roy-agent-core-pk1b3kvf.js → roy-agent-core-ns3pbyz4.js} +1 -1
  107. package/dist/shared/@ai-setting/{roy-agent-core-7g03zkkb.js → roy-agent-core-pemxr5n4.js} +1 -1
  108. package/dist/shared/@ai-setting/{roy-agent-core-skzjs973.js → roy-agent-core-pjxa78mp.js} +5 -5
  109. package/dist/shared/@ai-setting/{roy-agent-core-p8ak03s0.js → roy-agent-core-q7zksbw0.js} +117 -315
  110. package/dist/shared/@ai-setting/{roy-agent-core-zd3ddm4k.js → roy-agent-core-qjjf4tjb.js} +1 -1
  111. package/dist/shared/@ai-setting/{roy-agent-core-qamktze3.js → roy-agent-core-qyqnmz8c.js} +1 -1
  112. package/dist/shared/@ai-setting/{roy-agent-core-9csa89jx.js → roy-agent-core-r9qe0ghe.js} +2 -2
  113. package/dist/shared/@ai-setting/{roy-agent-core-h93v6p6y.js → roy-agent-core-tc7gw38m.js} +2 -2
  114. package/dist/shared/@ai-setting/{roy-agent-core-35s1w7tc.js → roy-agent-core-v2188rnk.js} +157 -85
  115. package/dist/shared/@ai-setting/{roy-agent-core-p2r27era.js → roy-agent-core-vmg30n5x.js} +8 -8
  116. package/dist/shared/@ai-setting/{roy-agent-core-rnwr39b0.js → roy-agent-core-w7hnjhvx.js} +5 -3
  117. package/dist/shared/@ai-setting/{roy-agent-core-dv714bqh.js → roy-agent-core-wafk25ff.js} +1 -1
  118. package/dist/shared/@ai-setting/{roy-agent-core-brwzs8wf.js → roy-agent-core-xcq04fq0.js} +5 -5
  119. package/dist/shared/@ai-setting/{roy-agent-core-2gay3sjt.js → roy-agent-core-yg247mk4.js} +1 -1
  120. package/dist/shared/@ai-setting/{roy-agent-core-zy3hqfwg.js → roy-agent-core-yv9x4wmg.js} +631 -35
  121. package/dist/shared/@ai-setting/{roy-agent-core-yhsssn86.js → roy-agent-core-zmeka63k.js} +1 -1
  122. package/dist/test-utils/child-process-mock.d.ts +73 -0
  123. package/package.json +2 -2
  124. package/dist/shared/@ai-setting/roy-agent-core-dsevjbck.js +0 -245
@@ -1,8 +1,19 @@
1
+ import {
2
+ sniffImageMime
3
+ } from "./roy-agent-core-zjdzk1gg.js";
4
+ import {
5
+ TracedAs,
6
+ embedParamFilter,
7
+ embedResultFilter,
8
+ init_decorator,
9
+ init_trace_filters
10
+ } from "./roy-agent-core-b599jgyd.js";
1
11
  import {
2
12
  createLogger,
3
13
  init_logger
4
14
  } from "./roy-agent-core-8seq65bp.js";
5
15
  import {
16
+ __legacyDecorateClassTS,
6
17
  __require
7
18
  } from "./roy-agent-core-fs0mn2jk.js";
8
19
 
@@ -59,13 +70,15 @@ function buildOpencodeHeaders(providerId, conversationId, baseURL) {
59
70
  return { "x-opencode-session": getOrCreateOpencodeSessionId(conversationId) };
60
71
  }
61
72
 
62
- // src/env/llm/invoke.ts
63
- import { randomUUID } from "crypto";
64
- import { streamText, jsonSchema } from "ai";
65
- import { createOpenAI } from "@ai-sdk/openai";
66
- import { createAnthropic } from "@ai-sdk/anthropic";
67
- import { createGoogleGenerativeAI } from "@ai-sdk/google";
68
- import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
73
+ // src/env/llm/adapter-pi-ai.ts
74
+ init_decorator();
75
+ init_trace_filters();
76
+ init_logger();
77
+ import {
78
+ complete,
79
+ stream as piStream,
80
+ getModel
81
+ } from "@earendil-works/pi-ai";
69
82
 
70
83
  // src/env/llm/tool-schema.ts
71
84
  import { zodToJsonSchema } from "zod-to-json-schema";
@@ -152,12 +165,479 @@ function toolParametersToJsonSchema(parameters) {
152
165
  return deref;
153
166
  }
154
167
 
168
+ // src/env/llm/reasoning-defense.ts
169
+ var DEEPSEEK_PROVIDER_PREFIX = "deepseek";
170
+ var DEEPSEEK_MODEL_MARKER = "deepseek";
171
+ function shouldInjectReasoningContent(provider, modelId) {
172
+ const p = (provider ?? "").toLowerCase();
173
+ const m = (modelId ?? "").toLowerCase();
174
+ if (p === DEEPSEEK_PROVIDER_PREFIX || p.startsWith(`${DEEPSEEK_PROVIDER_PREFIX}-`)) {
175
+ return true;
176
+ }
177
+ return m.includes(DEEPSEEK_MODEL_MARKER);
178
+ }
179
+ function injectReasoningContent(messages) {
180
+ return messages.map((msg) => {
181
+ if (msg?.role !== "assistant")
182
+ return msg;
183
+ if ("reasoning_content" in msg)
184
+ return msg;
185
+ return { ...msg, reasoning_content: "" };
186
+ });
187
+ }
188
+ function applyReasoningDefense(payload, target) {
189
+ if (!payload || typeof payload !== "object")
190
+ return payload;
191
+ if (!shouldInjectReasoningContent(target.provider, target.modelId))
192
+ return payload;
193
+ const messages = payload.messages;
194
+ if (!Array.isArray(messages))
195
+ return payload;
196
+ return { ...payload, messages: injectReasoningContent(messages) };
197
+ }
198
+ function createReasoningDefenseHook(target) {
199
+ return (payload) => applyReasoningDefense(payload, target);
200
+ }
201
+
202
+ // src/env/llm/adapter-pi-ai.ts
203
+ var logger = createLogger("llm:adapter-pi-ai");
204
+ var KNOWN_PROVIDER_APIS = {
205
+ anthropic: {
206
+ api: "anthropic-messages",
207
+ apiProtocol: "anthropic-messages",
208
+ contextLimit: 200000,
209
+ maxTokensLimit: 8192
210
+ },
211
+ openai: {
212
+ api: "openai-responses",
213
+ apiProtocol: "openai-responses",
214
+ contextLimit: 128000,
215
+ maxTokensLimit: 16384
216
+ },
217
+ google: {
218
+ api: "google-generative-ai",
219
+ apiProtocol: "google-generative-ai",
220
+ contextLimit: 1e6,
221
+ maxTokensLimit: 8192
222
+ },
223
+ "google-vertex": {
224
+ api: "google-vertex",
225
+ apiProtocol: "google-vertex",
226
+ contextLimit: 1e6,
227
+ maxTokensLimit: 8192
228
+ },
229
+ deepseek: {
230
+ api: "openai-completions",
231
+ apiProtocol: "openai-completions",
232
+ contextLimit: 64000,
233
+ maxTokensLimit: 8192
234
+ },
235
+ glm: {
236
+ api: "openai-completions",
237
+ apiProtocol: "openai-completions",
238
+ contextLimit: 128000,
239
+ maxTokensLimit: 8192
240
+ },
241
+ xai: {
242
+ api: "openai-completions",
243
+ apiProtocol: "openai-completions",
244
+ contextLimit: 131072,
245
+ maxTokensLimit: 8192
246
+ },
247
+ groq: {
248
+ api: "openai-completions",
249
+ apiProtocol: "openai-completions",
250
+ contextLimit: 32768,
251
+ maxTokensLimit: 8192
252
+ },
253
+ minimax: {
254
+ api: "anthropic-messages",
255
+ apiProtocol: "anthropic-messages",
256
+ contextLimit: 128000,
257
+ maxTokensLimit: 8192
258
+ },
259
+ "minimax-cn": {
260
+ api: "anthropic-messages",
261
+ apiProtocol: "anthropic-messages",
262
+ contextLimit: 128000,
263
+ maxTokensLimit: 8192
264
+ },
265
+ moonshotai: {
266
+ api: "openai-completions",
267
+ apiProtocol: "openai-completions",
268
+ contextLimit: 128000,
269
+ maxTokensLimit: 8192
270
+ },
271
+ "kimi-coding": {
272
+ api: "openai-completions",
273
+ apiProtocol: "openai-completions",
274
+ contextLimit: 128000,
275
+ maxTokensLimit: 8192
276
+ }
277
+ };
278
+ var PROVIDER_ENDPOINT_APIS = {
279
+ minimax: [
280
+ { pathIncludes: "/anthropic", apiProtocol: "anthropic-messages" },
281
+ { pathIncludes: "/v1", apiProtocol: "openai-completions" }
282
+ ],
283
+ "minimax-cn": [
284
+ { pathIncludes: "/anthropic", apiProtocol: "anthropic-messages" },
285
+ { pathIncludes: "/v1", apiProtocol: "openai-completions" }
286
+ ]
287
+ };
288
+ var ENDPOINT_RULES_SORTED = Object.fromEntries(Object.entries(PROVIDER_ENDPOINT_APIS).map(([provider, rules]) => [
289
+ provider,
290
+ [...rules].sort((a, b) => b.pathIncludes.length - a.pathIncludes.length)
291
+ ]));
292
+ var PROVIDER_API_OVERRIDES = {
293
+ "minimax-responses": "openai-responses",
294
+ "minimax-openai": "openai-completions"
295
+ };
296
+ function resolveApiProtocol(provider, baseURL, explicitProtocol) {
297
+ if (explicitProtocol)
298
+ return explicitProtocol;
299
+ if (PROVIDER_API_OVERRIDES[provider])
300
+ return PROVIDER_API_OVERRIDES[provider];
301
+ const endpointRules = ENDPOINT_RULES_SORTED[provider];
302
+ if (endpointRules) {
303
+ for (const rule of endpointRules) {
304
+ if (baseURL?.includes(rule.pathIncludes))
305
+ return rule.apiProtocol;
306
+ }
307
+ }
308
+ const declared = KNOWN_PROVIDER_APIS[provider]?.apiProtocol;
309
+ if (declared)
310
+ return declared;
311
+ if (baseURL?.includes("/responses"))
312
+ return "openai-responses";
313
+ if (baseURL?.includes("anthropic")) {
314
+ logger.warn(`[adapter-pi-ai] provider "${provider}" 的协议靠 baseURL 含 "anthropic" 推断为 anthropic-messages;` + `建议在 KNOWN_PROVIDER_APIS 或调用处显式声明 apiProtocol(Task #4383 P1)`, { provider, inferred_api_protocol: "anthropic-messages", base_url: baseURL });
315
+ return "anthropic-messages";
316
+ }
317
+ return KNOWN_PROVIDER_APIS[provider]?.api || "openai-completions";
318
+ }
319
+ var REASONING_COMPAT_PIN = {
320
+ supportsDeveloperRole: false,
321
+ thinkingFormat: "openai",
322
+ supportsReasoningEffort: false
323
+ };
324
+ var REASONING_SAFE_PROTOCOLS = new Set([
325
+ "openai-completions",
326
+ "anthropic-messages"
327
+ ]);
328
+ var warnedReasoningRefusals = new Set;
329
+ function resolveModelReasoning(provider, modelId, capabilities, apiProtocol) {
330
+ const requested = capabilities?.reasoning === true;
331
+ if (!requested)
332
+ return false;
333
+ if (!apiProtocol || !REASONING_SAFE_PROTOCOLS.has(apiProtocol)) {
334
+ const key = `${provider}:${apiProtocol ?? "<unresolved>"}`;
335
+ if (!warnedReasoningRefusals.has(key)) {
336
+ warnedReasoningRefusals.add(key);
337
+ logger.warn(`[adapter-pi-ai] provider "${provider}" (${apiProtocol ?? "unresolved"}) 的 capabilities.reasoning=true 被忽略:` + `该协议无法通过 compat pin 保持请求体字节一致,打开会破坏 prompt cache 前缀(Task #4403)`, { provider, model_id: modelId, api_protocol: apiProtocol });
338
+ }
339
+ return false;
340
+ }
341
+ return true;
342
+ }
343
+ function buildPiCacheOptions(args) {
344
+ const out = {};
345
+ if (args.sessionId)
346
+ out.sessionId = args.sessionId;
347
+ if (args.apiProtocol === "openai-completions") {
348
+ out.cacheRetention = args.cacheRetention ?? "long";
349
+ } else if (args.cacheRetention) {
350
+ out.cacheRetention = args.cacheRetention;
351
+ }
352
+ return out;
353
+ }
354
+ function resolvePiModel(provider, modelId, baseURL, capabilities) {
355
+ const builtIn = getModel(provider, modelId);
356
+ if (builtIn)
357
+ return baseURL ? { ...builtIn, baseUrl: baseURL } : builtIn;
358
+ const configuredApi = resolveApiProtocol(provider, baseURL);
359
+ const reasoning = resolveModelReasoning(provider, modelId, capabilities, configuredApi);
360
+ return {
361
+ id: modelId,
362
+ name: modelId,
363
+ api: configuredApi,
364
+ provider,
365
+ baseUrl: baseURL || "",
366
+ reasoning,
367
+ ...reasoning ? { compat: { ...REASONING_COMPAT_PIN } } : {},
368
+ input: ["text", "image"],
369
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
370
+ contextWindow: KNOWN_PROVIDER_APIS[provider]?.contextLimit || 128000,
371
+ maxTokens: KNOWN_PROVIDER_APIS[provider]?.maxTokensLimit || 8192
372
+ };
373
+ }
374
+ function toPiMessages(messages) {
375
+ const out = [];
376
+ const ts = Date.now();
377
+ for (const m of messages) {
378
+ if (m.role === "system")
379
+ continue;
380
+ if (m.role === "user") {
381
+ if (typeof m.content === "string") {
382
+ out.push({ role: "user", content: m.content, timestamp: ts });
383
+ } else {
384
+ out.push({ role: "user", content: m.content.flatMap((c) => {
385
+ if (c.type === "text")
386
+ return [{ type: "text", text: c.text }];
387
+ if (c.type === "image")
388
+ return [{ type: "image", data: c.image instanceof Uint8Array ? Buffer.from(c.image).toString("base64") : c.image, mimeType: sniffImageMime(c.image, c.mediaType) }];
389
+ return [{ type: "text", text: `[file:${c.mediaType}] ${typeof c.file === "string" ? c.file : Buffer.from(c.file).toString("base64")}` }];
390
+ }), timestamp: ts });
391
+ }
392
+ continue;
393
+ }
394
+ if (m.role === "tool") {
395
+ out.push({ role: "toolResult", toolCallId: m.toolCallId || "", toolName: m.name || "", content: [{ type: "text", text: typeof m.content === "string" ? m.content : JSON.stringify(m.content) }], isError: false, timestamp: ts });
396
+ continue;
397
+ }
398
+ const content = [];
399
+ if (typeof m.content === "string" && m.content)
400
+ content.push({ type: "text", text: m.content });
401
+ else if (Array.isArray(m.content))
402
+ for (const c of m.content) {
403
+ if (c.type === "text")
404
+ content.push({ type: "text", text: c.text });
405
+ else if (c.type === "image")
406
+ content.push({ type: "image", data: c.image instanceof Uint8Array ? Buffer.from(c.image).toString("base64") : c.image, mimeType: sniffImageMime(c.image, c.mediaType) });
407
+ else
408
+ content.push({ type: "text", text: `[file:${c.mediaType}] ${typeof c.file === "string" ? c.file : Buffer.from(c.file).toString("base64")}` });
409
+ }
410
+ for (const tc of m.toolCalls || [])
411
+ content.push({ type: "toolCall", id: tc.id, name: tc.name, arguments: safeJson(tc.arguments) });
412
+ out.push({ role: "assistant", content, api: "openai-completions", model: "", provider: "", usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, totalTokens: 0, cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 } }, stopReason: "stop", timestamp: ts });
413
+ }
414
+ return out;
415
+ }
416
+ function extractSystemPrompt(messages) {
417
+ const prompts = messages.filter((m) => m.role === "system").map((m) => typeof m.content === "string" ? m.content : m.content.filter((c) => c.type === "text").map((c) => c.text).join(""));
418
+ return prompts.length ? prompts.join(`
419
+
420
+ `) : undefined;
421
+ }
422
+ function safeJson(s) {
423
+ try {
424
+ return JSON.parse(s);
425
+ } catch (e) {
426
+ logger.warn(`[safeJson] JSON.parse failed`, {
427
+ parse_failed: true,
428
+ input_length: s.length,
429
+ error: e.message
430
+ });
431
+ return {};
432
+ }
433
+ }
434
+ function convertToolParameters(parameters) {
435
+ return toolParametersToJsonSchema(parameters);
436
+ }
437
+ function toPiTools(tools) {
438
+ if (!tools)
439
+ return;
440
+ return tools.map((t) => ({
441
+ name: t.name,
442
+ description: t.description || "",
443
+ parameters: convertToolParameters(t.parameters)
444
+ }));
445
+ }
446
+ function piRequestExtras(req) {
447
+ const headers = buildOpencodeHeaders(req.provider, req.sessionId, req.baseURL);
448
+ return Object.keys(headers).length > 0 ? { headers } : {};
449
+ }
450
+ function fromAssistantMessage(msg) {
451
+ let text = "";
452
+ const toolCalls = [];
453
+ for (const block of msg.content) {
454
+ const b = block;
455
+ if (b.type === "text") {
456
+ text += b.text || "";
457
+ } else if (b.type === "toolCall") {
458
+ toolCalls.push({
459
+ id: b.id || "",
460
+ name: b.name || "",
461
+ arguments: typeof b.arguments === "string" ? b.arguments : JSON.stringify(b.arguments ?? {})
462
+ });
463
+ }
464
+ }
465
+ return {
466
+ text,
467
+ finishReason: msg.stopReason || "stop",
468
+ toolCalls: toolCalls.length ? toolCalls : undefined,
469
+ usage: {
470
+ promptTokens: msg.usage?.input ?? 0,
471
+ completionTokens: msg.usage?.output ?? 0,
472
+ totalTokens: msg.usage?.totalTokens ?? 0,
473
+ cacheRead: msg.usage?.cacheRead,
474
+ cacheWrite: msg.usage?.cacheWrite
475
+ },
476
+ raw: msg
477
+ };
478
+ }
479
+
480
+ class EmbeddingNotSupportedError extends Error {
481
+ constructor(adapter) {
482
+ super(`Embedding is not supported by ${adapter}; use AiSdkAdapter.embed() or apply at higher layer.`);
483
+ this.name = "EmbeddingNotSupportedError";
484
+ }
485
+ }
486
+
487
+ class PiAiAdapter {
488
+ name = "pi-ai";
489
+ async chat(req) {
490
+ const model = resolvePiModel(req.provider, req.modelId, req.baseURL, req.capabilities);
491
+ const ctx = {
492
+ systemPrompt: [req.systemPrompt, extractSystemPrompt(req.messages)].filter(Boolean).join(`
493
+
494
+ `) || undefined,
495
+ messages: toPiMessages(req.messages),
496
+ tools: toPiTools(req.tools)
497
+ };
498
+ const msg = await complete(model, ctx, {
499
+ apiKey: req.apiKey,
500
+ baseURL: req.baseURL,
501
+ temperature: req.temperature,
502
+ maxTokens: req.maxTokens,
503
+ signal: req.signal,
504
+ ...buildPiCacheOptions({
505
+ apiProtocol: model.api,
506
+ sessionId: req.sessionId,
507
+ cacheRetention: req.cacheRetention
508
+ }),
509
+ onPayload: createReasoningDefenseHook({
510
+ provider: req.provider,
511
+ modelId: req.modelId
512
+ }),
513
+ ...piRequestExtras(req)
514
+ });
515
+ return fromAssistantMessage(msg);
516
+ }
517
+ async stream(req) {
518
+ const model = resolvePiModel(req.provider, req.modelId, req.baseURL, req.capabilities);
519
+ const ctx = {
520
+ systemPrompt: [req.systemPrompt, extractSystemPrompt(req.messages)].filter(Boolean).join(`
521
+
522
+ `) || undefined,
523
+ messages: toPiMessages(req.messages),
524
+ tools: toPiTools(req.tools)
525
+ };
526
+ const eventStream = piStream(model, ctx, {
527
+ apiKey: req.apiKey,
528
+ baseURL: req.baseURL,
529
+ temperature: req.temperature,
530
+ maxTokens: req.maxTokens,
531
+ signal: req.signal,
532
+ ...buildPiCacheOptions({
533
+ apiProtocol: model.api,
534
+ sessionId: req.sessionId,
535
+ cacheRetention: req.cacheRetention
536
+ }),
537
+ onPayload: createReasoningDefenseHook({
538
+ provider: req.provider,
539
+ modelId: req.modelId
540
+ }),
541
+ ...piRequestExtras(req)
542
+ });
543
+ return { events: eventStream, result: async () => fromAssistantMessage(await eventStream.result()) };
544
+ }
545
+ async embed(_req) {
546
+ throw new EmbeddingNotSupportedError(this.name);
547
+ }
548
+ async resolveProvider(provider, modelId) {
549
+ const model = resolvePiModel(provider, modelId);
550
+ const caps = KNOWN_PROVIDER_APIS[provider] || {
551
+ api: model.api,
552
+ contextLimit: model.contextWindow,
553
+ maxTokensLimit: model.maxTokens
554
+ };
555
+ return {
556
+ api: model.api,
557
+ provider,
558
+ modelId,
559
+ contextLimit: caps.contextLimit,
560
+ maxTokensLimit: caps.maxTokensLimit
561
+ };
562
+ }
563
+ }
564
+ __legacyDecorateClassTS([
565
+ TracedAs("llm.adapter.chat", {
566
+ recordParams: true,
567
+ recordResult: true,
568
+ log: true,
569
+ paramFilter: (args) => {
570
+ const req = args[0];
571
+ return {
572
+ provider: req?.provider,
573
+ model_id: req?.modelId,
574
+ messages_count: req?.messages?.length,
575
+ tools_count: req?.tools?.length,
576
+ temperature: req?.temperature,
577
+ max_tokens: req?.maxTokens
578
+ };
579
+ },
580
+ resultFilter: (r) => ({
581
+ finish_reason: r?.finishReason,
582
+ usage_input: r?.usage?.promptTokens,
583
+ usage_output: r?.usage?.completionTokens,
584
+ usage_total: r?.usage?.totalTokens,
585
+ content_length: r?.text?.length
586
+ })
587
+ })
588
+ ], PiAiAdapter.prototype, "chat", null);
589
+ __legacyDecorateClassTS([
590
+ TracedAs("llm.adapter.stream", {
591
+ recordParams: true,
592
+ recordResult: false,
593
+ log: true,
594
+ paramFilter: (args) => {
595
+ const req = args[0];
596
+ return {
597
+ provider: req?.provider,
598
+ model_id: req?.modelId,
599
+ messages_count: req?.messages?.length
600
+ };
601
+ }
602
+ })
603
+ ], PiAiAdapter.prototype, "stream", null);
604
+ __legacyDecorateClassTS([
605
+ TracedAs("llm.adapter.embed", {
606
+ paramFilter: embedParamFilter,
607
+ resultFilter: embedResultFilter,
608
+ recordResult: false,
609
+ log: true
610
+ })
611
+ ], PiAiAdapter.prototype, "embed", null);
612
+ __legacyDecorateClassTS([
613
+ TracedAs("llm.adapter.resolve_provider", {
614
+ recordParams: true,
615
+ recordResult: true,
616
+ log: true,
617
+ paramFilter: (args) => ({
618
+ provider: args[0],
619
+ model_id: args[1]
620
+ }),
621
+ resultFilter: (r) => ({
622
+ api: r?.api,
623
+ context_limit: r?.contextLimit,
624
+ max_tokens_limit: r?.maxTokensLimit
625
+ })
626
+ })
627
+ ], PiAiAdapter.prototype, "resolveProvider", null);
628
+
155
629
  // src/env/llm/invoke.ts
630
+ import { randomUUID } from "crypto";
631
+ import { streamText, jsonSchema } from "ai";
632
+ import { createOpenAI } from "@ai-sdk/openai";
633
+ import { createAnthropic } from "@ai-sdk/anthropic";
634
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
635
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
156
636
  init_logger();
157
637
 
158
638
  // src/env/llm/tool-args-parser.ts
159
639
  init_logger();
160
- var logger = createLogger("llm:tool-args-parser");
640
+ var logger2 = createLogger("llm:tool-args-parser");
161
641
  var ARG_KEY_RE = /<arg_key>([\s\S]*?)<\/arg_key>\s*<arg_value>([\s\S]*?)<\/arg_value>/g;
162
642
  function salvageTextualToolArgs(raw) {
163
643
  if (!raw.includes("<arg_key>"))
@@ -201,7 +681,7 @@ function parseToolArgsStrict(args) {
201
681
  const direct = tryParseObject(raw);
202
682
  if (direct.ok) {
203
683
  if (raw.includes("<arg_key>") || raw.includes("<arg_value>") || raw.includes("<tool_call>")) {
204
- logger.warn("[parseToolArgsStrict] arguments 里出现上游文本工具调用标记,已清洗值中的 marker");
684
+ logger2.warn("[parseToolArgsStrict] arguments 里出现上游文本工具调用标记,已清洗值中的 marker");
205
685
  return { ok: true, args: sanitizeArgValues(direct.args), salvaged: true };
206
686
  }
207
687
  return { ok: true, args: direct.args };
@@ -210,12 +690,12 @@ function parseToolArgsStrict(args) {
210
690
  const stripped = stripTextualToolArgsMarkers(raw);
211
691
  const afterStrip = tryParseObject(stripped);
212
692
  if (afterStrip.ok) {
213
- logger.warn("[parseToolArgsStrict] 上游把文本工具调用标记混进了 arguments,已剥离 marker 后恢复");
693
+ logger2.warn("[parseToolArgsStrict] 上游把文本工具调用标记混进了 arguments,已剥离 marker 后恢复");
214
694
  return { ok: true, args: afterStrip.args, salvaged: true };
215
695
  }
216
696
  const salvaged = salvageTextualToolArgs(raw);
217
697
  if (salvaged) {
218
- logger.warn("[parseToolArgsStrict] 上游输出的是文本工具调用格式,已按 <arg_key>/<arg_value> 重建参数", { keys: Object.keys(salvaged).join(",") });
698
+ logger2.warn("[parseToolArgsStrict] 上游输出的是文本工具调用格式,已按 <arg_key>/<arg_value> 重建参数", { keys: Object.keys(salvaged).join(",") });
219
699
  return { ok: true, args: salvaged, salvaged: true };
220
700
  }
221
701
  }
@@ -269,33 +749,33 @@ function tryParseObject(raw) {
269
749
  var MAX_SAFE_DEPTH = 5;
270
750
  function safeParseToolArgs(args, depth = 0) {
271
751
  if (depth >= MAX_SAFE_DEPTH) {
272
- logger.warn(`[safeParseToolArgs] Max recursion depth (${MAX_SAFE_DEPTH}) exceeded at depth ${depth}. ` + "Input may be malicious or abnormally deeply nested. Returning empty object.", { depth, argsType: typeof args });
752
+ logger2.warn(`[safeParseToolArgs] Max recursion depth (${MAX_SAFE_DEPTH}) exceeded at depth ${depth}. ` + "Input may be malicious or abnormally deeply nested. Returning empty object.", { depth, argsType: typeof args });
273
753
  return {};
274
754
  }
275
755
  if (typeof args === "object" && args !== null && !Array.isArray(args)) {
276
756
  return args;
277
757
  }
278
758
  if (Array.isArray(args)) {
279
- logger.debug(`[safeParseToolArgs] Input is an array. Tool arguments should be objects. Returning empty object.`, { depth, arrayLength: args.length });
759
+ logger2.debug(`[safeParseToolArgs] Input is an array. Tool arguments should be objects. Returning empty object.`, { depth, arrayLength: args.length });
280
760
  return {};
281
761
  }
282
762
  if (typeof args === "string") {
283
763
  try {
284
764
  const parsed = JSON.parse(args);
285
765
  if (typeof parsed === "string") {
286
- logger.debug(`[safeParseToolArgs] Detected double/multi-stringified JSON at depth ${depth}. ` + "LLM may be double-stringifying tool arguments. Parsing recursively.", { depth, parsedLength: parsed.length });
766
+ logger2.debug(`[safeParseToolArgs] Detected double/multi-stringified JSON at depth ${depth}. ` + "LLM may be double-stringifying tool arguments. Parsing recursively.", { depth, parsedLength: parsed.length });
287
767
  return safeParseToolArgs(parsed, depth + 1);
288
768
  }
289
769
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
290
770
  return parsed;
291
771
  }
292
772
  if (Array.isArray(parsed)) {
293
- logger.debug(`[safeParseToolArgs] Parsed result is an array at depth ${depth}. ` + "Tool arguments should be objects, not arrays. Returning empty object.", { depth, parsedLength: parsed.length });
773
+ logger2.debug(`[safeParseToolArgs] Parsed result is an array at depth ${depth}. ` + "Tool arguments should be objects, not arrays. Returning empty object.", { depth, parsedLength: parsed.length });
294
774
  return {};
295
775
  }
296
776
  return { value: parsed };
297
777
  } catch (e) {
298
- logger.warn(`[safeParseToolArgs] JSON.parse failed at depth ${depth}`, {
778
+ logger2.warn(`[safeParseToolArgs] JSON.parse failed at depth ${depth}`, {
299
779
  parse_failed: true,
300
780
  input_length: args.length,
301
781
  depth,
@@ -366,8 +846,98 @@ function canonicalizeToolCallArgsInPlace(value) {
366
846
  }
367
847
  }
368
848
  }
849
+
850
+ // src/env/llm/outbound-defense.ts
851
+ var CONVERSATION_LIST_KEYS = ["messages", "input"];
852
+ function findConversationList(body, wireProtocol) {
853
+ if (wireProtocol === "openai-responses") {
854
+ return Array.isArray(body.input) ? { key: "input", list: body.input } : null;
855
+ }
856
+ if (wireProtocol === "openai-chat" || wireProtocol === "anthropic") {
857
+ return Array.isArray(body.messages) ? { key: "messages", list: body.messages } : null;
858
+ }
859
+ for (const key of CONVERSATION_LIST_KEYS) {
860
+ if (Array.isArray(body[key])) {
861
+ return { key, list: body[key] };
862
+ }
863
+ }
864
+ return null;
865
+ }
866
+ function protocolSupportsCacheKeys(wireProtocol) {
867
+ return wireProtocol === undefined || wireProtocol === "openai-chat" || wireProtocol === "openai-responses";
868
+ }
869
+ function protocolSupportsReasoningField(wireProtocol) {
870
+ return wireProtocol === undefined || wireProtocol === "openai-chat" || wireProtocol === "openai-responses";
871
+ }
872
+ function applyOutboundDefense(body, target) {
873
+ let next = null;
874
+ const writable = () => {
875
+ if (!next)
876
+ next = { ...body };
877
+ return next;
878
+ };
879
+ if (protocolSupportsReasoningField(target.wireProtocol) && shouldInjectReasoningContent(target.provider, target.modelId)) {
880
+ const found = findConversationList(body, target.wireProtocol);
881
+ if (found) {
882
+ const injected = injectReasoningContent(found.list);
883
+ const changed = injected.some((m, i) => m !== found.list[i]);
884
+ if (changed)
885
+ writable()[found.key] = injected;
886
+ }
887
+ }
888
+ if (protocolSupportsCacheKeys(target.wireProtocol) && target.sessionId) {
889
+ const retention = target.cacheRetention ?? "long";
890
+ if (retention !== "none") {
891
+ if (body.prompt_cache_key === undefined) {
892
+ writable().prompt_cache_key = clampOpenAIPromptCacheKey(target.sessionId);
893
+ }
894
+ if (retention === "long" && body.prompt_cache_retention === undefined) {
895
+ writable().prompt_cache_retention = "24h";
896
+ }
897
+ }
898
+ }
899
+ return next ?? body;
900
+ }
901
+ function createOutboundDefenseFetch(target, inner = (...args) => globalThis.fetch(...args)) {
902
+ return async (input, init) => {
903
+ if (!init || typeof init.body !== "string" || init.body.length === 0) {
904
+ return inner(input, init);
905
+ }
906
+ let parsed;
907
+ try {
908
+ parsed = JSON.parse(init.body);
909
+ } catch {
910
+ return inner(input, init);
911
+ }
912
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
913
+ return inner(input, init);
914
+ }
915
+ let patched;
916
+ try {
917
+ patched = applyOutboundDefense(parsed, target);
918
+ } catch {
919
+ return inner(input, init);
920
+ }
921
+ if (patched === parsed) {
922
+ return inner(input, init);
923
+ }
924
+ return inner(input, { ...init, body: JSON.stringify(patched) });
925
+ };
926
+ }
927
+ function wireProtocolFromApiProtocol(apiProtocol) {
928
+ switch (apiProtocol) {
929
+ case "openai-responses":
930
+ return "openai-responses";
931
+ case "anthropic-messages":
932
+ return "anthropic";
933
+ case "openai-completions":
934
+ return "openai-chat";
935
+ default:
936
+ return "openai-chat";
937
+ }
938
+ }
369
939
  // src/env/llm/invoke.ts
370
- var logger2 = createLogger("llm:invoke");
940
+ var logger3 = createLogger("llm:invoke");
371
941
  var MAX_RETRIES = 3;
372
942
  var DEFAULT_TIMEOUT = 60000;
373
943
 
@@ -587,7 +1157,7 @@ function convertToSDKMessages(messages, options) {
587
1157
  }
588
1158
  if (msg.role === "tool") {
589
1159
  if (!msg.toolCallId) {
590
- logger2.warn("Tool message missing toolCallId", { msg });
1160
+ logger3.warn("Tool message missing toolCallId", { msg });
591
1161
  }
592
1162
  let outputValue = "";
593
1163
  const content = msg.content;
@@ -675,7 +1245,7 @@ function convertToolChoice(toolChoice) {
675
1245
  }
676
1246
  function createEnvEventEmitter(env, context) {
677
1247
  if (!env || typeof env.pushEnvEvent !== "function") {
678
- logger2.warn("[invoke] createEnvEventEmitter: env is null/undefined or pushEnvEvent is unavailable, streaming events will be disabled");
1248
+ logger3.warn("[invoke] createEnvEventEmitter: env is null/undefined or pushEnvEvent is unavailable, streaming events will be disabled");
679
1249
  return null;
680
1250
  }
681
1251
  return (event) => {
@@ -693,7 +1263,7 @@ function createEnvEventEmitter(env, context) {
693
1263
  payload: event
694
1264
  });
695
1265
  } catch (err) {
696
- logger2.warn("Failed to push env event", { error: String(err), eventType: event.type });
1266
+ logger3.warn("Failed to push env event", { error: String(err), eventType: event.type });
697
1267
  }
698
1268
  };
699
1269
  }
@@ -776,12 +1346,12 @@ function processThinkingStream(textDelta, config, state) {
776
1346
  async function invoke(config, options, ctx) {
777
1347
  try {
778
1348
  const emitToEnv = createEnvEventEmitter(options.env, options.context);
779
- logger2.info("[invoke] Created event emitter", {
1349
+ logger3.info("[invoke] Created event emitter", {
780
1350
  envAvailable: !!options.env,
781
1351
  hasContext: options.context !== undefined
782
1352
  });
783
1353
  const { providerId, modelId } = parseModelString(options.model || config.model);
784
- const provider = createProviderInstance(providerId, config.apiKey, config.baseURL, options.context?.sessionId);
1354
+ const provider = createProviderInstance(providerId, config.apiKey, config.baseURL, options.context?.sessionId, options.cacheRetention, modelId);
785
1355
  if (!provider) {
786
1356
  throw new Error(`Failed to create provider for ${providerId}`);
787
1357
  }
@@ -815,7 +1385,7 @@ async function invoke(config, options, ctx) {
815
1385
  const missingToolResults = assistantToolCalls.filter((tc) => !toolResultIds.includes(tc.id));
816
1386
  const orphanedToolResults = toolResultIds.filter((id) => !toolCallIds.has(id));
817
1387
  if (assistantToolCalls.length > 0 || toolResultIds.length > 0) {
818
- logger2.debug("[invoke] ToolCallId matching analysis:", {
1388
+ logger3.debug("[invoke] ToolCallId matching analysis:", {
819
1389
  assistantToolCalls,
820
1390
  toolResultIds,
821
1391
  missingToolResults: missingToolResults.length > 0 ? missingToolResults : "none",
@@ -829,10 +1399,10 @@ async function invoke(config, options, ctx) {
829
1399
  });
830
1400
  const model = `${providerId}/${modelId}`;
831
1401
  if (emitToEnv) {
832
- logger2.info("[invoke] Emitting llm.start event");
1402
+ logger3.info("[invoke] Emitting llm.start event");
833
1403
  emitToEnv({ type: "start", metadata: { model } });
834
1404
  } else {
835
- logger2.warn("[invoke] emitToEnv is null, skipping llm.start event");
1405
+ logger3.warn("[invoke] emitToEnv is null, skipping llm.start event");
836
1406
  }
837
1407
  const streamTextOptions = {
838
1408
  model: provider.languageModel(modelId),
@@ -954,7 +1524,7 @@ async function invoke(config, options, ctx) {
954
1524
  `).filter(Boolean);
955
1525
  const uniqueLines = new Set(outputLines);
956
1526
  if (outputLines.length !== uniqueLines.size) {
957
- logger2.warn("[DEBUG_DUPLICATE] outputContent has duplicate lines", {
1527
+ logger3.warn("[DEBUG_DUPLICATE] outputContent has duplicate lines", {
958
1528
  fullContent,
959
1529
  rawFullContent,
960
1530
  outputContent,
@@ -962,7 +1532,7 @@ async function invoke(config, options, ctx) {
962
1532
  textDeltas: textDeltaLog
963
1533
  });
964
1534
  } else {
965
- logger2.info("[DEBUG_DUPLICATE] outputContent OK", {
1535
+ logger3.info("[DEBUG_DUPLICATE] outputContent OK", {
966
1536
  charCount: outputContent.length,
967
1537
  lineCount: outputLines.length,
968
1538
  uniqueLineCount: uniqueLines.size,
@@ -1000,7 +1570,7 @@ async function invoke(config, options, ctx) {
1000
1570
  const rawMessage = error instanceof Error ? error.message : String(error);
1001
1571
  const rawStack = error instanceof Error ? error.stack : undefined;
1002
1572
  const safeMessage = redactSecrets(rawMessage, [config.apiKey]);
1003
- logger2.error("Error during invocation", {
1573
+ logger3.error("Error during invocation", {
1004
1574
  error: safeMessage,
1005
1575
  stack: rawStack ? redactSecrets(rawStack, [config.apiKey]) : undefined
1006
1576
  });
@@ -1023,18 +1593,37 @@ function redactSecrets(text, knownSecrets = []) {
1023
1593
  out = out.replace(/\bBearer\s+[A-Za-z0-9._\-+/=]{12,}\b/g, "<redacted>");
1024
1594
  return out;
1025
1595
  }
1026
- function createProviderInstance(providerId, apiKey, baseURL, conversationId) {
1596
+ function resolveDefenseProtocol(providerId, baseURL) {
1597
+ if (providerId === "openai")
1598
+ return "openai-responses";
1599
+ return wireProtocolFromApiProtocol(resolveApiProtocol(providerId, baseURL));
1600
+ }
1601
+ function createProviderInstance(providerId, apiKey, baseURL, conversationId, cacheRetention, modelId) {
1027
1602
  try {
1028
1603
  if (providerId === "openai") {
1029
1604
  const openai = createOpenAI({
1030
1605
  apiKey,
1031
- baseURL
1606
+ baseURL,
1607
+ fetch: createOutboundDefenseFetch({
1608
+ provider: providerId,
1609
+ modelId,
1610
+ sessionId: conversationId,
1611
+ cacheRetention,
1612
+ wireProtocol: resolveDefenseProtocol(providerId, baseURL)
1613
+ })
1032
1614
  });
1033
1615
  return openai;
1034
1616
  }
1035
1617
  if (providerId === "anthropic") {
1036
1618
  const anthropic = createAnthropic({
1037
- apiKey
1619
+ apiKey,
1620
+ fetch: createOutboundDefenseFetch({
1621
+ provider: providerId,
1622
+ modelId,
1623
+ sessionId: conversationId,
1624
+ cacheRetention,
1625
+ wireProtocol: resolveDefenseProtocol(providerId, baseURL)
1626
+ })
1038
1627
  });
1039
1628
  return anthropic;
1040
1629
  }
@@ -1050,17 +1639,24 @@ function createProviderInstance(providerId, apiKey, baseURL, conversationId) {
1050
1639
  apiKey,
1051
1640
  baseURL: baseURL || "",
1052
1641
  includeUsage: true,
1053
- headers: providerHeaders
1642
+ headers: providerHeaders,
1643
+ fetch: createOutboundDefenseFetch({
1644
+ provider: providerId,
1645
+ modelId,
1646
+ sessionId: conversationId,
1647
+ cacheRetention,
1648
+ wireProtocol: resolveDefenseProtocol(providerId, baseURL)
1649
+ })
1054
1650
  });
1055
1651
  return defaultProvider;
1056
1652
  } catch (error) {
1057
- logger2.error(`Failed to create provider ${providerId}`, { error: String(error) });
1653
+ logger3.error(`Failed to create provider ${providerId}`, { error: String(error) });
1058
1654
  return null;
1059
1655
  }
1060
1656
  }
1061
1657
  async function invokeNonStream(config, options, ctx) {
1062
1658
  const { providerId, modelId } = parseModelString(options.model || config.model);
1063
- const provider = createProviderInstance(providerId, config.apiKey, config.baseURL, options.context?.sessionId);
1659
+ const provider = createProviderInstance(providerId, config.apiKey, config.baseURL, options.context?.sessionId, options.cacheRetention, modelId);
1064
1660
  if (!provider) {
1065
1661
  throw new Error(`Failed to create provider for ${providerId}`);
1066
1662
  }
@@ -1126,4 +1722,4 @@ function createInvokeConfig(model, apiKey, baseURL) {
1126
1722
  };
1127
1723
  }
1128
1724
 
1129
- export { toolParametersToJsonSchema, parseToolArgsStrict, safeParseToolArgs, generateOpencodeSessionId, isOpencodeProvider, isOpencodeEndpoint, getOrCreateOpencodeSessionId, buildOpencodeHeaders, canonicalizeParts, withTimeout, parseModelString, convertToSDKMessages, invoke, invokeNonStream, createInvokeConfig };
1725
+ export { parseToolArgsStrict, safeParseToolArgs, generateOpencodeSessionId, isOpencodeProvider, isOpencodeEndpoint, getOrCreateOpencodeSessionId, buildOpencodeHeaders, canonicalizeParts, PiAiAdapter, withTimeout, parseModelString, convertToSDKMessages, invoke, invokeNonStream, createInvokeConfig };