@desplega.ai/agent-swarm 2.4.3 → 2.4.5
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.
- package/dist/{acp-adapter-1885dpr7.js → acp-adapter-2wdkktv6.js} +1 -2
- package/dist/{actions-pn76n32q.js → actions-c40ebcm4.js} +18 -18
- package/dist/{amp-adapter-af84rx1d.js → amp-adapter-wb67m95z.js} +2 -2
- package/dist/{app-6sv8mhzm.js → app-353vre8g.js} +3 -3
- package/dist/{assistant-sc2tf825.js → assistant-sj1njh23.js} +21 -21
- package/dist/{boot-reembed-y3m0ydzj.js → boot-reembed-b9c3az3c.js} +1 -1
- package/dist/{boot-reembed-gvxjs2py.js → boot-reembed-qdkvxeem.js} +1 -1
- package/dist/{boot-scrub-sweep-1j9mk05f.js → boot-scrub-sweep-m3wh8eks.js} +2 -2
- package/dist/{boot-seeds-37sp626b.js → boot-seeds-j2273s54.js} +4 -4
- package/dist/{claude-adapter-rp0jtnwr.js → claude-adapter-m7q0a085.js} +2 -2
- package/dist/{claude-managed-adapter-h2y889ge.js → claude-managed-adapter-5ptb6tzs.js} +2 -2
- package/dist/{claude-managed-setup-rdt248k7.js → claude-managed-setup-smrqk5j5.js} +3 -3
- package/dist/{claude-sdk-session-53rcw5we.js → claude-sdk-session-38xnz21e.js} +8284 -8267
- package/dist/{cli-6eyncg0y.js → cli-018r4jq6.js} +34 -6
- package/dist/{cli-sds5zzs8.js → cli-1f3qzw6y.js} +78 -12
- package/dist/{cli-f0p0f6ja.js → cli-1sp861s4.js} +7 -7
- package/dist/{cli-dm8p2dpf.js → cli-1syn2xy1.js} +10 -10
- package/dist/{cli-tkf4x6ha.js → cli-37j04k05.js} +11 -11
- package/dist/{cli-v87dr6e3.js → cli-3a45zcgm.js} +1 -1
- package/dist/{cli-1n9gdg56.js → cli-43x64hv3.js} +4 -4
- package/dist/{cli-p0qerd2r.js → cli-4zfqgjc5.js} +2 -2
- package/dist/{cli-aa3tb29r.js → cli-7c9qs530.js} +1 -1
- package/dist/{cli-9qtjfd60.js → cli-848hxdwj.js} +1 -1
- package/dist/{cli-1xsraagq.js → cli-94gwyg7m.js} +8 -8
- package/dist/{cli-0dxxwfkt.js → cli-9hstj09h.js} +17 -14
- package/dist/{cli-1012xb7j.js → cli-9yqgm9nd.js} +22 -22
- package/dist/{cli-pygdsgh8.js → cli-a92r1127.js} +1 -1
- package/dist/{cli-8vverzf7.js → cli-ba8ne1es.js} +5 -0
- package/dist/{cli-bxrqvpg5.js → cli-be2161h1.js} +7 -7
- package/dist/{cli-npfe9t1s.js → cli-bnes4z6b.js} +2 -2
- package/dist/{cli-aypbg9r2.js → cli-cxxe61f6.js} +1 -1
- package/dist/{cli-vq9gqarq.js → cli-dk44dxec.js} +1 -1
- package/dist/{cli-836ehxmt.js → cli-eww120g8.js} +3 -2
- package/dist/{cli-a0kcty51.js → cli-f01h25yt.js} +1 -1
- package/dist/{cli-mzkwkbdy.js → cli-f0g3pgvf.js} +1 -1
- package/dist/{cli-1ma335fz.js → cli-ftc1g5tj.js} +2 -2
- package/dist/{cli-4yef8ghv.js → cli-fv5hepyy.js} +3 -3
- package/dist/{cli-58vwn100.js → cli-g35m2xwm.js} +4 -4
- package/dist/{cli-qje9k2nh.js → cli-g9ypd5en.js} +12 -2
- package/dist/{cli-gx0j2khs.js → cli-j99azg3g.js} +3 -3
- package/dist/{cli-er83cjbn.js → cli-k8g16gz3.js} +416 -116
- package/dist/{cli-qp2m4btv.js → cli-kpw04va0.js} +2 -2
- package/dist/{cli-8y99kfey.js → cli-ms85309d.js} +33 -15
- package/dist/{cli-kgnkyabk.js → cli-n72rg53p.js} +1555 -645
- package/dist/{cli-e4d78xsv.js → cli-p14m2cnp.js} +1 -1
- package/dist/{cli-1eszr343.js → cli-qfxc84gh.js} +1 -1
- package/dist/{cli-wk28hzqn.js → cli-qwhy2qma.js} +1 -1
- package/dist/{cli-73ezfhha.js → cli-st8aw1m6.js} +228 -11
- package/dist/{cli-zvbb4n0e.js → cli-tw4p90jb.js} +92 -192
- package/dist/{cli-038fga5k.js → cli-v0yrfmdh.js} +148 -183
- package/dist/{cli-6aen3ezb.js → cli-v8fjakwf.js} +1 -1
- package/dist/{cli-99jez72r.js → cli-w9etnnxk.js} +6 -1
- package/dist/{cli-vcgscaan.js → cli-wt0jf9hm.js} +217 -80
- package/dist/{cli-s9rr4gr2.js → cli-xpa64rek.js} +1065 -305
- package/dist/{cli-h0mgxann.js → cli-z7d29rw9.js} +2 -2
- package/dist/cli.js +45 -20
- package/dist/{codex-adapter-2zrmab9b.js → codex-adapter-tn6k5mkg.js} +1 -1
- package/dist/{codex-session-runner-kbkz62vc.js → codex-session-runner-7vjt7jbw.js} +1 -1
- package/dist/{commands-hd574th6.js → commands-t7rz9146.js} +2 -2
- package/dist/{controller-pz5mcfg4.js → controller-m2jasma5.js} +2 -2
- package/dist/{controllers-connect-5rgq2hfk.js → controllers-connect-9ftpex99.js} +19 -19
- package/dist/{cursor-adapter-mgaprq0j.js → cursor-adapter-mjv79e4z.js} +1 -1
- package/dist/{db-6nf1207q.js → db-6sfrn9g3.js} +1 -1
- package/dist/{db-h06dxp05.js → db-rn673r06.js} +3 -3
- package/dist/{dispatcher-zthpy4m1.js → dispatcher-c155xz0p.js} +17 -17
- package/dist/{dsh-adapter-64dhw0j7.js → dsh-adapter-3mmszc1x.js} +1 -1
- package/dist/{external-channel-x01t7ke6.js → external-channel-35k6tkv8.js} +2 -2
- package/dist/{grok-adapter-h21jv594.js → grok-adapter-tfrq7tg1.js} +2 -3
- package/dist/handlers-7gw64dxw.js +39 -0
- package/dist/{heartbeat-zzfksckz.js → heartbeat-dyg4npkp.js} +20 -20
- package/dist/{hook-z4zhzj1f.js → hook-drspbwpe.js} +1 -1
- package/dist/{hook-3xfqhh2s.js → hook-x26b31bg.js} +1 -1
- package/dist/{http-q813tmya.js → http-pk972xyw.js} +571 -294
- package/dist/{index-va3y63es.js → index-6srwvd5b.js} +1 -2
- package/dist/{index-x8xbyn1t.js → index-arytgj5q.js} +1 -1
- package/dist/{index-wbbs14c5.js → index-bgdyvcnv.js} +17 -17
- package/dist/{index-s98037v0.js → index-cbxkmfc5.js} +1 -2
- package/dist/{index-c4ykd0f1.js → index-dr94zbnh.js} +13348 -11611
- package/dist/{index-m0a4ydqj.js → index-gabbcdn2.js} +17 -17
- package/dist/{index-220tk9bw.js → index-jwxkkex2.js} +139 -76
- package/dist/index-tfb26zhy.js +41 -0
- package/dist/{keepalive-y5t1my7m.js → keepalive-7yrng7px.js} +3 -3
- package/dist/{lead-2xwtq66b.js → lead-7e02z839.js} +29 -30
- package/dist/{maintenance-ybfsaedv.js → maintenance-e6cemdqt.js} +1 -1
- package/dist/{node-3v3f08f7.js → node-de6akczr.js} +10 -9
- package/dist/{oauth-refresh-sweep-909jmn12.js → oauth-refresh-sweep-yw3xdbcj.js} +2 -2
- package/dist/{onboard-xn6fkkys.js → onboard-0a9y5yrc.js} +2 -2
- package/dist/{otel-impl-e6mn0z13.js → otel-impl-trjpkfb7.js} +1 -1
- package/dist/{pricing-refresh-ygd362ep.js → pricing-refresh-d2b5my0y.js} +3 -3
- package/dist/{rbac-roles-mb470p4e.js → rbac-roles-hey3yv9d.js} +2 -2
- package/dist/{rbac-roles-c9axvfnz.js → rbac-roles-nxh5ahwk.js} +2 -2
- package/dist/{registry-rxw10xzg.js → registry-ajhexe44.js} +1 -1
- package/dist/{render-v2-g0306nh1.js → render-v2-rr3p2atg.js} +3 -3
- package/dist/{resume-v315hnq6.js → resume-2efkf1s1.js} +5 -5
- package/dist/{session-access-2zg285a1.js → session-access-s2mttxpw.js} +6 -4
- package/dist/{setup-a4mtf02k.js → setup-vypma5yt.js} +1 -1
- package/dist/{work-objects-9fr0fgtn.js → work-objects-rvhckdkp.js} +20 -20
- package/dist/{worker-qae22jeb.js → worker-5snytpbd.js} +29 -30
- package/dist/worker-token-xf11yyds.js +136 -0
- package/openapi.json +303 -13
- package/package.json +8 -8
- package/src/apps/action-runner.ts +4 -0
- package/src/apps/catalog.generated.json +209 -4
- package/src/apps/page-validator.ts +21 -3
- package/src/be/chunking.ts +42 -9
- package/src/be/db/tasks/draft-text.ts +15 -0
- package/src/be/db/tasks/read.ts +14 -1
- package/src/be/db.ts +5 -1
- package/src/be/memory/index-content.ts +36 -17
- package/src/be/memory/providers/openai-embedding.ts +115 -61
- package/src/be/memory/providers/sqlite-store.ts +69 -23
- package/src/be/memory/reranker.ts +31 -1
- package/src/be/memory/search-candidates.ts +47 -0
- package/src/be/memory/types.ts +14 -0
- package/src/be/migrations/232_agent_session_tokens.sql +41 -0
- package/src/be/scripts/typecheck.ts +2 -0
- package/src/be/seed-scripts/catalog/heartbeat-jev-gate.ts +116 -55
- package/src/be/seed-scripts/index.ts +2 -2
- package/src/be/swarm-config-guard.ts +40 -1
- package/src/be/task-attachment-store.ts +30 -0
- package/src/be/users.ts +169 -12
- package/src/cli.tsx +24 -0
- package/src/commands/worker-token.ts +164 -0
- package/src/extensions/catalog.generated.json +4 -4
- package/src/extensions/contract-types.generated.ts +1 -1
- package/src/extensions/contract.ts +7 -0
- package/src/fs/provider.ts +13 -1
- package/src/heartbeat/heartbeat.ts +31 -11
- package/src/http/apps.ts +43 -5
- package/src/http/codex-oauth-keep-warm.ts +27 -9
- package/src/http/config.ts +5 -3
- package/src/http/core.ts +2 -0
- package/src/http/fs.ts +54 -34
- package/src/http/mcp-body.ts +37 -0
- package/src/http/mcp-user.ts +3 -5
- package/src/http/mcp.ts +6 -7
- package/src/http/memory.ts +26 -15
- package/src/http/page-proxy.ts +61 -5
- package/src/http/pages-public.ts +27 -44
- package/src/http/pages.ts +4 -4
- package/src/http/script-runs.ts +2 -0
- package/src/http/session-access.ts +51 -2
- package/src/http/sessions.ts +249 -10
- package/src/http/tasks.ts +4 -32
- package/src/http/users.ts +12 -1
- package/src/integrations/chat-sdk/adapters.ts +7 -3
- package/src/integrations/chat-sdk/attachments.ts +90 -12
- package/src/integrations/chat-sdk/facts.ts +120 -0
- package/src/integrations/chat-sdk/inbound.ts +156 -8
- package/src/integrations/chat-sdk/limits.ts +24 -0
- package/src/integrations/chat-sdk/outbound-files.ts +186 -0
- package/src/integrations/chat-sdk/outbound.ts +234 -4
- package/src/integrations/chat-sdk/relay.ts +4 -1
- package/src/integrations/chat-sdk/router.ts +28 -2
- package/src/integrations/chat-sdk/steering.ts +9 -0
- package/src/integrations/chat-sdk/templates.ts +14 -0
- package/src/integrations/chat-sdk/thread-buffer.ts +4 -0
- package/src/mcp-limits.ts +20 -0
- package/src/pages/browser-sdk.ts +8 -3
- package/src/pages/feedback-overlay.ts +1 -1
- package/src/providers/acp-adapter.ts +33 -13
- package/src/providers/acp-swarm-events.ts +1 -1
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/codex-adapter.ts +106 -119
- package/src/providers/codex-agents-md.ts +35 -229
- package/src/providers/codex-oauth/storage.ts +1 -1
- package/src/providers/cursor-adapter.ts +1 -1
- package/src/rbac/legacy-policy.ts +3 -1
- package/src/rbac/permissions.ts +4 -0
- package/src/realtime/transport.ts +1 -2
- package/src/script-workflows/workflow-ctx.ts +1 -0
- package/src/scripts-runtime/types/stdlib.d.ts +2 -0
- package/src/scripts-runtime/types/swarm-extension.d.ts +8 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +2 -0
- package/src/server-user.ts +2 -0
- package/src/server.ts +2 -0
- package/src/slack/assistant.ts +2 -2
- package/src/slack/files.ts +2 -0
- package/src/slack/handlers.ts +4 -4
- package/src/slack/inbound-files.ts +39 -6
- package/src/slack/thread-buffer.ts +2 -1
- package/src/tasks/task-terminal-effects.ts +21 -17
- package/src/tests/acp-adapter.test.ts +10 -23
- package/src/tests/acp-fake-agent.ts +36 -0
- package/src/tests/acp-swarm-events.test.ts +1 -1
- package/src/tests/agent-session-tokens.test.ts +452 -0
- package/src/tests/apps-action-parent-task.test.ts +295 -0
- package/src/tests/apps-card-grid.test.ts +197 -0
- package/src/tests/apps-catalog-additions.test.ts +120 -0
- package/src/tests/apps-tree.test.ts +129 -0
- package/src/tests/chat-sdk-attachments-reply.test.ts +52 -0
- package/src/tests/chat-sdk-config.test.ts +11 -0
- package/src/tests/chat-sdk-facts.test.ts +23 -0
- package/src/tests/chat-sdk-inbound.test.ts +558 -4
- package/src/tests/chat-sdk-outbound-files.test.ts +652 -0
- package/src/tests/codex-adapter.test.ts +167 -242
- package/src/tests/codex-oauth-keep-warm.test.ts +85 -1
- package/src/tests/config-api-only-keys.test.ts +9 -0
- package/src/tests/config-session-auth.test.ts +14 -0
- package/src/tests/cors-allowlist.test.ts +1 -1
- package/src/tests/docs-index-footprint.test.js +2 -2
- package/src/tests/extensions-example-slack-reply-gate.test.ts +262 -91
- package/src/tests/grok-adapter.test.ts +3 -3
- package/src/tests/heartbeat-checklist.test.ts +33 -0
- package/src/tests/heartbeat-jev-gate-credentials.test.ts +44 -0
- package/src/tests/heartbeat-jev-gate.test.ts +265 -1
- package/src/tests/kv-page-proxy.test.ts +91 -5
- package/src/tests/launch-password-rejection.test.ts +2 -2
- package/src/tests/mcp-input-caps.test.ts +294 -0
- package/src/tests/memory-chunked-search-starvation.test.ts +200 -0
- package/src/tests/memory-embedding-input-cap.test.ts +114 -0
- package/src/tests/memory.test.ts +14 -0
- package/src/tests/migration-232-agent-session-tokens.test.ts +67 -0
- package/src/tests/page-guest-session.test.ts +19 -8
- package/src/tests/page-proxy-authed.test.ts +1 -1
- package/src/tests/page-proxy.test.ts +17 -10
- package/src/tests/page-session.test.ts +102 -1
- package/src/tests/pages-authed-mode.test.ts +82 -12
- package/src/tests/pages-password-mode.test.ts +5 -5
- package/src/tests/rbac-engine.test.ts +1 -0
- package/src/tests/realtime-transport.test.ts +13 -7
- package/src/tests/runtime-child-token-cleanup.test.ts +3 -3
- package/src/tests/script-connections.test.ts +2 -0
- package/src/tests/script-runs-http.test.ts +84 -0
- package/src/tests/scripts-http.test.ts +10 -1
- package/src/tests/session-route-posture.test.ts +2 -0
- package/src/tests/swarm-config-export-to-env.test.ts +22 -3
- package/src/tests/task-audio-transcription.test.ts +299 -0
- package/src/tests/task-completion-memory-chunking.test.ts +434 -0
- package/src/tests/task-terminal-secret-scrub.test.ts +6 -1
- package/src/tests/transcription.test.ts +299 -0
- package/src/tests/worker-token-cli.test.ts +76 -0
- package/src/tests/workflow-executors.test.ts +4 -2
- package/src/tests/workflow-system-one-decision-providers.test.ts +98 -1
- package/src/tests/workflow-system-one-decision.test.ts +2 -1
- package/src/tests/workflow-system-one-extraction.test.ts +805 -0
- package/src/tools/chat-access.ts +10 -0
- package/src/tools/chat-post.ts +31 -11
- package/src/tools/chat-reply.ts +32 -10
- package/src/tools/memory-search.ts +3 -1
- package/src/tools/system-one-decide.ts +17 -4
- package/src/types.ts +8 -1
- package/src/utils/config-env-export.ts +3 -1
- package/src/utils/page-session.ts +133 -20
- package/src/utils/request-auth-context.ts +2 -1
- package/src/utils/transcription.ts +246 -0
- package/src/workflows/definition.ts +7 -1
- package/src/workflows/engine.ts +18 -12
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/system-one-decision.ts +84 -262
- package/src/workflows/executors/system-one-extract-wire.ts +57 -0
- package/src/workflows/executors/system-one-extraction.ts +830 -0
- package/src/workflows/executors/system-one-providers.ts +316 -114
- package/src/workflows/executors/system-one-transport.ts +264 -0
- package/templates/extensions/slack-reply-gate/README.md +24 -22
- package/templates/extensions/slack-reply-gate/hooks.ts +146 -95
- package/templates/extensions/slack-reply-gate/manifest.json +2 -2
- package/templates/official/lead/HEARTBEAT.md +1 -1
- package/templates/skills/apps/SKILL.md +31 -7
- package/templates/skills/apps/content.md +31 -7
- package/templates/skills/chat-sdk/content.md +6 -2
- package/templates/skills/code-quality/content.md +2 -1
- package/templates/skills/heartbeat-runbook/content.md +8 -8
- package/templates/skills/pages/content.md +6 -4
- package/templates/skills/swarm-scripts/SKILL.md +2 -2
- package/templates/skills/swarm-scripts/content.md +2 -2
- package/dist/cli-v1sjhn52.js +0 -7
- package/dist/handlers-2qjw434w.js +0 -39
- package/dist/index-d0g18bax.js +0 -41
|
@@ -67,6 +67,7 @@ declare module "swarm-extension" {
|
|
|
67
67
|
sourceTaskId?: string | undefined;
|
|
68
68
|
outputSchema?: Record<string, unknown> | undefined;
|
|
69
69
|
inheritParentOutputSchema?: boolean | undefined;
|
|
70
|
+
inheritParentRequester?: boolean | undefined;
|
|
70
71
|
inheritParentRoutingAffinity?: boolean | undefined;
|
|
71
72
|
inheritParentFollowUpConfig?: boolean | undefined;
|
|
72
73
|
followUpConfig?:
|
|
@@ -485,8 +486,15 @@ declare module "swarm-extension" {
|
|
|
485
486
|
userName?: string;
|
|
486
487
|
/** The buffered messages, joined. */
|
|
487
488
|
text: string;
|
|
489
|
+
/** True for an @mention and for a reply to one of the bot's messages. */
|
|
488
490
|
botMentioned: boolean;
|
|
489
491
|
isDirectMessage: boolean;
|
|
492
|
+
/** Platform chat type, such as Telegram `private`, `group`, `supergroup` or `channel`. */
|
|
493
|
+
chatType?: string;
|
|
494
|
+
/** Set for a Telegram supergroup with topics. */
|
|
495
|
+
isForum?: boolean;
|
|
496
|
+
/** A buffered message replies to one of the bot's own messages. */
|
|
497
|
+
replyToBot: boolean;
|
|
490
498
|
/** Set when earlier swarm tasks exist in this thread. */
|
|
491
499
|
threadContext?: {
|
|
492
500
|
adapter: string;
|
package/src/server-user.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as z from "zod";
|
|
|
4
4
|
import pkg from "../package.json";
|
|
5
5
|
import { enqueueAdmissionRow } from "./be/rbac-audit";
|
|
6
6
|
import { getUserGrant } from "./be/rbac-roles";
|
|
7
|
+
import { MCP_MAX_TOOL_INPUT_ELEMENTS } from "./mcp-limits";
|
|
7
8
|
import {
|
|
8
9
|
type AdmissionRbac,
|
|
9
10
|
decideToolAdmission,
|
|
@@ -107,6 +108,7 @@ export function createUserServer(user: User): McpServer {
|
|
|
107
108
|
capabilities: {
|
|
108
109
|
logging: {},
|
|
109
110
|
},
|
|
111
|
+
maxToolInputElements: MCP_MAX_TOOL_INPUT_ELEMENTS,
|
|
110
112
|
},
|
|
111
113
|
);
|
|
112
114
|
|
package/src/server.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { isSteeringEnabled } from "./be/steering";
|
|
|
7
7
|
import { registerGithubTaskReactions } from "./github/task-reactions";
|
|
8
8
|
import { loadGlobalConfigsIntoEnv } from "./http/core";
|
|
9
9
|
import { isChatSdkEnabled } from "./integrations/chat-sdk/config";
|
|
10
|
+
import { MCP_MAX_TOOL_INPUT_ELEMENTS } from "./mcp-limits";
|
|
10
11
|
import { resolveTemplate } from "./prompts/resolver";
|
|
11
12
|
import { isRbacEnabled } from "./rbac";
|
|
12
13
|
import { getSlackConfiguration } from "./slack/config";
|
|
@@ -450,6 +451,7 @@ export async function createServer(
|
|
|
450
451
|
capabilities: {
|
|
451
452
|
logging: {},
|
|
452
453
|
},
|
|
454
|
+
maxToolInputElements: MCP_MAX_TOOL_INPUT_ELEMENTS,
|
|
453
455
|
},
|
|
454
456
|
);
|
|
455
457
|
|
package/src/slack/assistant.ts
CHANGED
|
@@ -204,13 +204,13 @@ export function createAssistant(): Assistant {
|
|
|
204
204
|
// Fetch shared files before the task text is final: a file that can't be
|
|
205
205
|
// downloaded is flagged in it.
|
|
206
206
|
if (files?.length) await safeSetStatus("Downloading attachments...");
|
|
207
|
-
await using inbound = await fetchSlackFiles(client, files);
|
|
207
|
+
await using inbound = await fetchSlackFiles(client, files, { transcribe: true });
|
|
208
208
|
// Any in-body `<@U…>` mention the requester typed is rewritten via
|
|
209
209
|
// the identity primitive before it reaches agent-visible task text —
|
|
210
210
|
// never a raw Slack ID. Bot-mention routing checks above use the
|
|
211
211
|
// raw `messageText`, not this rendered copy.
|
|
212
212
|
const renderedMessageText = await rewriteSlackMentions(
|
|
213
|
-
buildEffectiveText(messageText, inbound.files, inbound.failed),
|
|
213
|
+
buildEffectiveText(messageText, inbound.files, inbound.failed, inbound.notes),
|
|
214
214
|
cachedBotUserId ?? undefined,
|
|
215
215
|
);
|
|
216
216
|
|
package/src/slack/files.ts
CHANGED
package/src/slack/handlers.ts
CHANGED
|
@@ -702,8 +702,8 @@ export function registerMessageHandler(app: App): void {
|
|
|
702
702
|
return ignoreSlackInbound("rate_limited");
|
|
703
703
|
}
|
|
704
704
|
|
|
705
|
-
await using inbound = await fetchSlackFiles(client, msg.files);
|
|
706
|
-
const taskText = buildEffectiveText(msg.text, inbound.files, inbound.failed);
|
|
705
|
+
await using inbound = await fetchSlackFiles(client, msg.files, { transcribe: true });
|
|
706
|
+
const taskText = buildEffectiveText(msg.text, inbound.files, inbound.failed, inbound.notes);
|
|
707
707
|
const taskDescription = isImplicitMention
|
|
708
708
|
? taskText
|
|
709
709
|
: extractTaskFromMessage(taskText, botUserId);
|
|
@@ -778,9 +778,9 @@ export function registerMessageHandler(app: App): void {
|
|
|
778
778
|
}
|
|
779
779
|
|
|
780
780
|
// Extract task description (the text plus a `[File: …]` line per attachment)
|
|
781
|
-
await using inbound = await fetchSlackFiles(client, msg.files);
|
|
781
|
+
await using inbound = await fetchSlackFiles(client, msg.files, { transcribe: true });
|
|
782
782
|
const taskDescription = extractTaskFromMessage(
|
|
783
|
-
buildEffectiveText(msg.text, inbound.files, inbound.failed),
|
|
783
|
+
buildEffectiveText(msg.text, inbound.files, inbound.failed, inbound.notes),
|
|
784
784
|
botUserId,
|
|
785
785
|
);
|
|
786
786
|
if (!taskDescription) {
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* could not be attached — never dropped silently. A download failure is
|
|
14
14
|
* also flagged on that line; a storage failure happens after the text is
|
|
15
15
|
* written, so it shows up only in the reply and in the missing attachment.
|
|
16
|
+
* Audio files (voice clips) a user shares get their transcript on the next
|
|
17
|
+
* line when transcription is configured, and keep the audio attached.
|
|
16
18
|
*/
|
|
17
19
|
import { mkdtemp, rm } from "node:fs/promises";
|
|
18
20
|
import { tmpdir } from "node:os";
|
|
@@ -27,6 +29,7 @@ import { createTaskWithSiblingAwareness } from "../tasks/sibling-awareness";
|
|
|
27
29
|
import type { AgentTask, CreateTaskOptions, TaskAttachment } from "../types";
|
|
28
30
|
import { scrubSecrets } from "../utils/secret-scrubber";
|
|
29
31
|
import { taskAttachmentFetchCommand } from "../utils/task-attachment-links";
|
|
32
|
+
import { transcribeAudioNotes } from "../utils/transcription";
|
|
30
33
|
import { getFileInfo, type SlackFile } from "./files";
|
|
31
34
|
import { noteSlackInboundSideEffect } from "./inbound-dispatch";
|
|
32
35
|
// Side-effect import: registers all Slack event templates in the in-memory registry
|
|
@@ -73,6 +76,8 @@ export type InboundSlackFiles = {
|
|
|
73
76
|
files: SlackFile[];
|
|
74
77
|
fetched: FetchedSlackFile[];
|
|
75
78
|
failed: SlackFileFailure[];
|
|
79
|
+
/** Task-text note per audio file id (a transcript), filled when fetched with `transcribe`. */
|
|
80
|
+
notes?: Map<string, string>;
|
|
76
81
|
/** Deletes the downloaded copies; hold the batch with `await using`. */
|
|
77
82
|
[Symbol.asyncDispose](): Promise<void>;
|
|
78
83
|
};
|
|
@@ -96,9 +101,14 @@ export function formatFileSize(bytes: number): string {
|
|
|
96
101
|
* Build a text representation of file attachments for inclusion in messages.
|
|
97
102
|
* Each file is formatted as: [File: filename.ext (mimetype, size) id=FILE_ID],
|
|
98
103
|
* followed by `(not attached: <reason>)` when the file never made it into the
|
|
99
|
-
* task's attachments
|
|
104
|
+
* task's attachments, and by the file's note (a voice-clip transcript) on the
|
|
105
|
+
* next line.
|
|
100
106
|
*/
|
|
101
|
-
export function buildAttachmentText(
|
|
107
|
+
export function buildAttachmentText(
|
|
108
|
+
files: SlackFile[],
|
|
109
|
+
failed: SlackFileFailure[] = [],
|
|
110
|
+
notes: Map<string, string> = new Map(),
|
|
111
|
+
): string {
|
|
102
112
|
const reasons = new Map(failed.map((f) => [f.file.id, f.reason]));
|
|
103
113
|
return files
|
|
104
114
|
.map((f) => {
|
|
@@ -106,7 +116,8 @@ export function buildAttachmentText(files: SlackFile[], failed: SlackFileFailure
|
|
|
106
116
|
const size = typeof f.size === "number" ? formatFileSize(f.size) : "unknown size";
|
|
107
117
|
const line = `[File: ${f.name ?? f.id} (${f.mimetype ?? "unknown type"}, ${size}) id=${f.id}]`;
|
|
108
118
|
const reason = reasons.get(f.id);
|
|
109
|
-
|
|
119
|
+
const note = notes.get(f.id);
|
|
120
|
+
return [reason ? `${line} (not attached: ${reason})` : line, note].filter(Boolean).join("\n");
|
|
110
121
|
})
|
|
111
122
|
.join("\n");
|
|
112
123
|
}
|
|
@@ -121,15 +132,16 @@ export function buildEffectiveText(
|
|
|
121
132
|
text: string | undefined,
|
|
122
133
|
files?: SlackFile[],
|
|
123
134
|
failed?: SlackFileFailure[],
|
|
135
|
+
notes?: Map<string, string>,
|
|
124
136
|
): string {
|
|
125
137
|
const hasText = !!text?.trim();
|
|
126
138
|
const hasFiles = files && files.length > 0;
|
|
127
139
|
|
|
128
140
|
if (hasText && hasFiles) {
|
|
129
|
-
return `${text}\n\n${buildAttachmentText(files, failed)}`;
|
|
141
|
+
return `${text}\n\n${buildAttachmentText(files, failed, notes)}`;
|
|
130
142
|
}
|
|
131
143
|
if (hasFiles) {
|
|
132
|
-
return buildAttachmentText(files, failed);
|
|
144
|
+
return buildAttachmentText(files, failed, notes);
|
|
133
145
|
}
|
|
134
146
|
return text || "";
|
|
135
147
|
}
|
|
@@ -147,11 +159,14 @@ export function bufferedFileFailures(files: SlackFile[] | undefined): SlackFileF
|
|
|
147
159
|
* Download every file on a Slack message with the bot token, each to its own
|
|
148
160
|
* temp file. Never throws: a file that can't be fetched lands in `failed` with
|
|
149
161
|
* a reason the user and the agent can read. Hold the result with `await using`
|
|
150
|
-
* so the temp files go away with it.
|
|
162
|
+
* so the temp files go away with it. With `transcribe`, every downloaded audio
|
|
163
|
+
* file also gets a `notes` entry: its transcript, the failure, or a line saying
|
|
164
|
+
* no provider is configured.
|
|
151
165
|
*/
|
|
152
166
|
export async function fetchSlackFiles(
|
|
153
167
|
client: WebClient,
|
|
154
168
|
files: SlackFile[] | undefined,
|
|
169
|
+
options: { transcribe?: boolean } = {},
|
|
155
170
|
): Promise<InboundSlackFiles> {
|
|
156
171
|
let dir: string | undefined;
|
|
157
172
|
const result: InboundSlackFiles = {
|
|
@@ -182,9 +197,27 @@ export async function fetchSlackFiles(
|
|
|
182
197
|
result.fetched.push({ file, ...outcome });
|
|
183
198
|
}
|
|
184
199
|
}
|
|
200
|
+
if (options.transcribe) {
|
|
201
|
+
result.notes = await transcribeAudioNotes(
|
|
202
|
+
result.fetched
|
|
203
|
+
.filter(({ file }) => isSlackAudio(file))
|
|
204
|
+
.map(({ file, path }) => ({
|
|
205
|
+
key: file.id,
|
|
206
|
+
name: file.name ?? file.id,
|
|
207
|
+
data: Bun.file(path),
|
|
208
|
+
mimeType: file.mimetype,
|
|
209
|
+
})),
|
|
210
|
+
"[Slack]",
|
|
211
|
+
);
|
|
212
|
+
}
|
|
185
213
|
return result;
|
|
186
214
|
}
|
|
187
215
|
|
|
216
|
+
/** An audio file, or a voice clip recorded in Slack (its MIME type can read `video/…`). */
|
|
217
|
+
function isSlackAudio(file: SlackFile): boolean {
|
|
218
|
+
return file.subtype === "slack_audio" || Boolean(file.mimetype?.startsWith("audio/"));
|
|
219
|
+
}
|
|
220
|
+
|
|
188
221
|
/** Does the start of an HTML response read like Slack's sign-in page? */
|
|
189
222
|
function looksLikeSignIn(head: Uint8Array[]): boolean {
|
|
190
223
|
const joined = new Uint8Array(head.reduce((total, part) => total + part.byteLength, 0));
|
|
@@ -177,7 +177,7 @@ async function slackFlush(
|
|
|
177
177
|
const app = getSlackApp();
|
|
178
178
|
const files = items.flatMap((item) => item.files ?? []);
|
|
179
179
|
await using inbound = app
|
|
180
|
-
? await fetchSlackFiles(app.client, files)
|
|
180
|
+
? await fetchSlackFiles(app.client, files, { transcribe: true })
|
|
181
181
|
: {
|
|
182
182
|
files,
|
|
183
183
|
fetched: [],
|
|
@@ -196,6 +196,7 @@ async function slackFlush(
|
|
|
196
196
|
item.text,
|
|
197
197
|
item.files?.map((file) => resolvedFiles.get(file.id) ?? file),
|
|
198
198
|
inbound.failed,
|
|
199
|
+
inbound.notes,
|
|
199
200
|
),
|
|
200
201
|
)
|
|
201
202
|
.join("\n---\n"),
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import { getSessionLogsByTaskId } from "@/be/db";
|
|
19
|
-
import {
|
|
19
|
+
import { indexMemoryContent, taskCompletionMemoryKey } from "@/be/memory/index-content";
|
|
20
20
|
import { getRetrievalsForTask } from "@/be/memory/raters/retrieval";
|
|
21
21
|
import { runServerRaters } from "@/be/memory/raters/run-server-raters";
|
|
22
22
|
import { shouldPersistTaskCompletionMemory } from "@/memory/automatic-task-gate";
|
|
@@ -55,21 +55,22 @@ export async function runTaskTerminalEffects(args: {
|
|
|
55
55
|
// Skip indexing if there's truly no content
|
|
56
56
|
if (taskContent.length < 30) return;
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
// Same path as memory-store: chunk, store, and embed each chunk, so a
|
|
59
|
+
// long output never meets the embedding model's input cap. The per-task
|
|
60
|
+
// key makes the chunks one document, like a keyed manual memory, and a
|
|
61
|
+
// repeat write for the task replaces that document atomically.
|
|
62
|
+
const key = taskCompletionMemoryKey(taskId);
|
|
63
|
+
await indexMemoryContent({
|
|
62
64
|
agentId: agentId ?? null,
|
|
63
65
|
content: taskContent,
|
|
64
66
|
name: `Task: ${safeTask.slice(0, 80)}`,
|
|
65
67
|
scope: "agent",
|
|
66
68
|
source: "task_completion",
|
|
67
69
|
sourceTaskId: taskId,
|
|
70
|
+
key,
|
|
71
|
+
intent: "task completion memory",
|
|
72
|
+
replaceExisting: true,
|
|
68
73
|
});
|
|
69
|
-
const embedding = await provider.embed(taskContent);
|
|
70
|
-
if (embedding) {
|
|
71
|
-
await store.updateEmbedding(memory.id, embedding, provider.name);
|
|
72
|
-
}
|
|
73
74
|
|
|
74
75
|
// Auto-promote high-value completions to swarm memory (P3)
|
|
75
76
|
const shouldShareWithSwarm =
|
|
@@ -80,24 +81,27 @@ export async function runTaskTerminalEffects(args: {
|
|
|
80
81
|
|
|
81
82
|
if (shouldShareWithSwarm) {
|
|
82
83
|
try {
|
|
83
|
-
|
|
84
|
+
await indexMemoryContent({
|
|
84
85
|
agentId: agentId ?? null,
|
|
85
|
-
scope: "swarm",
|
|
86
|
-
name: `Shared: ${safeTask.slice(0, 80)}`,
|
|
87
86
|
content: `Task completed by agent ${agentId}:\n\n${taskContent}`,
|
|
87
|
+
name: `Shared: ${safeTask.slice(0, 80)}`,
|
|
88
|
+
scope: "swarm",
|
|
88
89
|
source: "task_completion",
|
|
89
90
|
sourceTaskId: taskId,
|
|
91
|
+
key,
|
|
92
|
+
intent: "task completion memory",
|
|
93
|
+
replaceExisting: true,
|
|
90
94
|
});
|
|
91
|
-
const swarmEmbedding = await provider.embed(taskContent);
|
|
92
|
-
if (swarmEmbedding) {
|
|
93
|
-
await store.updateEmbedding(swarmMemory.id, swarmEmbedding, provider.name);
|
|
94
|
-
}
|
|
95
95
|
} catch {
|
|
96
96
|
// Non-blocking — swarm memory promotion failure is not critical
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
} catch {
|
|
99
|
+
} catch (err) {
|
|
100
100
|
// Non-blocking — task completion memory failure should not affect task status
|
|
101
|
+
console.error(
|
|
102
|
+
"[task-terminal-effects] task completion memory write failed:",
|
|
103
|
+
scrubSecrets(err instanceof Error ? err.message : String(err)),
|
|
104
|
+
);
|
|
101
105
|
}
|
|
102
106
|
})().catch((err) =>
|
|
103
107
|
console.error(
|
|
@@ -3,7 +3,7 @@ import { chmodSync, existsSync, mkdirSync, mkdtempSync, rmSync } from "node:fs";
|
|
|
3
3
|
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
-
import type { Usage } from "@agentclientprotocol/sdk";
|
|
6
|
+
import type { Usage } from "@agentclientprotocol/sdk/unstable";
|
|
7
7
|
import { normalizeSessionLogs } from "../../apps/ui/src/logs-parser";
|
|
8
8
|
import {
|
|
9
9
|
closeDb,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
resolveAcpTarget,
|
|
30
30
|
} from "../providers/acp-targets";
|
|
31
31
|
import type { ProviderEvent, ProviderSessionConfig } from "../providers/types";
|
|
32
|
+
import { ACP_SDK_PATH, serveFakeAcpAgent } from "./acp-fake-agent";
|
|
32
33
|
import { listenOnFreePort } from "./test-net";
|
|
33
34
|
|
|
34
35
|
const tmpDirs: string[] = [];
|
|
@@ -148,16 +149,11 @@ describe("ACPAdapter", () => {
|
|
|
148
149
|
}) => {
|
|
149
150
|
const cwd = makeTempDir();
|
|
150
151
|
const agentPath = join(cwd, "fake-acp-agent.ts");
|
|
151
|
-
const sdkPath = join(process.cwd(), "node_modules/@agentclientprotocol/sdk/dist/acp.js");
|
|
152
152
|
await Bun.write(
|
|
153
153
|
agentPath,
|
|
154
154
|
`
|
|
155
155
|
import { Readable, Writable } from "node:stream";
|
|
156
|
-
import {
|
|
157
|
-
AgentSideConnection,
|
|
158
|
-
PROTOCOL_VERSION,
|
|
159
|
-
ndJsonStream,
|
|
160
|
-
} from "${sdkPath}";
|
|
156
|
+
import { PROTOCOL_VERSION, agent, methods, ndJsonStream } from "${ACP_SDK_PATH}";
|
|
161
157
|
|
|
162
158
|
class FakeAgent {
|
|
163
159
|
constructor(connection) {
|
|
@@ -313,10 +309,7 @@ class FakeAgent {
|
|
|
313
309
|
async cancel() {}
|
|
314
310
|
}
|
|
315
311
|
|
|
316
|
-
|
|
317
|
-
const output = Readable.toWeb(process.stdin);
|
|
318
|
-
const stream = ndJsonStream(input, output);
|
|
319
|
-
new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
312
|
+
${serveFakeAcpAgent("FakeAgent")}
|
|
320
313
|
`,
|
|
321
314
|
);
|
|
322
315
|
|
|
@@ -952,7 +945,6 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
|
952
945
|
const binDir = makeTempDir();
|
|
953
946
|
const captureFile = join(binDir, "capture.json");
|
|
954
947
|
const agentPath = join(binDir, "fake-copilot-acp.ts");
|
|
955
|
-
const sdkPath = join(process.cwd(), "node_modules/@agentclientprotocol/sdk/dist/acp.js");
|
|
956
948
|
const repoAgentsMd = "# Repo rules\nKeep this file as is.\n";
|
|
957
949
|
await Bun.write(join(cwd, "AGENTS.md"), repoAgentsMd);
|
|
958
950
|
await Bun.write(
|
|
@@ -961,7 +953,7 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
|
961
953
|
import { readFileSync } from "node:fs";
|
|
962
954
|
import { join } from "node:path";
|
|
963
955
|
import { Readable, Writable } from "node:stream";
|
|
964
|
-
import {
|
|
956
|
+
import { PROTOCOL_VERSION, agent, methods, ndJsonStream } from "${ACP_SDK_PATH}";
|
|
965
957
|
class FakeCopilot {
|
|
966
958
|
constructor(connection) { this.connection = connection; }
|
|
967
959
|
async initialize() {
|
|
@@ -986,8 +978,7 @@ class FakeCopilot {
|
|
|
986
978
|
}
|
|
987
979
|
async cancel() {}
|
|
988
980
|
}
|
|
989
|
-
|
|
990
|
-
new AgentSideConnection((connection) => new FakeCopilot(connection), stream);
|
|
981
|
+
${serveFakeAcpAgent("FakeCopilot")}
|
|
991
982
|
`,
|
|
992
983
|
);
|
|
993
984
|
const copilotStub = join(binDir, "copilot");
|
|
@@ -1191,7 +1182,6 @@ new AgentSideConnection((connection) => new FakeCopilot(connection), stream);
|
|
|
1191
1182
|
test("completes before the revoke response and logs a failed revocation", async () => {
|
|
1192
1183
|
const cwd = makeTempDir();
|
|
1193
1184
|
const agentPath = join(cwd, "fake-acp-ephem-agent.ts");
|
|
1194
|
-
const sdkPath = join(process.cwd(), "node_modules/@agentclientprotocol/sdk/dist/acp.js");
|
|
1195
1185
|
|
|
1196
1186
|
const captureFile = join(cwd, "captured-auth.txt");
|
|
1197
1187
|
|
|
@@ -1199,7 +1189,7 @@ new AgentSideConnection((connection) => new FakeCopilot(connection), stream);
|
|
|
1199
1189
|
agentPath,
|
|
1200
1190
|
`
|
|
1201
1191
|
import { Readable, Writable } from "node:stream";
|
|
1202
|
-
import {
|
|
1192
|
+
import { PROTOCOL_VERSION, agent, methods, ndJsonStream } from "${ACP_SDK_PATH}";
|
|
1203
1193
|
class FakeAgent {
|
|
1204
1194
|
constructor(connection) { this.connection = connection; }
|
|
1205
1195
|
async initialize() {
|
|
@@ -1223,8 +1213,7 @@ class FakeAgent {
|
|
|
1223
1213
|
}
|
|
1224
1214
|
async cancel() {}
|
|
1225
1215
|
}
|
|
1226
|
-
|
|
1227
|
-
new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
1216
|
+
${serveFakeAcpAgent("FakeAgent")}
|
|
1228
1217
|
`,
|
|
1229
1218
|
);
|
|
1230
1219
|
|
|
@@ -1361,12 +1350,11 @@ new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
|
1361
1350
|
])("$name", async ({ costs, totalCostUsd, costSource }) => {
|
|
1362
1351
|
const cwd = makeTempDir();
|
|
1363
1352
|
const agentPath = join(cwd, "fake-acp-cost-agent.ts");
|
|
1364
|
-
const sdkPath = join(process.cwd(), "node_modules/@agentclientprotocol/sdk/dist/acp.js");
|
|
1365
1353
|
await Bun.write(
|
|
1366
1354
|
agentPath,
|
|
1367
1355
|
`
|
|
1368
1356
|
import { Readable, Writable } from "node:stream";
|
|
1369
|
-
import {
|
|
1357
|
+
import { PROTOCOL_VERSION, agent, methods, ndJsonStream } from "${ACP_SDK_PATH}";
|
|
1370
1358
|
class FakeAgent {
|
|
1371
1359
|
constructor(connection) { this.connection = connection; }
|
|
1372
1360
|
async initialize() {
|
|
@@ -1384,8 +1372,7 @@ class FakeAgent {
|
|
|
1384
1372
|
}
|
|
1385
1373
|
async cancel() {}
|
|
1386
1374
|
}
|
|
1387
|
-
|
|
1388
|
-
new AgentSideConnection((connection) => new FakeAgent(connection), stream);
|
|
1375
|
+
${serveFakeAcpAgent("FakeAgent")}
|
|
1389
1376
|
`,
|
|
1390
1377
|
);
|
|
1391
1378
|
const { close: closeTokenStub, apiUrl } = await startTokenStubServer(
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
// Fake ACP targets run from temp dirs, so they import the SDK by path. The
|
|
4
|
+
// unstable v1 entry point lets them return turn `usage` like OpenCode does.
|
|
5
|
+
export const ACP_SDK_PATH = join(
|
|
6
|
+
process.cwd(),
|
|
7
|
+
"node_modules/@agentclientprotocol/sdk/dist/v1/unstable/acp.js",
|
|
8
|
+
);
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Script tail that serves a fake agent class over stdio with the SDK's agent
|
|
12
|
+
* app API. The class implements the ACP agent methods and gets
|
|
13
|
+
* `{ sessionUpdate }` to notify the client. The script must import `agent`,
|
|
14
|
+
* `methods`, and `ndJsonStream` from ACP_SDK_PATH, and `Readable`/`Writable`
|
|
15
|
+
* from node:stream.
|
|
16
|
+
*/
|
|
17
|
+
export function serveFakeAcpAgent(className: string): string {
|
|
18
|
+
return `
|
|
19
|
+
const fake = new ${className}({
|
|
20
|
+
sessionUpdate: (params) => connection.client.notify(methods.client.session.update, params),
|
|
21
|
+
});
|
|
22
|
+
const app = agent()
|
|
23
|
+
.onRequest(methods.agent.initialize, ({ params }) => fake.initialize(params))
|
|
24
|
+
.onRequest(methods.agent.session.new, ({ params }) => fake.newSession(params))
|
|
25
|
+
.onRequest(methods.agent.session.prompt, ({ params }) => fake.prompt(params))
|
|
26
|
+
.onNotification(methods.agent.session.cancel, ({ params }) => fake.cancel(params));
|
|
27
|
+
if (fake.setSessionConfigOption) {
|
|
28
|
+
app.onRequest(methods.agent.session.setConfigOption, ({ params }) =>
|
|
29
|
+
fake.setSessionConfigOption(params),
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
const connection = app.connect(
|
|
33
|
+
ndJsonStream(Writable.toWeb(process.stdout), Readable.toWeb(process.stdin)),
|
|
34
|
+
);
|
|
35
|
+
`;
|
|
36
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
|
-
import type { SessionNotification } from "@agentclientprotocol/sdk";
|
|
2
|
+
import type { SessionNotification } from "@agentclientprotocol/sdk/unstable";
|
|
3
3
|
import { acpReportedCostUsd, translateAcpSessionNotification } from "../providers/acp-swarm-events";
|
|
4
4
|
|
|
5
5
|
function notification(update: SessionNotification["update"]): SessionNotification {
|