@fased/fased 0.1.58 → 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 (167) 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/custom-api-registry.js +21 -0
  5. package/dist/agents/google-transport-stream.js +543 -0
  6. package/dist/agents/models-config.js +2 -1
  7. package/dist/agents/openai-completions-compat.js +49 -0
  8. package/dist/agents/openai-responses-payload-policy.js +100 -0
  9. package/dist/agents/openai-tool-schema.js +130 -0
  10. package/dist/agents/openai-transport-stream.js +1040 -0
  11. package/dist/agents/pi-embedded-runner/compact.js +9 -0
  12. package/dist/agents/pi-embedded-runner/run/attempt.js +9 -0
  13. package/dist/agents/provider-request-config.js +1 -1
  14. package/dist/agents/provider-stream.js +29 -0
  15. package/dist/agents/provider-transport-fetch.js +89 -0
  16. package/dist/agents/provider-transport-stream.js +72 -0
  17. package/dist/agents/system-prompt-cache-boundary.js +1 -1
  18. package/dist/agents/system-prompt.js +1 -1
  19. package/dist/agents/transport-message-transform.js +143 -0
  20. package/dist/agents/transport-stream-shared.js +81 -0
  21. package/dist/brand.js +1 -1
  22. package/dist/build-info.json +3 -3
  23. package/dist/canvas-host/a2ui/.bundle.hash +1 -1
  24. package/dist/channels/delivery.js +78 -0
  25. package/dist/channels/plugins/catalog.js +10 -5
  26. package/dist/cli/components-cli.js +16 -13
  27. package/dist/cli/program/register.subclis.js +9 -0
  28. package/dist/cli/providers-cli.js +79 -6
  29. package/dist/cli/services-cli.js +28 -0
  30. package/dist/commands/auth-choice.js +1 -1
  31. package/dist/commands/models/list.auth-overview.js +12 -0
  32. package/dist/commands/onboard-channels.js +5 -0
  33. package/dist/commands/onboard-helpers.js +1 -1
  34. package/dist/commands/vllm-setup.js +12 -3
  35. package/dist/control-ui/assets/{app-CpgQGqe6.js → app-S_jg-ADS.js} +1706 -1675
  36. package/dist/control-ui/assets/{index-DiBBflpv.js → index-C22rDOFm.js} +3 -3
  37. package/dist/control-ui/assets/{providers-Cc89iMdx.js → providers-QMn4w2_f.js} +3 -3
  38. package/dist/control-ui/index.html +1 -1
  39. package/dist/control-ui/version.json +1 -1
  40. package/dist/gateway/control-reply-text.js +10 -1
  41. package/dist/gateway/method-scopes.js +2 -0
  42. package/dist/gateway/protocol/schema/agents-models-skills.js +1 -0
  43. package/dist/gateway/server-chat.js +3 -3
  44. package/dist/gateway/server-methods/channels.js +10 -2
  45. package/dist/gateway/server-methods/chat.js +19 -12
  46. package/dist/gateway/server-methods/models.js +4 -0
  47. package/dist/gateway/server-methods/services.js +47 -2
  48. package/dist/gateway/server-methods-list.js +2 -0
  49. package/dist/gateway/session-event-payloads.js +20 -9
  50. package/dist/infra/google-api-base-url.js +29 -0
  51. package/dist/plugin-sdk/{accounts-BJuN64m-.js → accounts-DxblobYM.js} +1 -1
  52. package/dist/plugin-sdk/{actions-DaEvM9Bl.js → actions-D4UNimWa.js} +2 -2
  53. package/dist/plugin-sdk/{active-listener-B8Kuanet.js → active-listener-CFuy106s.js} +1 -1
  54. package/dist/plugin-sdk/{audio-preflight-D7tCO0EH.js → audio-preflight-CxZixyhW.js} +25 -25
  55. package/dist/plugin-sdk/{audit-CVWH4BVP.js → audit-Cs0K7LBp.js} +1 -1
  56. package/dist/plugin-sdk/{channel-access-CH9FAS-I.js → channel-access-D5aHoTY8.js} +1 -1
  57. package/dist/plugin-sdk/{channel-access-configure-CI0je66H.js → channel-access-configure-Dvch9mMQ.js} +1 -1
  58. package/dist/plugin-sdk/channel-plugin-common.d.ts +2 -2
  59. package/dist/plugin-sdk/channel-plugin-common.js +4 -4
  60. package/dist/plugin-sdk/{chunk-01oBnQjh.js → chunk-B0FUGc5A.js} +1 -1
  61. package/dist/plugin-sdk/{chunk-items-D2zDJ8q8.js → chunk-items-Cy9a3X7x.js} +1 -1
  62. package/dist/plugin-sdk/command-status.js +25 -25
  63. package/dist/plugin-sdk/{commands-registry-ckg4fhYa.js → commands-registry-DmDRhRAU.js} +2 -2
  64. package/dist/plugin-sdk/{common-zHvdO8ly.js → common-CfUOowOp.js} +1 -1
  65. package/dist/plugin-sdk/{config-DrhYEiCM.js → config-mxULv0fQ.js} +1 -1
  66. package/dist/plugin-sdk/{config-schema-BtjeV5Hm.js → config-schema-D8E0LX8X.js} +4405 -460
  67. package/dist/plugin-sdk/device-pair.d.ts +1 -1
  68. package/dist/plugin-sdk/discord.d.ts +3 -3
  69. package/dist/plugin-sdk/discord.js +19 -19
  70. package/dist/plugin-sdk/{handle-action-5dhYpMbP.js → handle-action-DbVCF9HZ.js} +13 -13
  71. package/dist/plugin-sdk/{helpers-E9aafRzA.js → helpers-BXbdgs5H.js} +1 -1
  72. package/dist/plugin-sdk/{image-ops-D2U9ctmu.js → image-ops-D7jPxaph.js} +1 -1
  73. package/dist/plugin-sdk/index.d.ts +4 -4
  74. package/dist/plugin-sdk/index.js +27 -27
  75. package/dist/plugin-sdk/{login-hql0fNuL.js → login-BRxww6nv.js} +3 -3
  76. package/dist/plugin-sdk/{login-qr-DJJ0svux.js → login-qr-DJXsk9XH.js} +3 -3
  77. package/dist/plugin-sdk/{manager-ciNnAMBn.js → manager-Y2S_5IlI.js} +2 -2
  78. package/dist/plugin-sdk/{markdown-tables-BKxbua_h.js → markdown-tables-DHLFQqaF.js} +1 -1
  79. package/dist/plugin-sdk/{media-DUIZ6x9H.js → media-Czo4carg.js} +2 -2
  80. package/dist/plugin-sdk/{monitor-D-giXewh.js → monitor-CFHFAUOj.js} +30 -30
  81. package/dist/plugin-sdk/{monitor-CNSGw4uQ.js → monitor-xS9A8Upr.js} +29 -29
  82. package/dist/plugin-sdk/ollama-runtime.js +970 -0
  83. package/dist/plugin-sdk/{openresponses-http-dbTd8UMk.js → openresponses-http-BcUbeVV6.js} +25 -25
  84. package/dist/plugin-sdk/{optional-runtime-dependency-CKsJL1PD.js → optional-runtime-dependency-DdMbxS24.js} +1 -1
  85. package/dist/plugin-sdk/{outbound-DhGrjRft.js → outbound-Db8mRN6P.js} +6 -6
  86. package/dist/plugin-sdk/{outbound-attachment-DAF8huFz.js → outbound-attachment-BqFjcypb.js} +2 -2
  87. package/dist/plugin-sdk/{pairing-message-BsJVvXkb.js → pairing-message-B3GC_7CD.js} +1 -1
  88. package/dist/plugin-sdk/{pairing-message-C403mq4K.d.ts → pairing-message-CxonJmwM.d.ts} +1 -1
  89. package/dist/plugin-sdk/{pairing-store-DwM-BNbj.js → pairing-store-CQikgIbw.js} +2 -2
  90. package/dist/plugin-sdk/{pi-model-discovery-DkIdlJvJ.js → pi-model-discovery-CY3m5zJP.js} +1 -1
  91. package/dist/plugin-sdk/{pi-model-discovery-runtime-Cv7okUMt.js → pi-model-discovery-runtime-DSh1T2pn.js} +2 -2
  92. package/dist/plugin-sdk/provider-web-search-config-contract.d.ts +1 -1
  93. package/dist/plugin-sdk/{pw-ai-Dxd87W3J.js → pw-ai-AFUqn-tQ.js} +3 -3
  94. package/dist/plugin-sdk/{replies-Bx61SvAC.js → replies-Fzh9PhXl.js} +2 -2
  95. package/dist/plugin-sdk/{resolve-outbound-target-bc-FpPZg.js → resolve-outbound-target-KpF3co6T.js} +1 -1
  96. package/dist/plugin-sdk/{resolve-route-D0eBYPtb.js → resolve-route-CDl74O19.js} +1 -1
  97. package/dist/plugin-sdk/{retry-policy-HTrC4zfC.js → retry-policy-D4uiqUOG.js} +1 -1
  98. package/dist/plugin-sdk/{runtime-BVkIrYLQ.js → runtime-Bb6KRnCC.js} +6 -4
  99. package/dist/plugin-sdk/{runtime-dependency-B2PqMdBu.js → runtime-dependency-DLDmB94f.js} +2 -2
  100. package/dist/plugin-sdk/sat-runtime.d.ts +2 -2
  101. package/dist/plugin-sdk/sat-runtime.js +25 -25
  102. package/dist/plugin-sdk/{send-DgzZUx2i.js → send-5nFktR1n.js} +5 -5
  103. package/dist/plugin-sdk/{send-DT2egZNK.js → send-Bfzf11VY.js} +7 -7
  104. package/dist/plugin-sdk/{send-BGDGzxUu.js → send-C4k4JuJN.js} +6 -6
  105. package/dist/plugin-sdk/{send-KJy3ajA3.js → send-D-uDKGIq.js} +6 -6
  106. package/dist/plugin-sdk/{send-C3QWSYLR.js → send-Du8ykP1k.js} +8 -8
  107. package/dist/plugin-sdk/{session-BCIEFOu1.js → session-CS-Td9EM.js} +2 -2
  108. package/dist/plugin-sdk/{skill-commands-CyIkcR8P.js → skill-commands-CFAlXWHk.js} +2 -2
  109. package/dist/plugin-sdk/{slack-DjKNh2uh.js → slack-DXYGbizH.js} +37 -37
  110. package/dist/plugin-sdk/{slack-actions-CeM9LWDp.js → slack-actions-BcMkNv1Z.js} +11 -11
  111. package/dist/plugin-sdk/slack.d.ts +3 -3
  112. package/dist/plugin-sdk/slack.js +9 -9
  113. package/dist/plugin-sdk/{sticker-cache-DcWzQ2wx.js → sticker-cache-Dr3rYfU1.js} +3 -3
  114. package/dist/plugin-sdk/{tables-B2iehyjG.js → tables-bFXyRpkx.js} +1 -1
  115. package/dist/plugin-sdk/{targets-BPket0SF.js → targets-DH7a9lKB.js} +1 -1
  116. package/dist/plugin-sdk/{telegram-actions-Cx_HWVht.js → telegram-actions-Besbw_Hg.js} +28 -28
  117. package/dist/plugin-sdk/telegram.d.ts +3 -3
  118. package/dist/plugin-sdk/telegram.js +8 -8
  119. package/dist/plugin-sdk/{thread-bindings.lifecycle-CYH69SIw.js → thread-bindings.lifecycle-CgOvvdw8.js} +3 -3
  120. package/dist/plugin-sdk/{thread-bindings.state-BN6461WG.js → thread-bindings.state-CQpk44Hq.js} +2 -2
  121. package/dist/plugin-sdk/{tmp-fased-dir-Ouj58axY.d.ts → tmp-fased-dir-DQ00xQ5D.d.ts} +1 -1
  122. package/dist/plugin-sdk/{types-B4hj6HgR.d.ts → types-B6zx-Dl2.d.ts} +1 -1
  123. package/dist/plugin-sdk/{types-dWZFX1fk.d.ts → types-eUM7hcDz.d.ts} +1 -1
  124. package/dist/plugin-sdk/{web-vR-oNiBv.js → web-Q1-G--JH.js} +30 -30
  125. package/dist/plugin-sdk/{whatsapp-actions-BYNf8ceY.js → whatsapp-actions-BtSc2CBv.js} +13 -13
  126. package/dist/plugin-sdk/{whatsapp-heartbeat-DZwa8MF0.js → whatsapp-heartbeat-Bg9TuYzl.js} +2 -2
  127. package/dist/plugin-sdk/whatsapp.d.ts +3 -3
  128. package/dist/plugin-sdk/whatsapp.js +12 -12
  129. package/dist/plugin-sdk/{wsl-WGtdw_6h.js → wsl-C4DGFkOd.js} +3 -3
  130. package/dist/plugins/provider-runtime.js +79 -0
  131. package/dist/providers/refresh.js +14 -0
  132. package/extensions/acpx/package.json +1 -1
  133. package/extensions/bluebubbles/package.json +1 -1
  134. package/extensions/copilot-proxy/package.json +1 -1
  135. package/extensions/diagnostics-otel/package.json +1 -1
  136. package/extensions/fased-federation/package.json +1 -1
  137. package/extensions/google-gemini-cli-auth/package.json +1 -1
  138. package/extensions/imessage/package.json +1 -1
  139. package/extensions/irc/package.json +1 -1
  140. package/extensions/line/package.json +1 -1
  141. package/extensions/llm-task/package.json +1 -1
  142. package/extensions/lobster/package.json +1 -1
  143. package/extensions/matrix/CHANGELOG.md +6 -0
  144. package/extensions/matrix/package.json +1 -1
  145. package/extensions/mattermost/package.json +1 -1
  146. package/extensions/memory-core/package.json +2 -2
  147. package/extensions/memory-lancedb/package.json +1 -1
  148. package/extensions/minimax-portal-auth/package.json +1 -1
  149. package/extensions/msteams/CHANGELOG.md +6 -0
  150. package/extensions/msteams/package.json +1 -1
  151. package/extensions/nextcloud-talk/package.json +1 -1
  152. package/extensions/nostr/CHANGELOG.md +6 -0
  153. package/extensions/nostr/package.json +1 -1
  154. package/extensions/open-prose/package.json +1 -1
  155. package/extensions/sat-mining/package.json +1 -1
  156. package/extensions/signal/package.json +1 -1
  157. package/extensions/synology-chat/package.json +1 -1
  158. package/extensions/tlon/package.json +1 -1
  159. package/extensions/twitch/CHANGELOG.md +6 -0
  160. package/extensions/twitch/package.json +1 -1
  161. package/extensions/voice-call/CHANGELOG.md +6 -0
  162. package/extensions/voice-call/package.json +1 -1
  163. package/extensions/zalo/CHANGELOG.md +6 -0
  164. package/extensions/zalo/package.json +1 -1
  165. package/extensions/zalouser/CHANGELOG.md +6 -0
  166. package/extensions/zalouser/package.json +1 -1
  167. 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,
@@ -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.58";
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.58",
3
- "commit": "90e7d5c7628e5b40333a1a31d4bfb34a1db9eb74",
4
- "builtAt": "2026-07-13T14:49:39.632Z"
2
+ "version": "0.1.59",
3
+ "commit": "52ee044888a4c31c2e7ee6958d86a61a1afdd081",
4
+ "builtAt": "2026-07-13T20:07:25.934Z"
5
5
  }
@@ -1 +1 @@
1
- 782c2af6b44d1581a8165b7eb7f8e771312faf6907d2df132f0c72d9d5b0cef6
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 };
@@ -2,6 +2,7 @@ import { CONFIG_DIR, isRecord, resolveUserPath } from "../../utils.js";
2
2
  import { resolveFasedAgentPackageRootSync } from "../../infra/fased-root.js";
3
3
  import { getPackageManifestMetadata } from "../../plugins/manifest.js";
4
4
  import { discoverFasedAgentPlugins } from "../../plugins/discovery.js";
5
+ import { channelDeliveryAllowsInstall, getChannelDelivery } from "../delivery.js";
5
6
  import fs from "node:fs";
6
7
  import path from "node:path";
7
8
 
@@ -152,20 +153,22 @@ function buildCatalogEntry(candidate) {
152
153
  if (!meta) {
153
154
  return null;
154
155
  }
156
+ const delivery = candidate.catalogSource === "official-catalog" ? "official-addon" : getChannelDelivery(id);
155
157
  const install = resolveInstallInfo({
156
158
  manifest,
157
159
  packageName: candidate.packageName,
158
160
  packageDir: candidate.packageDir,
159
161
  workspaceDir: candidate.workspaceDir
160
162
  });
161
- if (!install) {
163
+ if (!install && channelDeliveryAllowsInstall(delivery)) {
162
164
  return null;
163
165
  }
164
166
  return {
165
167
  id,
166
168
  meta,
169
+ delivery,
167
170
  catalogSource: candidate.catalogSource,
168
- install
171
+ install: channelDeliveryAllowsInstall(delivery) ? install ?? {} : {}
169
172
  };
170
173
  }
171
174
  function buildExternalCatalogEntry(entry, catalogSource) {
@@ -201,7 +204,7 @@ function formatChannelPluginCatalogSource(source) {
201
204
  }
202
205
  }
203
206
  function formatChannelPluginCatalogInstallBits(entry) {
204
- const bits = [formatChannelPluginCatalogSource(entry.catalogSource)];
207
+ const bits = [entry.delivery, formatChannelPluginCatalogSource(entry.catalogSource)];
205
208
  if (entry.install.expectedIntegrity) {
206
209
  bits.push("integrity pinned");
207
210
  }
@@ -211,10 +214,12 @@ function formatChannelPluginCatalogInstallBits(entry) {
211
214
  return bits;
212
215
  }
213
216
  function formatChannelPluginCatalogSelectionHint(entry) {
214
- return [...formatChannelPluginCatalogInstallBits(entry), "install"].join(" · ");
217
+ const action = entry.delivery === "official-addon" ? "install" : entry.delivery === "bundled" ? "enable bundled" : "docs required";
218
+ return [...formatChannelPluginCatalogInstallBits(entry), action].join(" · ");
215
219
  }
216
220
  function formatChannelPluginCatalogStatusLine(entry) {
217
- return `${entry.meta.label}: ${formatChannelPluginCatalogInstallBits(entry).join(", ")}, install plugin to enable`;
221
+ const next = entry.delivery === "official-addon" ? "install add-on to enable" : entry.delivery === "bundled" ? "enable bundled integration" : `follow ${entry.meta.docsPath}`;
222
+ return `${entry.meta.label}: ${formatChannelPluginCatalogInstallBits(entry).join(", ")}, ${next}`;
218
223
  }
219
224
  function buildChannelUiCatalog(plugins) {
220
225
  const entries = plugins.map((plugin) => {