@fased/fased 0.1.57 → 0.1.59

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 (172) hide show
  1. package/dist/agents/anthropic-payload-policy.js +188 -0
  2. package/dist/agents/anthropic-transport-stream.js +736 -0
  3. package/dist/agents/copilot-dynamic-headers.js +1 -1
  4. package/dist/agents/current-model-catalog.js +5 -2
  5. package/dist/agents/custom-api-registry.js +21 -0
  6. package/dist/agents/google-transport-stream.js +543 -0
  7. package/dist/agents/model-catalog-status.js +6 -1
  8. package/dist/agents/models-config.js +2 -1
  9. package/dist/agents/openai-completions-compat.js +49 -0
  10. package/dist/agents/openai-responses-payload-policy.js +100 -0
  11. package/dist/agents/openai-tool-schema.js +130 -0
  12. package/dist/agents/openai-transport-stream.js +1040 -0
  13. package/dist/agents/pi-embedded-runner/compact.js +9 -0
  14. package/dist/agents/pi-embedded-runner/run/attempt.js +9 -0
  15. package/dist/agents/pi-embedded-runner/session-manager-init.js +5 -20
  16. package/dist/agents/provider-extension-catalog-manifest.js +2 -2
  17. package/dist/agents/provider-request-config.js +1 -1
  18. package/dist/agents/provider-stream.js +29 -0
  19. package/dist/agents/provider-transport-fetch.js +89 -0
  20. package/dist/agents/provider-transport-stream.js +72 -0
  21. package/dist/agents/system-prompt-cache-boundary.js +1 -1
  22. package/dist/agents/system-prompt.js +1 -1
  23. package/dist/agents/transport-message-transform.js +143 -0
  24. package/dist/agents/transport-stream-shared.js +81 -0
  25. package/dist/brand.js +1 -1
  26. package/dist/build-info.json +3 -3
  27. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  28. package/dist/channels/delivery.js +78 -0
  29. package/dist/channels/plugins/catalog.js +10 -5
  30. package/dist/cli/components-cli.js +16 -13
  31. package/dist/cli/program/register.subclis.js +9 -0
  32. package/dist/cli/providers-cli.js +79 -6
  33. package/dist/cli/services-cli.js +28 -0
  34. package/dist/commands/auth-choice.js +1 -1
  35. package/dist/commands/models/list.auth-overview.js +12 -0
  36. package/dist/commands/onboard-channels.js +5 -0
  37. package/dist/commands/onboard-helpers.js +1 -1
  38. package/dist/commands/vllm-setup.js +12 -3
  39. package/dist/control-ui/assets/{app-DltSyY4Y.js → app-S_jg-ADS.js} +1706 -1675
  40. package/dist/control-ui/assets/{index-D5JlBp7f.js → index-C22rDOFm.js} +3 -3
  41. package/dist/control-ui/assets/{providers-Cc89iMdx.js → providers-QMn4w2_f.js} +3 -3
  42. package/dist/control-ui/index.html +1 -1
  43. package/dist/control-ui/version.json +1 -1
  44. package/dist/gateway/control-reply-text.js +10 -1
  45. package/dist/gateway/method-scopes.js +2 -0
  46. package/dist/gateway/protocol/schema/agents-models-skills.js +1 -0
  47. package/dist/gateway/server-chat.js +3 -3
  48. package/dist/gateway/server-methods/channels.js +10 -2
  49. package/dist/gateway/server-methods/chat.js +19 -12
  50. package/dist/gateway/server-methods/models.js +4 -0
  51. package/dist/gateway/server-methods/services.js +47 -2
  52. package/dist/gateway/server-methods-list.js +2 -0
  53. package/dist/gateway/session-event-payloads.js +20 -9
  54. package/dist/infra/google-api-base-url.js +29 -0
  55. package/dist/plugin-sdk/{accounts-CmMwe9Dt.js → accounts-DxblobYM.js} +1 -1
  56. package/dist/plugin-sdk/{actions-DYViFQiX.js → actions-D4UNimWa.js} +2 -2
  57. package/dist/plugin-sdk/{active-listener-DVbpcisf.js → active-listener-CFuy106s.js} +1 -1
  58. package/dist/plugin-sdk/{audio-preflight-D-Mfay8i.js → audio-preflight-CxZixyhW.js} +25 -25
  59. package/dist/plugin-sdk/{audit-JImYFOzJ.js → audit-Cs0K7LBp.js} +1 -1
  60. package/dist/plugin-sdk/{channel-access-cxCK2mci.js → channel-access-D5aHoTY8.js} +1 -1
  61. package/dist/plugin-sdk/{channel-access-configure-B_qYjml8.js → channel-access-configure-Dvch9mMQ.js} +1 -1
  62. package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
  63. package/dist/plugin-sdk/channel-plugin-common.js +4 -4
  64. package/dist/plugin-sdk/{chunk-CF8nvZNj.js → chunk-B0FUGc5A.js} +1 -1
  65. package/dist/plugin-sdk/{chunk-items-yLFoO571.js → chunk-items-Cy9a3X7x.js} +1 -1
  66. package/dist/plugin-sdk/command-status.js +25 -25
  67. package/dist/plugin-sdk/{commands-registry-CK4KmMG0.js → commands-registry-DmDRhRAU.js} +2 -2
  68. package/dist/plugin-sdk/{common-Cky4hpqr.js → common-CfUOowOp.js} +1 -1
  69. package/dist/plugin-sdk/{config-Dbxj_jUP.js → config-mxULv0fQ.js} +4 -1
  70. package/dist/plugin-sdk/{config-schema-aKPMn6ML.js → config-schema-D8E0LX8X.js} +4422 -486
  71. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  72. package/dist/plugin-sdk/discord.d.ts +4 -4
  73. package/dist/plugin-sdk/discord.js +19 -19
  74. package/dist/plugin-sdk/{handle-action-BSNDD2Vc.js → handle-action-DbVCF9HZ.js} +13 -13
  75. package/dist/plugin-sdk/{helpers-CDo2XBSr.js → helpers-BXbdgs5H.js} +1 -1
  76. package/dist/plugin-sdk/{image-ops-DbeBxbn4.js → image-ops-D7jPxaph.js} +1 -1
  77. package/dist/plugin-sdk/index.d.ts +15 -15
  78. package/dist/plugin-sdk/index.js +27 -27
  79. package/dist/plugin-sdk/{login-CWXvFTd8.js → login-BRxww6nv.js} +3 -3
  80. package/dist/plugin-sdk/{login-qr-CJB2zjmM.js → login-qr-DJXsk9XH.js} +3 -3
  81. package/dist/plugin-sdk/{manager-CbiFFLKS.js → manager-Y2S_5IlI.js} +2 -2
  82. package/dist/plugin-sdk/{markdown-tables-Bskt9r8i.js → markdown-tables-DHLFQqaF.js} +1 -1
  83. package/dist/plugin-sdk/{media-B3aAg5rh.js → media-Czo4carg.js} +2 -2
  84. package/dist/plugin-sdk/{monitor-BYGbTI5V.js → monitor-CFHFAUOj.js} +32 -32
  85. package/dist/plugin-sdk/{monitor-BJs6z7AT.js → monitor-xS9A8Upr.js} +29 -29
  86. package/dist/plugin-sdk/ollama-runtime.js +970 -0
  87. package/dist/plugin-sdk/{openresponses-http-BGCl2dS2.js → openresponses-http-BcUbeVV6.js} +25 -25
  88. package/dist/plugin-sdk/{optional-runtime-dependency-BlTVkcAg.js → optional-runtime-dependency-DdMbxS24.js} +1 -1
  89. package/dist/plugin-sdk/{outbound-CIemga5_.js → outbound-Db8mRN6P.js} +6 -6
  90. package/dist/plugin-sdk/{outbound-attachment-2RckWqrk.js → outbound-attachment-BqFjcypb.js} +2 -2
  91. package/dist/plugin-sdk/{pairing-message-r-VQfhFB.js → pairing-message-B3GC_7CD.js} +1 -1
  92. package/dist/plugin-sdk/{pairing-message-C403mq4K.d.ts → pairing-message-CxonJmwM.d.ts} +1 -1
  93. package/dist/plugin-sdk/{pairing-store-uPnLfGgB.js → pairing-store-CQikgIbw.js} +2 -2
  94. package/dist/plugin-sdk/{pi-model-discovery-BpEilAym.js → pi-model-discovery-CY3m5zJP.js} +1 -1
  95. package/dist/plugin-sdk/{pi-model-discovery-runtime-DwNdFaz-.js → pi-model-discovery-runtime-DSh1T2pn.js} +2 -2
  96. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
  97. package/dist/plugin-sdk/{pw-ai-H7UgunQQ.js → pw-ai-AFUqn-tQ.js} +3 -3
  98. package/dist/plugin-sdk/{replies-CKMwkH4G.js → replies-Fzh9PhXl.js} +2 -2
  99. package/dist/plugin-sdk/{resolve-outbound-target-B68fSoGi.js → resolve-outbound-target-KpF3co6T.js} +1 -1
  100. package/dist/plugin-sdk/{resolve-route-B8fOfihG.js → resolve-route-CDl74O19.js} +1 -1
  101. package/dist/plugin-sdk/{retry-policy-B6GQldxB.js → retry-policy-D4uiqUOG.js} +1 -1
  102. package/dist/plugin-sdk/{runtime-nVJl3PlS.js → runtime-Bb6KRnCC.js} +6 -4
  103. package/dist/plugin-sdk/{runtime-dependency-DlqVSsSs.js → runtime-dependency-DLDmB94f.js} +11 -11
  104. package/dist/plugin-sdk/sat-runtime.d.ts +2 -2
  105. package/dist/plugin-sdk/sat-runtime.js +25 -25
  106. package/dist/plugin-sdk/{send-CPK_HlYW.js → send-5nFktR1n.js} +5 -5
  107. package/dist/plugin-sdk/{send-hSu1HWms.js → send-Bfzf11VY.js} +7 -7
  108. package/dist/plugin-sdk/{send-D3DQOg2a.js → send-C4k4JuJN.js} +6 -6
  109. package/dist/plugin-sdk/{send-BHokB4TR.js → send-D-uDKGIq.js} +6 -6
  110. package/dist/plugin-sdk/{send-BCJ4hi3t.js → send-Du8ykP1k.js} +8 -8
  111. package/dist/plugin-sdk/{session-DQ4Dr-mf.js → session-CS-Td9EM.js} +2 -2
  112. package/dist/plugin-sdk/{skill-commands-CmdoKLh_.js → skill-commands-CFAlXWHk.js} +2 -2
  113. package/dist/plugin-sdk/{slack-B70NHpMF.js → slack-DXYGbizH.js} +37 -37
  114. package/dist/plugin-sdk/{slack-actions-fSmP981b.js → slack-actions-BcMkNv1Z.js} +11 -11
  115. package/dist/plugin-sdk/slack.d.ts +4 -4
  116. package/dist/plugin-sdk/slack.js +9 -9
  117. package/dist/plugin-sdk/{sticker-cache-B4dG2sKU.js → sticker-cache-Dr3rYfU1.js} +3 -3
  118. package/dist/plugin-sdk/{tables-EX4Hy-a-.js → tables-bFXyRpkx.js} +1 -1
  119. package/dist/plugin-sdk/{targets-BeGUCGWK.js → targets-DH7a9lKB.js} +1 -1
  120. package/dist/plugin-sdk/{telegram-actions-CM8SJgc9.js → telegram-actions-Besbw_Hg.js} +28 -28
  121. package/dist/plugin-sdk/telegram.d.ts +4 -4
  122. package/dist/plugin-sdk/telegram.js +8 -8
  123. package/dist/plugin-sdk/{thread-bindings.lifecycle-tHK_1mvp.js → thread-bindings.lifecycle-CgOvvdw8.js} +3 -3
  124. package/dist/plugin-sdk/{thread-bindings.state-D7xG1GHu.js → thread-bindings.state-CQpk44Hq.js} +2 -2
  125. package/dist/plugin-sdk/{tmp-fased-dir-Ouj58axY.d.ts → tmp-fased-dir-DQ00xQ5D.d.ts} +1 -1
  126. package/dist/plugin-sdk/{types-B4hj6HgR.d.ts → types-B6zx-Dl2.d.ts} +1 -1
  127. package/dist/plugin-sdk/{types-dWZFX1fk.d.ts → types-eUM7hcDz.d.ts} +1 -1
  128. package/dist/plugin-sdk/{web-BFolfZ3i.js → web-Q1-G--JH.js} +30 -30
  129. package/dist/plugin-sdk/{whatsapp-actions-CYmleHCz.js → whatsapp-actions-BtSc2CBv.js} +13 -13
  130. package/dist/plugin-sdk/{whatsapp-heartbeat-BEwm4GK3.js → whatsapp-heartbeat-Bg9TuYzl.js} +2 -2
  131. package/dist/plugin-sdk/whatsapp.d.ts +9 -9
  132. package/dist/plugin-sdk/whatsapp.js +12 -12
  133. package/dist/plugin-sdk/{wsl-BtMDzMv5.js → wsl-C4DGFkOd.js} +3 -3
  134. package/dist/plugin-sdk/{zod-schema.providers-core-FaYR6KdD.d.ts → zod-schema.providers-core-CIzCjXH9.d.ts} +61 -61
  135. package/dist/plugins/provider-runtime.js +79 -0
  136. package/dist/providers/refresh.js +14 -0
  137. package/extensions/acpx/package.json +1 -1
  138. package/extensions/bluebubbles/package.json +1 -1
  139. package/extensions/copilot-proxy/package.json +1 -1
  140. package/extensions/diagnostics-otel/package.json +1 -1
  141. package/extensions/fased-federation/package.json +1 -1
  142. package/extensions/google-gemini-cli-auth/package.json +1 -1
  143. package/extensions/imessage/package.json +1 -1
  144. package/extensions/irc/package.json +1 -1
  145. package/extensions/line/package.json +1 -1
  146. package/extensions/llm-task/package.json +1 -1
  147. package/extensions/lobster/package.json +1 -1
  148. package/extensions/matrix/CHANGELOG.md +12 -0
  149. package/extensions/matrix/package.json +1 -1
  150. package/extensions/mattermost/package.json +1 -1
  151. package/extensions/memory-core/package.json +2 -2
  152. package/extensions/memory-lancedb/package.json +1 -1
  153. package/extensions/minimax-portal-auth/package.json +1 -1
  154. package/extensions/msteams/CHANGELOG.md +12 -0
  155. package/extensions/msteams/package.json +1 -1
  156. package/extensions/nextcloud-talk/package.json +1 -1
  157. package/extensions/nostr/CHANGELOG.md +12 -0
  158. package/extensions/nostr/package.json +1 -1
  159. package/extensions/open-prose/package.json +1 -1
  160. package/extensions/sat-mining/package.json +1 -1
  161. package/extensions/signal/package.json +1 -1
  162. package/extensions/synology-chat/package.json +1 -1
  163. package/extensions/tlon/package.json +1 -1
  164. package/extensions/twitch/CHANGELOG.md +12 -0
  165. package/extensions/twitch/package.json +1 -1
  166. package/extensions/voice-call/CHANGELOG.md +12 -0
  167. package/extensions/voice-call/package.json +1 -1
  168. package/extensions/zalo/CHANGELOG.md +12 -0
  169. package/extensions/zalo/package.json +1 -1
  170. package/extensions/zalouser/CHANGELOG.md +12 -0
  171. package/extensions/zalouser/package.json +1 -1
  172. package/package.json +1 -1
@@ -30,6 +30,7 @@ import { resolveFasedAgentDocsPath } from "../docs-path.js";
30
30
  import { createPreparedEmbeddedPiSettingsManager } from "../pi-project-settings.js";
31
31
  import { detectRuntimeShell } from "../shell-utils.js";
32
32
  import { createFasedAgentCodingTools } from "../pi-tools.js";
33
+ import { registerProviderStreamForModel } from "../provider-stream.js";
33
34
  import { repairSessionFileIfNeeded } from "../session-file-repair.js";
34
35
  import { log } from "./logger.js";
35
36
  import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
@@ -436,6 +437,14 @@ async function compactEmbeddedPiSessionDirect(params) {
436
437
  tools,
437
438
  sandboxEnabled: !!sandbox?.enabled
438
439
  });
440
+ if (model.api === "ollama") {
441
+ registerProviderStreamForModel({
442
+ model,
443
+ cfg: params.config,
444
+ agentDir,
445
+ workspaceDir: params.workspaceDir
446
+ });
447
+ }
439
448
  const { session } = await createAgentSession({
440
449
  cwd: resolvedWorkspace,
441
450
  agentDir,
@@ -33,6 +33,7 @@ import { isTimeoutError } from "../../failover-error.js";
33
33
  import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
34
34
  import { resolveEffectiveToolFsWorkspaceOnly } from "../../tool-fs-policy.js";
35
35
  import { createFasedAgentCodingTools, filterToolsByDisabledToolNames, resolveToolLoopDetectionConfig } from "../../pi-tools.js";
36
+ import { registerProviderStreamForModel } from "../../provider-stream.js";
36
37
  import { repairSessionFileIfNeeded } from "../../session-file-repair.js";
37
38
  import { log } from "../logger.js";
38
39
  import { sanitizeToolCallIdsForCloudCodeAssist } from "../../tool-call-id.js";
@@ -580,6 +581,14 @@ async function runEmbeddedAttempt(params) {
580
581
  loopDetection: clientToolLoopDetection
581
582
  }) : [];
582
583
  const allCustomTools = [...customTools, ...clientToolDefs];
584
+ if (params.model.api === "ollama") {
585
+ registerProviderStreamForModel({
586
+ model: params.model,
587
+ cfg: params.config,
588
+ agentDir,
589
+ workspaceDir: params.workspaceDir
590
+ });
591
+ }
583
592
  ({session} = await createAgentSession({
584
593
  cwd: resolvedWorkspace,
585
594
  agentDir,
@@ -1,33 +1,18 @@
1
- import fs from "node:fs/promises";
2
-
3
1
  //#region src/agents/pi-embedded-runner/session-manager-init.ts
4
2
  /**
5
- * pi-coding-agent SessionManager persistence quirk:
6
- * - If the file exists but has no assistant message, SessionManager marks itself `flushed=true`
7
- * and will never persist the initial user message.
8
- * - If the file doesn't exist yet, SessionManager builds a new session in memory and flushes
9
- * header+user+assistant once the first assistant arrives (good).
10
- *
11
- * This normalizes the file/session state so the first user prompt is persisted before the first
12
- * assistant entry, even for pre-created session files.
3
+ * Keep Fased's requested identity for new transcripts while leaving existing
4
+ * transcripts under SessionManager's append lifecycle. In particular, an
5
+ * existing header-only file is already marked flushed by SessionManager and
6
+ * must not be truncated or reset to unflushed: its next assistant write uses
7
+ * exclusive creation and would fail with EEXIST.
13
8
  */
14
9
  async function prepareSessionManagerForRun(params) {
15
10
  const sm = params.sessionManager;
16
11
  const header = sm.fileEntries.find((e) => e.type === "session");
17
- const hasAssistant = sm.fileEntries.some((e) => e.type === "message" && e.message?.role === "assistant");
18
12
  if (!params.hadSessionFile && header) {
19
13
  header.id = params.sessionId;
20
14
  header.cwd = params.cwd;
21
15
  sm.sessionId = params.sessionId;
22
- return;
23
- }
24
- if (params.hadSessionFile && header && !hasAssistant) {
25
- await fs.writeFile(params.sessionFile, "", "utf-8");
26
- sm.fileEntries = [header];
27
- sm.byId?.clear?.();
28
- sm.labelsById?.clear?.();
29
- sm.leafId = null;
30
- sm.flushed = false;
31
16
  }
32
17
  }
33
18
 
@@ -56,8 +56,8 @@ const FASED_PROVIDER_EXTENSION_CATALOG_MANIFEST = [
56
56
  upstreamProviderId: "kimi-coding",
57
57
  upstreamCatalogPaths: ["extensions/kimi-coding/provider-catalog.ts"],
58
58
  status: "mapped",
59
- fasedProviderIds: ["kimi"],
60
- fasedProviderAliases: ["kimi-coding", "kimi-code"],
59
+ fasedProviderIds: ["kimi-coding"],
60
+ fasedProviderAliases: ["kimi", "kimi-code"],
61
61
  docsPath: "docs/providers/moonshot.md",
62
62
  authSurface: "api-key",
63
63
  authChoiceIds: ["kimi-code-api-key"]
@@ -460,4 +460,4 @@ function getModelProviderRequestTransport(model) {
460
460
  }
461
461
 
462
462
  //#endregion
463
- export { attachModelProviderRequestTransport, sanitizeConfiguredModelProviderRequest };
463
+ export { attachModelProviderRequestTransport, buildProviderRequestDispatcherPolicy, getModelProviderRequestTransport, resolveProviderRequestPolicyConfig, sanitizeConfiguredModelProviderRequest };
@@ -0,0 +1,29 @@
1
+ import { resolveProviderStreamFn } from "../plugins/provider-runtime.js";
2
+ import { ensureCustomApiRegistered } from "./custom-api-registry.js";
3
+ import { createTransportAwareStreamFnForModel } from "./provider-transport-stream.js";
4
+
5
+ //#region src/agents/provider-stream.ts
6
+ function registerProviderStreamForModel(params) {
7
+ const streamFn = resolveProviderStreamFn({
8
+ provider: params.model.provider,
9
+ config: params.cfg,
10
+ workspaceDir: params.workspaceDir,
11
+ env: params.env,
12
+ context: {
13
+ config: params.cfg,
14
+ agentDir: params.agentDir,
15
+ workspaceDir: params.workspaceDir,
16
+ provider: params.model.provider,
17
+ modelId: params.model.id,
18
+ model: params.model
19
+ }
20
+ }) ?? createTransportAwareStreamFnForModel(params.model);
21
+ if (!streamFn) {
22
+ return undefined;
23
+ }
24
+ ensureCustomApiRegistered(params.model.api, streamFn);
25
+ return streamFn;
26
+ }
27
+
28
+ //#endregion
29
+ export { registerProviderStreamForModel };
@@ -0,0 +1,89 @@
1
+ import { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
2
+ import { buildProviderRequestDispatcherPolicy, getModelProviderRequestTransport, resolveProviderRequestPolicyConfig } from "./provider-request-config.js";
3
+
4
+ //#region src/agents/provider-transport-fetch.ts
5
+ function buildManagedResponse(response, release) {
6
+ if (!response.body) {
7
+ void release();
8
+ return response;
9
+ }
10
+ const source = response.body;
11
+ let reader;
12
+ let released = false;
13
+ const finalize = async () => {
14
+ if (released) {
15
+ return;
16
+ }
17
+ released = true;
18
+ await release().catch(() => undefined);
19
+ };
20
+ const wrappedBody = new ReadableStream({
21
+ start() {
22
+ reader = source.getReader();
23
+ },
24
+ async pull(controller) {
25
+ try {
26
+ const chunk = await reader?.read();
27
+ if (!chunk || chunk.done) {
28
+ controller.close();
29
+ await finalize();
30
+ return;
31
+ }
32
+ controller.enqueue(chunk.value);
33
+ } catch (error) {
34
+ controller.error(error);
35
+ await finalize();
36
+ }
37
+ },
38
+ async cancel(reason) {
39
+ try {
40
+ await reader?.cancel(reason);
41
+ } finally {
42
+ await finalize();
43
+ }
44
+ }
45
+ });
46
+ return new Response(wrappedBody, {
47
+ status: response.status,
48
+ statusText: response.statusText,
49
+ headers: response.headers
50
+ });
51
+ }
52
+ function resolveModelRequestPolicy(model) {
53
+ return resolveProviderRequestPolicyConfig({
54
+ provider: model.provider,
55
+ api: model.api,
56
+ baseUrl: model.baseUrl,
57
+ capability: "llm",
58
+ transport: "stream",
59
+ request: getModelProviderRequestTransport(model)
60
+ });
61
+ }
62
+ function buildGuardedModelFetch(model) {
63
+ const requestConfig = resolveModelRequestPolicy(model);
64
+ const dispatcherPolicy = buildProviderRequestDispatcherPolicy(requestConfig);
65
+ return async (input, init) => {
66
+ const request = input instanceof Request ? new Request(input, init) : undefined;
67
+ const url = request?.url ?? (input instanceof URL ? input.toString() : typeof input === "string" ? input : (() => {
68
+ throw new Error("Unsupported fetch input for transport-aware model request");
69
+ })());
70
+ const requestInit = request && {
71
+ method: request.method,
72
+ headers: request.headers,
73
+ body: request.body ?? undefined,
74
+ redirect: request.redirect,
75
+ signal: request.signal,
76
+ ...request.body ? { duplex: "half" } : {}
77
+ };
78
+ const result = await fetchWithSsrFGuard({
79
+ url,
80
+ init: requestInit ?? init,
81
+ dispatcherPolicy,
82
+ ...requestConfig.allowPrivateNetwork ? { policy: { allowPrivateNetwork: true } } : {}
83
+ });
84
+ return buildManagedResponse(result.response, result.release);
85
+ };
86
+ }
87
+
88
+ //#endregion
89
+ export { buildGuardedModelFetch };
@@ -0,0 +1,72 @@
1
+ import { getModelProviderRequestTransport } from "./provider-request-config.js";
2
+ import { createAnthropicMessagesTransportStreamFn } from "./anthropic-transport-stream.js";
3
+ import { createGoogleGenerativeAiTransportStreamFn } from "./google-transport-stream.js";
4
+ import { createOpenAICompletionsTransportStreamFn, createOpenAIResponsesTransportStreamFn } from "./openai-transport-stream.js";
5
+
6
+ //#region src/agents/provider-transport-stream.ts
7
+ const SUPPORTED_TRANSPORT_APIS = new Set([
8
+ "openai-responses",
9
+ "openai-codex-responses",
10
+ "openai-completions",
11
+ "anthropic-messages",
12
+ "google-generative-ai"
13
+ ]);
14
+ const SIMPLE_TRANSPORT_API_ALIAS = {
15
+ "openai-responses": "fased-openai-responses-transport",
16
+ "openai-codex-responses": "fased-openai-responses-transport",
17
+ "openai-completions": "fased-openai-completions-transport",
18
+ "anthropic-messages": "fased-anthropic-messages-transport",
19
+ "google-generative-ai": "fased-google-generative-ai-transport"
20
+ };
21
+ function createSupportedTransportStreamFn(api) {
22
+ switch (api) {
23
+ case "openai-responses":
24
+ case "openai-codex-responses": return createOpenAIResponsesTransportStreamFn();
25
+ case "openai-completions": return createOpenAICompletionsTransportStreamFn();
26
+ case "anthropic-messages": return createAnthropicMessagesTransportStreamFn();
27
+ case "google-generative-ai": return createGoogleGenerativeAiTransportStreamFn();
28
+ default: return undefined;
29
+ }
30
+ }
31
+ function hasTransportOverrides(model) {
32
+ const request = getModelProviderRequestTransport(model);
33
+ return Boolean(request?.proxy || request?.tls || request?.allowPrivateNetwork !== undefined);
34
+ }
35
+ function isTransportAwareApiSupported(api) {
36
+ return SUPPORTED_TRANSPORT_APIS.has(api);
37
+ }
38
+ function resolveTransportAwareSimpleApi(api) {
39
+ return SIMPLE_TRANSPORT_API_ALIAS[api];
40
+ }
41
+ function createTransportAwareStreamFnForModel(model) {
42
+ if (!hasTransportOverrides(model)) {
43
+ return undefined;
44
+ }
45
+ if (!isTransportAwareApiSupported(model.api)) {
46
+ throw new Error(`Model-provider request controls are not yet supported for api "${model.api}"`);
47
+ }
48
+ return createSupportedTransportStreamFn(model.api);
49
+ }
50
+ function createBoundaryAwareStreamFnForModel(model) {
51
+ if (!isTransportAwareApiSupported(model.api)) {
52
+ return undefined;
53
+ }
54
+ return createSupportedTransportStreamFn(model.api);
55
+ }
56
+ function prepareTransportAwareSimpleModel(model) {
57
+ const streamFn = createTransportAwareStreamFnForModel(model);
58
+ const alias = resolveTransportAwareSimpleApi(model.api);
59
+ if (!streamFn || !alias) {
60
+ return model;
61
+ }
62
+ return {
63
+ ...model,
64
+ api: alias
65
+ };
66
+ }
67
+ function buildTransportAwareSimpleStreamFn(model) {
68
+ return createTransportAwareStreamFnForModel(model);
69
+ }
70
+
71
+ //#endregion
72
+ export { createTransportAwareStreamFnForModel };
@@ -32,4 +32,4 @@ function prependSystemPromptAdditionAfterCacheBoundary(params) {
32
32
  }
33
33
 
34
34
  //#endregion
35
- export { SYSTEM_PROMPT_CACHE_BOUNDARY };
35
+ export { SYSTEM_PROMPT_CACHE_BOUNDARY, splitSystemPromptCacheBoundary, stripSystemPromptCacheBoundary };
@@ -1,8 +1,8 @@
1
1
  import { listDeliverableMessageChannels } from "../utils/message-channel.js";
2
2
  import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
3
3
  import { normalizePromptCapabilityIds, normalizeStructuredPromptSection } from "./prompt-cache-stability.js";
4
- import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
5
4
  import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "./system-prompt-cache-boundary.js";
5
+ import { sanitizeForPromptLiteral } from "./sanitize-for-prompt.js";
6
6
  import { createHash, createHmac } from "node:crypto";
7
7
 
8
8
  //#region src/agents/system-prompt.ts
@@ -0,0 +1,143 @@
1
+ //#region src/agents/transport-message-transform.ts
2
+ function transformTransportMessages(messages, model, normalizeToolCallId) {
3
+ const toolCallIdMap = new Map();
4
+ const transformed = messages.map((msg) => {
5
+ if (msg.role === "user") {
6
+ return msg;
7
+ }
8
+ if (msg.role === "toolResult") {
9
+ const normalizedId = toolCallIdMap.get(msg.toolCallId);
10
+ return normalizedId && normalizedId !== msg.toolCallId ? {
11
+ ...msg,
12
+ toolCallId: normalizedId
13
+ } : msg;
14
+ }
15
+ if (msg.role !== "assistant") {
16
+ return msg;
17
+ }
18
+ const isSameModel = msg.provider === model.provider && msg.api === model.api && msg.model === model.id;
19
+ const content = [];
20
+ for (const block of msg.content) {
21
+ if (block.type === "thinking") {
22
+ const thinkingBlock = block;
23
+ if (thinkingBlock.redacted) {
24
+ if (isSameModel) {
25
+ content.push(thinkingBlock);
26
+ }
27
+ continue;
28
+ }
29
+ if (isSameModel && block.thinkingSignature) {
30
+ content.push(block);
31
+ continue;
32
+ }
33
+ if (!block.thinking.trim()) {
34
+ continue;
35
+ }
36
+ content.push(isSameModel ? block : {
37
+ type: "text",
38
+ text: block.thinking
39
+ });
40
+ continue;
41
+ }
42
+ if (block.type === "text") {
43
+ content.push(isSameModel ? block : {
44
+ type: "text",
45
+ text: block.text
46
+ });
47
+ continue;
48
+ }
49
+ if (block.type !== "toolCall") {
50
+ content.push(block);
51
+ continue;
52
+ }
53
+ let normalizedToolCall = block;
54
+ if (!isSameModel && block.thoughtSignature) {
55
+ normalizedToolCall = { ...normalizedToolCall };
56
+ delete normalizedToolCall.thoughtSignature;
57
+ }
58
+ if (!isSameModel && normalizeToolCallId) {
59
+ const normalizedId = normalizeToolCallId(block.id, model, msg);
60
+ if (normalizedId !== block.id) {
61
+ toolCallIdMap.set(block.id, normalizedId);
62
+ normalizedToolCall = {
63
+ ...normalizedToolCall,
64
+ id: normalizedId
65
+ };
66
+ }
67
+ }
68
+ content.push(normalizedToolCall);
69
+ }
70
+ return {
71
+ ...msg,
72
+ content
73
+ };
74
+ });
75
+ const result = [];
76
+ let pendingToolCalls = [];
77
+ let existingToolResultIds = new Set();
78
+ for (const msg of transformed) {
79
+ if (msg.role === "assistant") {
80
+ if (pendingToolCalls.length > 0) {
81
+ for (const toolCall of pendingToolCalls) {
82
+ if (!existingToolResultIds.has(toolCall.id)) {
83
+ result.push({
84
+ role: "toolResult",
85
+ toolCallId: toolCall.id,
86
+ toolName: toolCall.name,
87
+ content: [{
88
+ type: "text",
89
+ text: "No result provided"
90
+ }],
91
+ isError: true,
92
+ timestamp: Date.now()
93
+ });
94
+ }
95
+ }
96
+ pendingToolCalls = [];
97
+ existingToolResultIds = new Set();
98
+ }
99
+ if (msg.stopReason === "error" || msg.stopReason === "aborted") {
100
+ continue;
101
+ }
102
+ const toolCalls = msg.content.filter((block) => block.type === "toolCall");
103
+ if (toolCalls.length > 0) {
104
+ pendingToolCalls = toolCalls.map((block) => ({
105
+ id: block.id,
106
+ name: block.name
107
+ }));
108
+ existingToolResultIds = new Set();
109
+ }
110
+ result.push(msg);
111
+ continue;
112
+ }
113
+ if (msg.role === "toolResult") {
114
+ existingToolResultIds.add(msg.toolCallId);
115
+ result.push(msg);
116
+ continue;
117
+ }
118
+ if (pendingToolCalls.length > 0) {
119
+ for (const toolCall of pendingToolCalls) {
120
+ if (!existingToolResultIds.has(toolCall.id)) {
121
+ result.push({
122
+ role: "toolResult",
123
+ toolCallId: toolCall.id,
124
+ toolName: toolCall.name,
125
+ content: [{
126
+ type: "text",
127
+ text: "No result provided"
128
+ }],
129
+ isError: true,
130
+ timestamp: Date.now()
131
+ });
132
+ }
133
+ }
134
+ pendingToolCalls = [];
135
+ existingToolResultIds = new Set();
136
+ }
137
+ result.push(msg);
138
+ }
139
+ return result;
140
+ }
141
+
142
+ //#endregion
143
+ export { transformTransportMessages };
@@ -0,0 +1,81 @@
1
+ import { createAssistantMessageEventStream } from "@mariozechner/pi-ai/compat";
2
+
3
+ //#region src/agents/transport-stream-shared.ts
4
+ function sanitizeTransportPayloadText(text) {
5
+ return text.replace(/[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/g, "");
6
+ }
7
+ function mergeTransportHeaders(...headerSources) {
8
+ const merged = {};
9
+ for (const headers of headerSources) {
10
+ if (headers) {
11
+ Object.assign(merged, headers);
12
+ }
13
+ }
14
+ return Object.keys(merged).length > 0 ? merged : undefined;
15
+ }
16
+ function mergeTransportMetadata(payload, metadata) {
17
+ if (!metadata || Object.keys(metadata).length === 0) {
18
+ return payload;
19
+ }
20
+ const existingMetadata = payload.metadata && typeof payload.metadata === "object" && !Array.isArray(payload.metadata) ? payload.metadata : undefined;
21
+ return {
22
+ ...payload,
23
+ metadata: {
24
+ ...existingMetadata,
25
+ ...metadata
26
+ }
27
+ };
28
+ }
29
+ function createEmptyTransportUsage() {
30
+ return {
31
+ input: 0,
32
+ output: 0,
33
+ cacheRead: 0,
34
+ cacheWrite: 0,
35
+ totalTokens: 0,
36
+ cost: {
37
+ input: 0,
38
+ output: 0,
39
+ cacheRead: 0,
40
+ cacheWrite: 0,
41
+ total: 0
42
+ }
43
+ };
44
+ }
45
+ function createWritableTransportEventStream() {
46
+ const eventStream = createAssistantMessageEventStream();
47
+ return {
48
+ eventStream,
49
+ stream: eventStream
50
+ };
51
+ }
52
+ function finalizeTransportStream(params) {
53
+ const { stream, output, signal } = params;
54
+ if (signal?.aborted) {
55
+ throw new Error("Request was aborted");
56
+ }
57
+ if (output.stopReason === "aborted" || output.stopReason === "error") {
58
+ throw new Error("An unknown error occurred");
59
+ }
60
+ stream.push({
61
+ type: "done",
62
+ reason: output.stopReason,
63
+ message: output
64
+ });
65
+ stream.end();
66
+ }
67
+ function failTransportStream(params) {
68
+ const { stream, output, signal, error, cleanup } = params;
69
+ cleanup?.();
70
+ output.stopReason = signal?.aborted ? "aborted" : "error";
71
+ output.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);
72
+ stream.push({
73
+ type: "error",
74
+ reason: output.stopReason,
75
+ error: output
76
+ });
77
+ stream.end();
78
+ }
79
+
80
+ //#endregion
81
+ export { createEmptyTransportUsage, createWritableTransportEventStream, failTransportStream, finalizeTransportStream, mergeTransportHeaders, mergeTransportMetadata, sanitizeTransportPayloadText };
package/dist/brand.js CHANGED
@@ -2,7 +2,7 @@
2
2
  const FASED_BRAND_NAME = "Fased";
3
3
  const FASED_AGENT_NAME = "Fased Agent";
4
4
  const FASED_CONTROL_NAME = "Fased Control";
5
- const FASED_PRODUCT_VERSION = "0.1.57";
5
+ const FASED_PRODUCT_VERSION = "0.1.59";
6
6
  const FASED_DISPLAY_VERSION = `v${FASED_PRODUCT_VERSION}`;
7
7
  function formatFasedDisplayLine() {
8
8
  return `${FASED_AGENT_NAME} ${FASED_DISPLAY_VERSION}`;
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.57",
3
- "commit": "91e53d4b2c1ca02701eff503d93e889ccfaab43d",
4
- "builtAt": "2026-07-13T13:04:23.327Z"
2
+ "version": "0.1.59",
3
+ "commit": "52ee044888a4c31c2e7ee6958d86a61a1afdd081",
4
+ "builtAt": "2026-07-13T20:07:25.934Z"
5
5
  }
@@ -1 +1 @@
1
- bfd05e986c05a91921422f61d2871d036c3e2622a756b89cd75c7ba92ccf4947
1
+ 03f1c6c4f9975b6d14e5cf7e79d871c44fab07eb079c05ec45b191f8eab384cd
@@ -0,0 +1,78 @@
1
+ //#region src/channels/delivery.ts
2
+ const CHANNEL_DELIVERIES = [
3
+ "official-addon",
4
+ "bundled",
5
+ "source-only",
6
+ "external-prerequisite"
7
+ ];
8
+ const CHANNEL_DELIVERY_ENTRIES = [
9
+ ...[
10
+ "telegram",
11
+ "whatsapp",
12
+ "discord",
13
+ "slack",
14
+ "feishu",
15
+ "googlechat"
16
+ ].map((id) => ({
17
+ id,
18
+ docsPath: `/channels/${id}`,
19
+ delivery: "official-addon"
20
+ })),
21
+ ...[
22
+ "irc",
23
+ "line",
24
+ "mattermost",
25
+ "msteams",
26
+ "nextcloud-talk",
27
+ "synology-chat",
28
+ "zalo",
29
+ "zalouser"
30
+ ].map((id) => ({
31
+ id,
32
+ docsPath: `/channels/${id}`,
33
+ delivery: "bundled"
34
+ })),
35
+ ...[
36
+ "matrix",
37
+ "nostr",
38
+ "tlon",
39
+ "twitch"
40
+ ].map((id) => ({
41
+ id,
42
+ docsPath: `/channels/${id}`,
43
+ delivery: "source-only"
44
+ })),
45
+ ...[
46
+ "signal",
47
+ "imessage",
48
+ "bluebubbles"
49
+ ].map((id) => ({
50
+ id,
51
+ docsPath: `/channels/${id}`,
52
+ delivery: "external-prerequisite"
53
+ }))
54
+ ];
55
+ const DELIVERY_BY_ID = new Map(CHANNEL_DELIVERY_ENTRIES.map((entry) => [entry.id, entry]));
56
+ function listChannelDeliveryEntries() {
57
+ return CHANNEL_DELIVERY_ENTRIES.map((entry) => ({ ...entry }));
58
+ }
59
+ function getChannelDeliveryEntry(id) {
60
+ return DELIVERY_BY_ID.get(id.trim().toLowerCase());
61
+ }
62
+ function getChannelDelivery(id) {
63
+ return getChannelDeliveryEntry(id)?.delivery ?? "source-only";
64
+ }
65
+ function formatChannelDelivery(delivery) {
66
+ switch (delivery) {
67
+ case "official-addon": return "Official add-on";
68
+ case "bundled": return "Bundled";
69
+ case "source-only": return "Source-only";
70
+ case "external-prerequisite": return "External prerequisite";
71
+ }
72
+ }
73
+ function channelDeliveryAllowsInstall(delivery) {
74
+ return delivery === "official-addon" || delivery === "bundled";
75
+ }
76
+
77
+ //#endregion
78
+ export { channelDeliveryAllowsInstall, formatChannelDelivery, getChannelDelivery };