@supen-ai/cli 0.1.6
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/README.md +235 -0
- package/daemon/dist/acp-client.d.ts +42 -0
- package/daemon/dist/acp-client.d.ts.map +1 -0
- package/daemon/dist/acp-client.js +149 -0
- package/daemon/dist/acp-client.js.map +1 -0
- package/daemon/dist/acp-types.d.ts +98 -0
- package/daemon/dist/acp-types.d.ts.map +1 -0
- package/daemon/dist/acp-types.js +2 -0
- package/daemon/dist/acp-types.js.map +1 -0
- package/daemon/dist/agent-sdk/app-server-approvals.d.ts +24 -0
- package/daemon/dist/agent-sdk/app-server-approvals.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/app-server-approvals.js +99 -0
- package/daemon/dist/agent-sdk/app-server-approvals.js.map +1 -0
- package/daemon/dist/agent-sdk/app-server-stream.d.ts +8 -0
- package/daemon/dist/agent-sdk/app-server-stream.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/app-server-stream.js +328 -0
- package/daemon/dist/agent-sdk/app-server-stream.js.map +1 -0
- package/daemon/dist/agent-sdk/driver-output-ui.d.ts +9 -0
- package/daemon/dist/agent-sdk/driver-output-ui.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/driver-output-ui.js +290 -0
- package/daemon/dist/agent-sdk/driver-output-ui.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/acpx-driver.d.ts +21 -0
- package/daemon/dist/agent-sdk/drivers/acpx-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/acpx-driver.js +488 -0
- package/daemon/dist/agent-sdk/drivers/acpx-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-acpx-driver.d.ts +5 -0
- package/daemon/dist/agent-sdk/drivers/claude-acpx-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-acpx-driver.js +7 -0
- package/daemon/dist/agent-sdk/drivers/claude-acpx-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-cli-direct-driver.d.ts +20 -0
- package/daemon/dist/agent-sdk/drivers/claude-cli-direct-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-cli-direct-driver.js +264 -0
- package/daemon/dist/agent-sdk/drivers/claude-cli-direct-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-driver.d.ts +29 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-driver.js +24 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-events.d.ts +25 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-events.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-events.js +58 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-events.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-items.d.ts +41 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-items.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-items.js +77 -0
- package/daemon/dist/agent-sdk/drivers/claude-code-items.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-acpx-driver.d.ts +5 -0
- package/daemon/dist/agent-sdk/drivers/codex-acpx-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-acpx-driver.js +7 -0
- package/daemon/dist/agent-sdk/drivers/codex-acpx-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts +12 -0
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js +484 -0
- package/daemon/dist/agent-sdk/drivers/codex-app-server-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-driver.d.ts +28 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-driver.js +219 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-events.d.ts +9 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-events.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-events.js +82 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-events.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-items.d.ts +9 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-items.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-items.js +86 -0
- package/daemon/dist/agent-sdk/drivers/codex-exec-items.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/driver.d.ts +60 -0
- package/daemon/dist/agent-sdk/drivers/driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/driver.js +2 -0
- package/daemon/dist/agent-sdk/drivers/driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/gemini-cli-driver.d.ts +17 -0
- package/daemon/dist/agent-sdk/drivers/gemini-cli-driver.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/gemini-cli-driver.js +255 -0
- package/daemon/dist/agent-sdk/drivers/gemini-cli-driver.js.map +1 -0
- package/daemon/dist/agent-sdk/drivers/registry.d.ts +21 -0
- package/daemon/dist/agent-sdk/drivers/registry.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/drivers/registry.js +167 -0
- package/daemon/dist/agent-sdk/drivers/registry.js.map +1 -0
- package/daemon/dist/agent-sdk/index.d.ts +24 -0
- package/daemon/dist/agent-sdk/index.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/index.js +19 -0
- package/daemon/dist/agent-sdk/index.js.map +1 -0
- package/daemon/dist/agent-sdk/intelligence/contracts.d.ts +17 -0
- package/daemon/dist/agent-sdk/intelligence/contracts.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/intelligence/contracts.js +2 -0
- package/daemon/dist/agent-sdk/intelligence/contracts.js.map +1 -0
- package/daemon/dist/agent-sdk/memory/filesystem.d.ts +7 -0
- package/daemon/dist/agent-sdk/memory/filesystem.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/memory/filesystem.js +133 -0
- package/daemon/dist/agent-sdk/memory/filesystem.js.map +1 -0
- package/daemon/dist/agent-sdk/memory/subsystem.d.ts +54 -0
- package/daemon/dist/agent-sdk/memory/subsystem.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/memory/subsystem.js +106 -0
- package/daemon/dist/agent-sdk/memory/subsystem.js.map +1 -0
- package/daemon/dist/agent-sdk/session-events.d.ts +59 -0
- package/daemon/dist/agent-sdk/session-events.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/session-events.js +104 -0
- package/daemon/dist/agent-sdk/session-events.js.map +1 -0
- package/daemon/dist/agent-sdk/session-manager.d.ts +28 -0
- package/daemon/dist/agent-sdk/session-manager.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/session-manager.js +54 -0
- package/daemon/dist/agent-sdk/session-manager.js.map +1 -0
- package/daemon/dist/agent-sdk/types.d.ts +110 -0
- package/daemon/dist/agent-sdk/types.d.ts.map +1 -0
- package/daemon/dist/agent-sdk/types.js +2 -0
- package/daemon/dist/agent-sdk/types.js.map +1 -0
- package/daemon/dist/automation-event-listener.d.ts +27 -0
- package/daemon/dist/automation-event-listener.d.ts.map +1 -0
- package/daemon/dist/automation-event-listener.js +342 -0
- package/daemon/dist/automation-event-listener.js.map +1 -0
- package/daemon/dist/automation-runner.d.ts +17 -0
- package/daemon/dist/automation-runner.d.ts.map +1 -0
- package/daemon/dist/automation-runner.js +592 -0
- package/daemon/dist/automation-runner.js.map +1 -0
- package/daemon/dist/autonomy/feedback-memory.d.ts +8 -0
- package/daemon/dist/autonomy/feedback-memory.d.ts.map +1 -0
- package/daemon/dist/autonomy/feedback-memory.js +23 -0
- package/daemon/dist/autonomy/feedback-memory.js.map +1 -0
- package/daemon/dist/autonomy/intent-router.d.ts +10 -0
- package/daemon/dist/autonomy/intent-router.d.ts.map +1 -0
- package/daemon/dist/autonomy/intent-router.js +72 -0
- package/daemon/dist/autonomy/intent-router.js.map +1 -0
- package/daemon/dist/autonomy/memory-rules.d.ts +35 -0
- package/daemon/dist/autonomy/memory-rules.d.ts.map +1 -0
- package/daemon/dist/autonomy/memory-rules.js +117 -0
- package/daemon/dist/autonomy/memory-rules.js.map +1 -0
- package/daemon/dist/autonomy/proof-packet.d.ts +17 -0
- package/daemon/dist/autonomy/proof-packet.d.ts.map +1 -0
- package/daemon/dist/autonomy/proof-packet.js +28 -0
- package/daemon/dist/autonomy/proof-packet.js.map +1 -0
- package/daemon/dist/autonomy/session-autonomy.d.ts +18 -0
- package/daemon/dist/autonomy/session-autonomy.d.ts.map +1 -0
- package/daemon/dist/autonomy/session-autonomy.js +71 -0
- package/daemon/dist/autonomy/session-autonomy.js.map +1 -0
- package/daemon/dist/autonomy/source-inventory.d.ts +3 -0
- package/daemon/dist/autonomy/source-inventory.d.ts.map +1 -0
- package/daemon/dist/autonomy/source-inventory.js +84 -0
- package/daemon/dist/autonomy/source-inventory.js.map +1 -0
- package/daemon/dist/autonomy/types.d.ts +20 -0
- package/daemon/dist/autonomy/types.d.ts.map +1 -0
- package/daemon/dist/autonomy/types.js +2 -0
- package/daemon/dist/autonomy/types.js.map +1 -0
- package/daemon/dist/bin/mcp-os.d.ts +3 -0
- package/daemon/dist/bin/mcp-os.d.ts.map +1 -0
- package/daemon/dist/bin/mcp-os.js +63 -0
- package/daemon/dist/bin/mcp-os.js.map +1 -0
- package/daemon/dist/bin/mcp-scheduler.d.ts +3 -0
- package/daemon/dist/bin/mcp-scheduler.d.ts.map +1 -0
- package/daemon/dist/bin/mcp-scheduler.js +90 -0
- package/daemon/dist/bin/mcp-scheduler.js.map +1 -0
- package/daemon/dist/bin/supen-sys.d.ts +3 -0
- package/daemon/dist/bin/supen-sys.d.ts.map +1 -0
- package/daemon/dist/bin/supen-sys.js +38 -0
- package/daemon/dist/bin/supen-sys.js.map +1 -0
- package/daemon/dist/bootstrap/hub-bootstrap.d.ts +2 -0
- package/daemon/dist/bootstrap/hub-bootstrap.d.ts.map +1 -0
- package/daemon/dist/bootstrap/hub-bootstrap.js +409 -0
- package/daemon/dist/bootstrap/hub-bootstrap.js.map +1 -0
- package/daemon/dist/bootstrap/skill-bootstrap.d.ts +2 -0
- package/daemon/dist/bootstrap/skill-bootstrap.d.ts.map +1 -0
- package/daemon/dist/bootstrap/skill-bootstrap.js +92 -0
- package/daemon/dist/bootstrap/skill-bootstrap.js.map +1 -0
- package/daemon/dist/channels/acp.d.ts +23 -0
- package/daemon/dist/channels/acp.d.ts.map +1 -0
- package/daemon/dist/channels/acp.js +916 -0
- package/daemon/dist/channels/acp.js.map +1 -0
- package/daemon/dist/channels/base.d.ts +38 -0
- package/daemon/dist/channels/base.d.ts.map +1 -0
- package/daemon/dist/channels/base.js +56 -0
- package/daemon/dist/channels/base.js.map +1 -0
- package/daemon/dist/channels/http-routes.d.ts +44 -0
- package/daemon/dist/channels/http-routes.d.ts.map +1 -0
- package/daemon/dist/channels/http-routes.js +688 -0
- package/daemon/dist/channels/http-routes.js.map +1 -0
- package/daemon/dist/channels/http.d.ts +16 -0
- package/daemon/dist/channels/http.d.ts.map +1 -0
- package/daemon/dist/channels/http.js +84 -0
- package/daemon/dist/channels/http.js.map +1 -0
- package/daemon/dist/channels/index.d.ts +3 -0
- package/daemon/dist/channels/index.d.ts.map +1 -0
- package/daemon/dist/channels/index.js +7 -0
- package/daemon/dist/channels/index.js.map +1 -0
- package/daemon/dist/channels/registry.d.ts +18 -0
- package/daemon/dist/channels/registry.d.ts.map +1 -0
- package/daemon/dist/channels/registry.js +11 -0
- package/daemon/dist/channels/registry.js.map +1 -0
- package/daemon/dist/commands/builtin.d.ts +7 -0
- package/daemon/dist/commands/builtin.d.ts.map +1 -0
- package/daemon/dist/commands/builtin.js +111 -0
- package/daemon/dist/commands/builtin.js.map +1 -0
- package/daemon/dist/commands/catalog.d.ts +47 -0
- package/daemon/dist/commands/catalog.d.ts.map +1 -0
- package/daemon/dist/commands/catalog.js +487 -0
- package/daemon/dist/commands/catalog.js.map +1 -0
- package/daemon/dist/core/app.d.ts +18 -0
- package/daemon/dist/core/app.d.ts.map +1 -0
- package/daemon/dist/core/app.js +49 -0
- package/daemon/dist/core/app.js.map +1 -0
- package/daemon/dist/core/automation-timing.d.ts +10 -0
- package/daemon/dist/core/automation-timing.d.ts.map +1 -0
- package/daemon/dist/core/automation-timing.js +211 -0
- package/daemon/dist/core/automation-timing.js.map +1 -0
- package/daemon/dist/core/codex-subscription.d.ts +8 -0
- package/daemon/dist/core/codex-subscription.d.ts.map +1 -0
- package/daemon/dist/core/codex-subscription.js +150 -0
- package/daemon/dist/core/codex-subscription.js.map +1 -0
- package/daemon/dist/core/command-hub.d.ts +22 -0
- package/daemon/dist/core/command-hub.d.ts.map +1 -0
- package/daemon/dist/core/command-hub.js +59 -0
- package/daemon/dist/core/command-hub.js.map +1 -0
- package/daemon/dist/core/config.d.ts +146 -0
- package/daemon/dist/core/config.d.ts.map +1 -0
- package/daemon/dist/core/config.js +663 -0
- package/daemon/dist/core/config.js.map +1 -0
- package/daemon/dist/core/control-commands.d.ts +17 -0
- package/daemon/dist/core/control-commands.d.ts.map +1 -0
- package/daemon/dist/core/control-commands.js +35 -0
- package/daemon/dist/core/control-commands.js.map +1 -0
- package/daemon/dist/core/control-log.d.ts +17 -0
- package/daemon/dist/core/control-log.d.ts.map +1 -0
- package/daemon/dist/core/control-log.js +67 -0
- package/daemon/dist/core/control-log.js.map +1 -0
- package/daemon/dist/core/cortex.d.ts +53 -0
- package/daemon/dist/core/cortex.d.ts.map +1 -0
- package/daemon/dist/core/cortex.js +1690 -0
- package/daemon/dist/core/cortex.js.map +1 -0
- package/daemon/dist/core/daemon-lock.d.ts +16 -0
- package/daemon/dist/core/daemon-lock.d.ts.map +1 -0
- package/daemon/dist/core/daemon-lock.js +285 -0
- package/daemon/dist/core/daemon-lock.js.map +1 -0
- package/daemon/dist/core/dispatcher.d.ts +42 -0
- package/daemon/dist/core/dispatcher.d.ts.map +1 -0
- package/daemon/dist/core/dispatcher.js +173 -0
- package/daemon/dist/core/dispatcher.js.map +1 -0
- package/daemon/dist/core/enrollment.d.ts +41 -0
- package/daemon/dist/core/enrollment.d.ts.map +1 -0
- package/daemon/dist/core/enrollment.js +195 -0
- package/daemon/dist/core/enrollment.js.map +1 -0
- package/daemon/dist/core/env.d.ts +109 -0
- package/daemon/dist/core/env.d.ts.map +1 -0
- package/daemon/dist/core/env.js +329 -0
- package/daemon/dist/core/env.js.map +1 -0
- package/daemon/dist/core/gateway-config.d.ts +16 -0
- package/daemon/dist/core/gateway-config.d.ts.map +1 -0
- package/daemon/dist/core/gateway-config.js +103 -0
- package/daemon/dist/core/gateway-config.js.map +1 -0
- package/daemon/dist/core/gateway-protocol.d.ts +80 -0
- package/daemon/dist/core/gateway-protocol.d.ts.map +1 -0
- package/daemon/dist/core/gateway-protocol.js +2 -0
- package/daemon/dist/core/gateway-protocol.js.map +1 -0
- package/daemon/dist/core/gateway-routing-config.d.ts +21 -0
- package/daemon/dist/core/gateway-routing-config.d.ts.map +1 -0
- package/daemon/dist/core/gateway-routing-config.js +56 -0
- package/daemon/dist/core/gateway-routing-config.js.map +1 -0
- package/daemon/dist/core/gateway.d.ts +124 -0
- package/daemon/dist/core/gateway.d.ts.map +1 -0
- package/daemon/dist/core/gateway.js +887 -0
- package/daemon/dist/core/gateway.js.map +1 -0
- package/daemon/dist/core/hub-snapshot.d.ts +42 -0
- package/daemon/dist/core/hub-snapshot.d.ts.map +1 -0
- package/daemon/dist/core/hub-snapshot.js +125 -0
- package/daemon/dist/core/hub-snapshot.js.map +1 -0
- package/daemon/dist/core/interrupts.d.ts +7 -0
- package/daemon/dist/core/interrupts.d.ts.map +1 -0
- package/daemon/dist/core/interrupts.js +28 -0
- package/daemon/dist/core/interrupts.js.map +1 -0
- package/daemon/dist/core/logger.d.ts +3 -0
- package/daemon/dist/core/logger.d.ts.map +1 -0
- package/daemon/dist/core/logger.js +91 -0
- package/daemon/dist/core/logger.js.map +1 -0
- package/daemon/dist/core/loop-guard.d.ts +27 -0
- package/daemon/dist/core/loop-guard.d.ts.map +1 -0
- package/daemon/dist/core/loop-guard.js +47 -0
- package/daemon/dist/core/loop-guard.js.map +1 -0
- package/daemon/dist/core/observable-logging.d.ts +43 -0
- package/daemon/dist/core/observable-logging.d.ts.map +1 -0
- package/daemon/dist/core/observable-logging.js +77 -0
- package/daemon/dist/core/observable-logging.js.map +1 -0
- package/daemon/dist/core/pairing.d.ts +51 -0
- package/daemon/dist/core/pairing.d.ts.map +1 -0
- package/daemon/dist/core/pairing.js +207 -0
- package/daemon/dist/core/pairing.js.map +1 -0
- package/daemon/dist/core/progress.d.ts +32 -0
- package/daemon/dist/core/progress.d.ts.map +1 -0
- package/daemon/dist/core/progress.js +145 -0
- package/daemon/dist/core/progress.js.map +1 -0
- package/daemon/dist/core/protocol-adapter.d.ts +14 -0
- package/daemon/dist/core/protocol-adapter.d.ts.map +1 -0
- package/daemon/dist/core/protocol-adapter.js +472 -0
- package/daemon/dist/core/protocol-adapter.js.map +1 -0
- package/daemon/dist/core/sdk-wrapper.d.ts +36 -0
- package/daemon/dist/core/sdk-wrapper.d.ts.map +1 -0
- package/daemon/dist/core/sdk-wrapper.js +533 -0
- package/daemon/dist/core/sdk-wrapper.js.map +1 -0
- package/daemon/dist/core/security.d.ts +10 -0
- package/daemon/dist/core/security.d.ts.map +1 -0
- package/daemon/dist/core/security.js +95 -0
- package/daemon/dist/core/security.js.map +1 -0
- package/daemon/dist/core/space-env.d.ts +15 -0
- package/daemon/dist/core/space-env.d.ts.map +1 -0
- package/daemon/dist/core/space-env.js +182 -0
- package/daemon/dist/core/space-env.js.map +1 -0
- package/daemon/dist/core/status-inspector.d.ts +31 -0
- package/daemon/dist/core/status-inspector.d.ts.map +1 -0
- package/daemon/dist/core/status-inspector.js +35 -0
- package/daemon/dist/core/status-inspector.js.map +1 -0
- package/daemon/dist/core/storage-paths.d.ts +30 -0
- package/daemon/dist/core/storage-paths.d.ts.map +1 -0
- package/daemon/dist/core/storage-paths.js +84 -0
- package/daemon/dist/core/storage-paths.js.map +1 -0
- package/daemon/dist/core/store.d.ts +256 -0
- package/daemon/dist/core/store.d.ts.map +1 -0
- package/daemon/dist/core/store.js +2956 -0
- package/daemon/dist/core/store.js.map +1 -0
- package/daemon/dist/core/streaming.d.ts +24 -0
- package/daemon/dist/core/streaming.d.ts.map +1 -0
- package/daemon/dist/core/streaming.js +57 -0
- package/daemon/dist/core/streaming.js.map +1 -0
- package/daemon/dist/core/task-artifacts.d.ts +17 -0
- package/daemon/dist/core/task-artifacts.d.ts.map +1 -0
- package/daemon/dist/core/task-artifacts.js +104 -0
- package/daemon/dist/core/task-artifacts.js.map +1 -0
- package/daemon/dist/core/thread-event-log.d.ts +54 -0
- package/daemon/dist/core/thread-event-log.d.ts.map +1 -0
- package/daemon/dist/core/thread-event-log.js +218 -0
- package/daemon/dist/core/thread-event-log.js.map +1 -0
- package/daemon/dist/core/thread-runtime-state.d.ts +53 -0
- package/daemon/dist/core/thread-runtime-state.d.ts.map +1 -0
- package/daemon/dist/core/thread-runtime-state.js +271 -0
- package/daemon/dist/core/thread-runtime-state.js.map +1 -0
- package/daemon/dist/core/types.d.ts +552 -0
- package/daemon/dist/core/types.d.ts.map +1 -0
- package/daemon/dist/core/types.js +2 -0
- package/daemon/dist/core/types.js.map +1 -0
- package/daemon/dist/core/utils.d.ts +5 -0
- package/daemon/dist/core/utils.d.ts.map +1 -0
- package/daemon/dist/core/utils.js +35 -0
- package/daemon/dist/core/utils.js.map +1 -0
- package/daemon/dist/http/command-catalog.d.ts +3 -0
- package/daemon/dist/http/command-catalog.d.ts.map +1 -0
- package/daemon/dist/http/command-catalog.js +2 -0
- package/daemon/dist/http/command-catalog.js.map +1 -0
- package/daemon/dist/http/context.d.ts +18 -0
- package/daemon/dist/http/context.d.ts.map +1 -0
- package/daemon/dist/http/context.js +121 -0
- package/daemon/dist/http/context.js.map +1 -0
- package/daemon/dist/http/office-preview.d.ts +10 -0
- package/daemon/dist/http/office-preview.d.ts.map +1 -0
- package/daemon/dist/http/office-preview.js +234 -0
- package/daemon/dist/http/office-preview.js.map +1 -0
- package/daemon/dist/http/response.d.ts +5 -0
- package/daemon/dist/http/response.d.ts.map +1 -0
- package/daemon/dist/http/response.js +37 -0
- package/daemon/dist/http/response.js.map +1 -0
- package/daemon/dist/http/router.d.ts +4 -0
- package/daemon/dist/http/router.d.ts.map +1 -0
- package/daemon/dist/http/router.js +57 -0
- package/daemon/dist/http/router.js.map +1 -0
- package/daemon/dist/http/routes/agents.d.ts +4 -0
- package/daemon/dist/http/routes/agents.d.ts.map +1 -0
- package/daemon/dist/http/routes/agents.js +747 -0
- package/daemon/dist/http/routes/agents.js.map +1 -0
- package/daemon/dist/http/routes/automations.d.ts +6 -0
- package/daemon/dist/http/routes/automations.d.ts.map +1 -0
- package/daemon/dist/http/routes/automations.js +530 -0
- package/daemon/dist/http/routes/automations.js.map +1 -0
- package/daemon/dist/http/routes/autonomy.d.ts +4 -0
- package/daemon/dist/http/routes/autonomy.d.ts.map +1 -0
- package/daemon/dist/http/routes/autonomy.js +78 -0
- package/daemon/dist/http/routes/autonomy.js.map +1 -0
- package/daemon/dist/http/routes/chat-input.d.ts +18 -0
- package/daemon/dist/http/routes/chat-input.d.ts.map +1 -0
- package/daemon/dist/http/routes/chat-input.js +122 -0
- package/daemon/dist/http/routes/chat-input.js.map +1 -0
- package/daemon/dist/http/routes/plugins.d.ts +5 -0
- package/daemon/dist/http/routes/plugins.d.ts.map +1 -0
- package/daemon/dist/http/routes/plugins.js +221 -0
- package/daemon/dist/http/routes/plugins.js.map +1 -0
- package/daemon/dist/http/routes/rpc.d.ts +28 -0
- package/daemon/dist/http/routes/rpc.d.ts.map +1 -0
- package/daemon/dist/http/routes/rpc.js +790 -0
- package/daemon/dist/http/routes/rpc.js.map +1 -0
- package/daemon/dist/http/routes/sessions.d.ts +11 -0
- package/daemon/dist/http/routes/sessions.d.ts.map +1 -0
- package/daemon/dist/http/routes/sessions.js +963 -0
- package/daemon/dist/http/routes/sessions.js.map +1 -0
- package/daemon/dist/http/routes/skills.d.ts +5 -0
- package/daemon/dist/http/routes/skills.d.ts.map +1 -0
- package/daemon/dist/http/routes/skills.js +420 -0
- package/daemon/dist/http/routes/skills.js.map +1 -0
- package/daemon/dist/http/routes/system.d.ts +64 -0
- package/daemon/dist/http/routes/system.d.ts.map +1 -0
- package/daemon/dist/http/routes/system.js +2676 -0
- package/daemon/dist/http/routes/system.js.map +1 -0
- package/daemon/dist/http/stream.d.ts +11 -0
- package/daemon/dist/http/stream.d.ts.map +1 -0
- package/daemon/dist/http/stream.js +100 -0
- package/daemon/dist/http/stream.js.map +1 -0
- package/daemon/dist/http/thread-stream.d.ts +10 -0
- package/daemon/dist/http/thread-stream.d.ts.map +1 -0
- package/daemon/dist/http/thread-stream.js +50 -0
- package/daemon/dist/http/thread-stream.js.map +1 -0
- package/daemon/dist/http/thread-title.d.ts +12 -0
- package/daemon/dist/http/thread-title.d.ts.map +1 -0
- package/daemon/dist/http/thread-title.js +122 -0
- package/daemon/dist/http/thread-title.js.map +1 -0
- package/daemon/dist/http/utils.d.ts +2 -0
- package/daemon/dist/http/utils.d.ts.map +1 -0
- package/daemon/dist/http/utils.js +18 -0
- package/daemon/dist/http/utils.js.map +1 -0
- package/daemon/dist/http/websocket.d.ts +5 -0
- package/daemon/dist/http/websocket.d.ts.map +1 -0
- package/daemon/dist/http/websocket.js +100 -0
- package/daemon/dist/http/websocket.js.map +1 -0
- package/daemon/dist/index.d.ts +35 -0
- package/daemon/dist/index.d.ts.map +1 -0
- package/daemon/dist/index.js +1582 -0
- package/daemon/dist/index.js.map +1 -0
- package/daemon/dist/mcp/aggregate-config.d.ts +16 -0
- package/daemon/dist/mcp/aggregate-config.d.ts.map +1 -0
- package/daemon/dist/mcp/aggregate-config.js +97 -0
- package/daemon/dist/mcp/aggregate-config.js.map +1 -0
- package/daemon/dist/mcp/client.d.ts +94 -0
- package/daemon/dist/mcp/client.d.ts.map +1 -0
- package/daemon/dist/mcp/client.js +207 -0
- package/daemon/dist/mcp/client.js.map +1 -0
- package/daemon/dist/mcp/default-servers.d.ts +35 -0
- package/daemon/dist/mcp/default-servers.d.ts.map +1 -0
- package/daemon/dist/mcp/default-servers.js +209 -0
- package/daemon/dist/mcp/default-servers.js.map +1 -0
- package/daemon/dist/mcp/gateway-client.d.ts +58 -0
- package/daemon/dist/mcp/gateway-client.d.ts.map +1 -0
- package/daemon/dist/mcp/gateway-client.js +181 -0
- package/daemon/dist/mcp/gateway-client.js.map +1 -0
- package/daemon/dist/mcp/index.d.ts +26 -0
- package/daemon/dist/mcp/index.d.ts.map +1 -0
- package/daemon/dist/mcp/index.js +50 -0
- package/daemon/dist/mcp/index.js.map +1 -0
- package/daemon/dist/mcp/settings.d.ts +3 -0
- package/daemon/dist/mcp/settings.d.ts.map +1 -0
- package/daemon/dist/mcp/settings.js +60 -0
- package/daemon/dist/mcp/settings.js.map +1 -0
- package/daemon/dist/mcp/tools.d.ts +21 -0
- package/daemon/dist/mcp/tools.d.ts.map +1 -0
- package/daemon/dist/mcp/tools.js +136 -0
- package/daemon/dist/mcp/tools.js.map +1 -0
- package/daemon/dist/plugins/catalog.d.ts +10 -0
- package/daemon/dist/plugins/catalog.d.ts.map +1 -0
- package/daemon/dist/plugins/catalog.js +304 -0
- package/daemon/dist/plugins/catalog.js.map +1 -0
- package/daemon/dist/plugins/hub.d.ts +42 -0
- package/daemon/dist/plugins/hub.d.ts.map +1 -0
- package/daemon/dist/plugins/hub.js +812 -0
- package/daemon/dist/plugins/hub.js.map +1 -0
- package/daemon/dist/plugins/types.d.ts +144 -0
- package/daemon/dist/plugins/types.d.ts.map +1 -0
- package/daemon/dist/plugins/types.js +2 -0
- package/daemon/dist/plugins/types.js.map +1 -0
- package/daemon/dist/router.d.ts +13 -0
- package/daemon/dist/router.d.ts.map +1 -0
- package/daemon/dist/router.js +43 -0
- package/daemon/dist/router.js.map +1 -0
- package/daemon/dist/skills/adapter.d.ts +4 -0
- package/daemon/dist/skills/adapter.d.ts.map +1 -0
- package/daemon/dist/skills/adapter.js +141 -0
- package/daemon/dist/skills/adapter.js.map +1 -0
- package/daemon/dist/skills/allowlist.d.ts +20 -0
- package/daemon/dist/skills/allowlist.d.ts.map +1 -0
- package/daemon/dist/skills/allowlist.js +52 -0
- package/daemon/dist/skills/allowlist.js.map +1 -0
- package/daemon/dist/skills/catalog.d.ts +26 -0
- package/daemon/dist/skills/catalog.d.ts.map +1 -0
- package/daemon/dist/skills/catalog.js +274 -0
- package/daemon/dist/skills/catalog.js.map +1 -0
- package/daemon/dist/skills/claude_code.d.ts +25 -0
- package/daemon/dist/skills/claude_code.d.ts.map +1 -0
- package/daemon/dist/skills/claude_code.js +49 -0
- package/daemon/dist/skills/claude_code.js.map +1 -0
- package/daemon/dist/skills/commands.d.ts +3 -0
- package/daemon/dist/skills/commands.d.ts.map +1 -0
- package/daemon/dist/skills/commands.js +689 -0
- package/daemon/dist/skills/commands.js.map +1 -0
- package/daemon/dist/skills/enabled.d.ts +7 -0
- package/daemon/dist/skills/enabled.d.ts.map +1 -0
- package/daemon/dist/skills/enabled.js +37 -0
- package/daemon/dist/skills/enabled.js.map +1 -0
- package/daemon/dist/skills/hub.d.ts +35 -0
- package/daemon/dist/skills/hub.d.ts.map +1 -0
- package/daemon/dist/skills/hub.js +574 -0
- package/daemon/dist/skills/hub.js.map +1 -0
- package/daemon/dist/skills/loader.d.ts +24 -0
- package/daemon/dist/skills/loader.d.ts.map +1 -0
- package/daemon/dist/skills/loader.js +693 -0
- package/daemon/dist/skills/loader.js.map +1 -0
- package/daemon/dist/skills/mcp-config.d.ts +8 -0
- package/daemon/dist/skills/mcp-config.d.ts.map +1 -0
- package/daemon/dist/skills/mcp-config.js +110 -0
- package/daemon/dist/skills/mcp-config.js.map +1 -0
- package/daemon/dist/skills/parser.d.ts +3 -0
- package/daemon/dist/skills/parser.d.ts.map +1 -0
- package/daemon/dist/skills/parser.js +279 -0
- package/daemon/dist/skills/parser.js.map +1 -0
- package/daemon/dist/skills/registry.d.ts +2 -0
- package/daemon/dist/skills/registry.d.ts.map +1 -0
- package/daemon/dist/skills/registry.js +2 -0
- package/daemon/dist/skills/registry.js.map +1 -0
- package/daemon/dist/skills/runtime-contract.d.ts +3 -0
- package/daemon/dist/skills/runtime-contract.d.ts.map +1 -0
- package/daemon/dist/skills/runtime-contract.js +92 -0
- package/daemon/dist/skills/runtime-contract.js.map +1 -0
- package/daemon/dist/skills/runtime.d.ts +28 -0
- package/daemon/dist/skills/runtime.d.ts.map +1 -0
- package/daemon/dist/skills/runtime.js +286 -0
- package/daemon/dist/skills/runtime.js.map +1 -0
- package/daemon/dist/skills/types.d.ts +228 -0
- package/daemon/dist/skills/types.d.ts.map +1 -0
- package/daemon/dist/skills/types.js +2 -0
- package/daemon/dist/skills/types.js.map +1 -0
- package/daemon/dist/start.d.ts +6 -0
- package/daemon/dist/start.d.ts.map +1 -0
- package/daemon/dist/start.js +19 -0
- package/daemon/dist/start.js.map +1 -0
- package/daemon/dist/sub-agent.d.ts +46 -0
- package/daemon/dist/sub-agent.d.ts.map +1 -0
- package/daemon/dist/sub-agent.js +120 -0
- package/daemon/dist/sub-agent.js.map +1 -0
- package/daemon/dist/sync/supabase-sync.d.ts +16 -0
- package/daemon/dist/sync/supabase-sync.d.ts.map +1 -0
- package/daemon/dist/sync/supabase-sync.js +240 -0
- package/daemon/dist/sync/supabase-sync.js.map +1 -0
- package/daemon/dist/task-executor.d.ts +6 -0
- package/daemon/dist/task-executor.d.ts.map +1 -0
- package/daemon/dist/task-executor.js +31 -0
- package/daemon/dist/task-executor.js.map +1 -0
- package/daemon/dist/tools/automations.d.ts +57 -0
- package/daemon/dist/tools/automations.d.ts.map +1 -0
- package/daemon/dist/tools/automations.js +94 -0
- package/daemon/dist/tools/automations.js.map +1 -0
- package/daemon/dist/tools/built-ins.d.ts +112 -0
- package/daemon/dist/tools/built-ins.d.ts.map +1 -0
- package/daemon/dist/tools/built-ins.js +251 -0
- package/daemon/dist/tools/built-ins.js.map +1 -0
- package/daemon/dist/tools/index.d.ts +287 -0
- package/daemon/dist/tools/index.d.ts.map +1 -0
- package/daemon/dist/tools/index.js +86 -0
- package/daemon/dist/tools/index.js.map +1 -0
- package/daemon/dist/tools/shell.d.ts +15 -0
- package/daemon/dist/tools/shell.d.ts.map +1 -0
- package/daemon/dist/tools/shell.js +46 -0
- package/daemon/dist/tools/shell.js.map +1 -0
- package/daemon/dist/tools/skill-tools.d.ts +23 -0
- package/daemon/dist/tools/skill-tools.d.ts.map +1 -0
- package/daemon/dist/tools/skill-tools.js +64 -0
- package/daemon/dist/tools/skill-tools.js.map +1 -0
- package/daemon/dist/tools/system.d.ts +36 -0
- package/daemon/dist/tools/system.d.ts.map +1 -0
- package/daemon/dist/tools/system.js +54 -0
- package/daemon/dist/tools/system.js.map +1 -0
- package/daemon/dist/tools/types.d.ts +11 -0
- package/daemon/dist/tools/types.d.ts.map +1 -0
- package/daemon/dist/tools/types.js +2 -0
- package/daemon/dist/tools/types.js.map +1 -0
- package/daemon/scripts/browser-smoke.mjs +125 -0
- package/daemon/scripts/supen-daemon.js +15 -0
- package/dist/agent.d.ts +11 -0
- package/dist/agent.js +159 -0
- package/dist/agent.js.map +1 -0
- package/dist/auth/login.d.ts +20 -0
- package/dist/auth/login.js +151 -0
- package/dist/auth/login.js.map +1 -0
- package/dist/auth/logout.d.ts +5 -0
- package/dist/auth/logout.js +19 -0
- package/dist/auth/logout.js.map +1 -0
- package/dist/auth/store.d.ts +37 -0
- package/dist/auth/store.js +80 -0
- package/dist/auth/store.js.map +1 -0
- package/dist/auth/whoami.d.ts +5 -0
- package/dist/auth/whoami.js +24 -0
- package/dist/auth/whoami.js.map +1 -0
- package/dist/backend.d.ts +8 -0
- package/dist/backend.js +148 -0
- package/dist/backend.js.map +1 -0
- package/dist/bootstrap.d.ts +13 -0
- package/dist/bootstrap.js +230 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/chat.d.ts +13 -0
- package/dist/chat.js +255 -0
- package/dist/chat.js.map +1 -0
- package/dist/commands.d.ts +48 -0
- package/dist/commands.js +273 -0
- package/dist/commands.js.map +1 -0
- package/dist/computer.d.ts +2 -0
- package/dist/computer.js +510 -0
- package/dist/computer.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +149 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon-manage.d.ts +29 -0
- package/dist/daemon-manage.js +255 -0
- package/dist/daemon-manage.js.map +1 -0
- package/dist/daemon.d.ts +15 -0
- package/dist/daemon.js +205 -0
- package/dist/daemon.js.map +1 -0
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.js +323 -0
- package/dist/doctor.js.map +1 -0
- package/dist/enroll.d.ts +7 -0
- package/dist/enroll.js +154 -0
- package/dist/enroll.js.map +1 -0
- package/dist/env.d.ts +10 -0
- package/dist/env.js +363 -0
- package/dist/env.js.map +1 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.js +141 -0
- package/dist/index.js.map +1 -0
- package/dist/knowledge.d.ts +3 -0
- package/dist/knowledge.js +1581 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/mcp.d.ts +11 -0
- package/dist/mcp.js +137 -0
- package/dist/mcp.js.map +1 -0
- package/dist/model.d.ts +8 -0
- package/dist/model.js +192 -0
- package/dist/model.js.map +1 -0
- package/dist/pairing.d.ts +21 -0
- package/dist/pairing.js +376 -0
- package/dist/pairing.js.map +1 -0
- package/dist/repl-events.d.ts +60 -0
- package/dist/repl-events.js +89 -0
- package/dist/repl-events.js.map +1 -0
- package/dist/repl-renderer.d.ts +37 -0
- package/dist/repl-renderer.js +140 -0
- package/dist/repl-renderer.js.map +1 -0
- package/dist/repl.d.ts +52 -0
- package/dist/repl.js +624 -0
- package/dist/repl.js.map +1 -0
- package/dist/service.d.ts +8 -0
- package/dist/service.js +238 -0
- package/dist/service.js.map +1 -0
- package/dist/skills.d.ts +14 -0
- package/dist/skills.js +423 -0
- package/dist/skills.js.map +1 -0
- package/dist/sse.d.ts +15 -0
- package/dist/sse.js +166 -0
- package/dist/sse.js.map +1 -0
- package/dist/thread.d.ts +9 -0
- package/dist/thread.js +152 -0
- package/dist/thread.js.map +1 -0
- package/dist/transport/computer-api.d.ts +1 -0
- package/dist/transport/computer-api.js +20 -0
- package/dist/transport/computer-api.js.map +1 -0
- package/dist/transport/gateway.d.ts +23 -0
- package/dist/transport/gateway.js +161 -0
- package/dist/transport/gateway.js.map +1 -0
- package/dist/transport/index.d.ts +27 -0
- package/dist/transport/index.js +77 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/local.d.ts +20 -0
- package/dist/transport/local.js +138 -0
- package/dist/transport/local.js.map +1 -0
- package/dist/transport/types.d.ts +42 -0
- package/dist/transport/types.js +11 -0
- package/dist/transport/types.js.map +1 -0
- package/dist/ui/app.d.ts +7 -0
- package/dist/ui/app.js +192 -0
- package/dist/ui/app.js.map +1 -0
- package/dist/ui/history-item.d.ts +9 -0
- package/dist/ui/history-item.js +35 -0
- package/dist/ui/history-item.js.map +1 -0
- package/dist/ui/input-bar.d.ts +17 -0
- package/dist/ui/input-bar.js +67 -0
- package/dist/ui/input-bar.js.map +1 -0
- package/dist/ui/streaming-view.d.ts +6 -0
- package/dist/ui/streaming-view.js +6 -0
- package/dist/ui/streaming-view.js.map +1 -0
- package/dist/ui/thread-input-history.d.ts +18 -0
- package/dist/ui/thread-input-history.js +67 -0
- package/dist/ui/thread-input-history.js.map +1 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.js +80 -0
- package/dist/utils.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,1690 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
4
|
+
import { logger } from './logger.js';
|
|
5
|
+
import { getGatewayInstance, getLlmToken, getLlmTokenOrWait } from './gateway.js';
|
|
6
|
+
import { AGENT_MIND_FILES, ASSISTANT_NAME, agentPaths, getAgentModelConfig, } from './config.js';
|
|
7
|
+
import { cleanupTaskFolderWithoutMeaningfulArtifacts, ensureTaskArtifactLayout, resolveSessionTaskArtifactPaths, } from './task-artifacts.js';
|
|
8
|
+
import { getUsageStats, appendGlobalUsage, clearSessionSdkId, ensureSession, updateSessionStatus, updateSessionSdkId, updateSessionUsage, getSessionForAgent, storeSessionUiEvent, } from './store.js';
|
|
9
|
+
import { usesAnthropicMessagesApi } from '../http/thread-title.js';
|
|
10
|
+
import { LoopGuard } from './loop-guard.js';
|
|
11
|
+
import { convertSdkEventToUiMessageChunks, enrichUiMessageChunksWithDocumentRefs, serializeUiMessageChunks, } from './protocol-adapter.js';
|
|
12
|
+
import { resolveMcpServers } from '../mcp/default-servers.js';
|
|
13
|
+
import { getMcpEnvOverrides } from '../mcp/settings.js';
|
|
14
|
+
import { customServersToMcpMap, fetchGlobalMcpConfig } from '../mcp/gateway-client.js';
|
|
15
|
+
import { resolveInstalledPluginMcpServers } from '../plugins/hub.js';
|
|
16
|
+
import { resolveEnabledSkillMcpServers } from '../skills/mcp-config.js';
|
|
17
|
+
import { getRuntimeSpaceEnvVars, withRuntimeSpaceEnv } from './space-env.js';
|
|
18
|
+
import { buildAssistantOutputExcerpt, buildObservableToolDetail, buildTaskContextExcerpt, excerptText, } from './observable-logging.js';
|
|
19
|
+
import { shouldWaitForGatewayToken } from './sdk-wrapper.js';
|
|
20
|
+
import { classifySessionInsight } from '../agent-sdk/session-events.js';
|
|
21
|
+
import { SessionManager } from '../agent-sdk/session-manager.js';
|
|
22
|
+
import { convertDriverOutputsToUiMessageChunks } from '../agent-sdk/driver-output-ui.js';
|
|
23
|
+
import { createSession, createTurn } from '../agent-sdk/session-events.js';
|
|
24
|
+
import { createFileMemorySubsystem } from '../agent-sdk/memory/filesystem.js';
|
|
25
|
+
function isVisualRuntimeAttachment(attachment) {
|
|
26
|
+
const type = typeof attachment?.type === 'string' ? attachment.type : '';
|
|
27
|
+
const mimeType = typeof attachment?.mimeType === 'string'
|
|
28
|
+
? attachment.mimeType
|
|
29
|
+
: typeof attachment?.mime_type === 'string'
|
|
30
|
+
? attachment.mime_type
|
|
31
|
+
: '';
|
|
32
|
+
return type === 'image' || mimeType.startsWith('image/');
|
|
33
|
+
}
|
|
34
|
+
function resolveRuntimeAttachmentPath(rawPath, artifacts) {
|
|
35
|
+
if (!rawPath)
|
|
36
|
+
return null;
|
|
37
|
+
if (path.isAbsolute(rawPath))
|
|
38
|
+
return fs.existsSync(rawPath) ? rawPath : null;
|
|
39
|
+
const normalized = rawPath.replace(/\\/g, '/').replace(/^\/+/, '');
|
|
40
|
+
const candidates = [];
|
|
41
|
+
if (normalized === artifacts.taskFolderName || normalized.startsWith(`${artifacts.taskFolderName}/`)) {
|
|
42
|
+
candidates.push(path.join(artifacts.artifactRoot, normalized));
|
|
43
|
+
}
|
|
44
|
+
candidates.push(path.resolve(artifacts.taskRoot, normalized));
|
|
45
|
+
candidates.push(path.resolve(artifacts.cwd, normalized));
|
|
46
|
+
for (const candidate of candidates) {
|
|
47
|
+
if (fs.existsSync(candidate))
|
|
48
|
+
return candidate;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
function resolveRuntimeAttachments(message, artifacts) {
|
|
53
|
+
const attachments = Array.isArray(message?.attachments) ? message.attachments : [];
|
|
54
|
+
return attachments
|
|
55
|
+
.map((attachment) => {
|
|
56
|
+
if (!attachment || typeof attachment !== 'object')
|
|
57
|
+
return null;
|
|
58
|
+
if (!isVisualRuntimeAttachment(attachment))
|
|
59
|
+
return null;
|
|
60
|
+
const rawPaths = [
|
|
61
|
+
typeof attachment.taskPath === 'string' ? attachment.taskPath.trim() : '',
|
|
62
|
+
typeof attachment.path === 'string' ? attachment.path.trim() : '',
|
|
63
|
+
].filter(Boolean);
|
|
64
|
+
const resolvedPath = rawPaths
|
|
65
|
+
.map((rawPath) => resolveRuntimeAttachmentPath(rawPath, artifacts))
|
|
66
|
+
.find((candidate) => Boolean(candidate));
|
|
67
|
+
if (!resolvedPath)
|
|
68
|
+
return null;
|
|
69
|
+
return {
|
|
70
|
+
type: 'image',
|
|
71
|
+
name: typeof attachment.name === 'string'
|
|
72
|
+
? attachment.name
|
|
73
|
+
: typeof attachment.filename === 'string'
|
|
74
|
+
? attachment.filename
|
|
75
|
+
: path.basename(resolvedPath),
|
|
76
|
+
filename: typeof attachment.filename === 'string'
|
|
77
|
+
? attachment.filename
|
|
78
|
+
: typeof attachment.name === 'string'
|
|
79
|
+
? attachment.name
|
|
80
|
+
: path.basename(resolvedPath),
|
|
81
|
+
path: resolvedPath,
|
|
82
|
+
mimeType: typeof attachment.mimeType === 'string'
|
|
83
|
+
? attachment.mimeType
|
|
84
|
+
: typeof attachment.mime_type === 'string'
|
|
85
|
+
? attachment.mime_type
|
|
86
|
+
: undefined,
|
|
87
|
+
};
|
|
88
|
+
})
|
|
89
|
+
.filter((attachment) => Boolean(attachment));
|
|
90
|
+
}
|
|
91
|
+
const APP_SERVER_REASONING_DELTA_METHODS = new Set([
|
|
92
|
+
'item/reasoningSummary/delta',
|
|
93
|
+
'item/reasoning/delta',
|
|
94
|
+
'item/reasoning/summaryTextDelta',
|
|
95
|
+
'item/reasoning/textDelta',
|
|
96
|
+
'item/plan/delta',
|
|
97
|
+
'item/reasoning/summaryPartAdded',
|
|
98
|
+
]);
|
|
99
|
+
function shouldPersistUiChunkToChat(chunk) {
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
const NATIVE_SESSION_PREWARM_TTL_MS = 30_000;
|
|
103
|
+
const nativeSessionPrewarmCache = new Map();
|
|
104
|
+
function appendNormalizedOutputToFinalText(normalizedOutputs, current) {
|
|
105
|
+
let next = current;
|
|
106
|
+
let receivedText = false;
|
|
107
|
+
for (const output of normalizedOutputs) {
|
|
108
|
+
if (output.kind === 'session-event' && output.event?.type === 'text.delta') {
|
|
109
|
+
const payload = output.event.payload;
|
|
110
|
+
const text = typeof payload?.text === 'string' ? payload.text : '';
|
|
111
|
+
if (text) {
|
|
112
|
+
next += text;
|
|
113
|
+
receivedText = true;
|
|
114
|
+
}
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (output.kind === 'turn-item' && output.item?.type === 'message') {
|
|
118
|
+
const payload = output.item.payload;
|
|
119
|
+
const text = typeof payload?.text === 'string' ? payload.text : '';
|
|
120
|
+
if (text) {
|
|
121
|
+
next = text;
|
|
122
|
+
receivedText = true;
|
|
123
|
+
}
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (output.kind === 'app-server-event') {
|
|
127
|
+
const event = output.event;
|
|
128
|
+
const params = event?.params;
|
|
129
|
+
if (event?.method === 'item/agentMessage/delta') {
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (event?.method === 'item/completed') {
|
|
133
|
+
const item = params?.item && typeof params.item === 'object'
|
|
134
|
+
? params.item
|
|
135
|
+
: {};
|
|
136
|
+
const phase = typeof item.phase === 'string' ? item.phase : '';
|
|
137
|
+
if (phase && phase !== 'final_answer') {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
const text = item.type === 'agentMessage' && typeof item.text === 'string' ? item.text : '';
|
|
141
|
+
if (text) {
|
|
142
|
+
next = text;
|
|
143
|
+
receivedText = true;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return { next, receivedText };
|
|
149
|
+
}
|
|
150
|
+
function extractTerminalResultText(normalizedOutputs) {
|
|
151
|
+
for (const output of normalizedOutputs) {
|
|
152
|
+
if (output.kind === 'app-server-event') {
|
|
153
|
+
const event = output.event;
|
|
154
|
+
if (event?.method !== 'turn/completed')
|
|
155
|
+
continue;
|
|
156
|
+
const params = event.params;
|
|
157
|
+
const turn = params?.turn && typeof params.turn === 'object'
|
|
158
|
+
? params.turn
|
|
159
|
+
: {};
|
|
160
|
+
if (turn.status && turn.status !== 'completed')
|
|
161
|
+
continue;
|
|
162
|
+
const result = typeof turn.result === 'string' ? turn.result : '';
|
|
163
|
+
if (result.trim())
|
|
164
|
+
return result;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (output.kind !== 'session-event')
|
|
168
|
+
continue;
|
|
169
|
+
if (output.event?.type !== 'turn.completed')
|
|
170
|
+
continue;
|
|
171
|
+
const payload = output.event.payload;
|
|
172
|
+
const result = typeof payload?.result === 'string' ? payload.result : '';
|
|
173
|
+
if (result.trim())
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
return '';
|
|
177
|
+
}
|
|
178
|
+
function extractTerminalFailureText(normalizedOutputs) {
|
|
179
|
+
for (const output of normalizedOutputs) {
|
|
180
|
+
if (output.kind === 'app-server-event') {
|
|
181
|
+
const event = output.event;
|
|
182
|
+
if (event?.method !== 'turn/completed' && event?.method !== 'turn/failed' && event?.method !== 'turn/cancelled') {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const params = event.params;
|
|
186
|
+
const turn = params?.turn && typeof params.turn === 'object'
|
|
187
|
+
? params.turn
|
|
188
|
+
: {};
|
|
189
|
+
const status = typeof turn.status === 'string' ? turn.status : '';
|
|
190
|
+
if (event.method === 'turn/completed' && status !== 'failed' && status !== 'cancelled') {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
const error = turn.error && typeof turn.error === 'object'
|
|
194
|
+
? turn.error
|
|
195
|
+
: {};
|
|
196
|
+
const candidates = [error.message, turn.error, params?.error, params?.message];
|
|
197
|
+
for (const candidate of candidates) {
|
|
198
|
+
if (typeof candidate === 'string' && candidate.trim())
|
|
199
|
+
return candidate.trim();
|
|
200
|
+
}
|
|
201
|
+
return status === 'cancelled' || event.method === 'turn/cancelled'
|
|
202
|
+
? 'Agent turn was cancelled.'
|
|
203
|
+
: 'Agent turn failed before producing a result.';
|
|
204
|
+
}
|
|
205
|
+
if (output.kind !== 'session-event')
|
|
206
|
+
continue;
|
|
207
|
+
if (output.event?.type !== 'turn.failed' && output.event?.type !== 'turn.cancelled')
|
|
208
|
+
continue;
|
|
209
|
+
const payload = output.event.payload;
|
|
210
|
+
const candidates = [payload?.error, payload?.message, payload?.result, payload?.stopReason];
|
|
211
|
+
for (const candidate of candidates) {
|
|
212
|
+
if (typeof candidate === 'string' && candidate.trim())
|
|
213
|
+
return candidate.trim();
|
|
214
|
+
}
|
|
215
|
+
return output.event.type === 'turn.cancelled'
|
|
216
|
+
? 'Agent turn was cancelled.'
|
|
217
|
+
: 'Agent turn failed before producing a result.';
|
|
218
|
+
}
|
|
219
|
+
return '';
|
|
220
|
+
}
|
|
221
|
+
function chunksContainTextDelta(chunks) {
|
|
222
|
+
return chunks.some((chunk) => {
|
|
223
|
+
return chunk.type === 'text-delta' && typeof chunk.delta === 'string' && chunk.delta.length > 0;
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
function chunksContainAppServerAgentMessage(chunks) {
|
|
227
|
+
return chunks.some((chunk) => isAppServerAgentMessageChunk(chunk));
|
|
228
|
+
}
|
|
229
|
+
function isAppServerAgentMessageChunk(chunk) {
|
|
230
|
+
if (chunk.type !== 'data-supen-event')
|
|
231
|
+
return false;
|
|
232
|
+
const data = chunk.data && typeof chunk.data === 'object'
|
|
233
|
+
? chunk.data
|
|
234
|
+
: null;
|
|
235
|
+
const raw = data?.raw && typeof data.raw === 'object'
|
|
236
|
+
? data.raw
|
|
237
|
+
: null;
|
|
238
|
+
const method = typeof raw?.method === 'string' ? raw.method : '';
|
|
239
|
+
if (method === 'item/agentMessage/delta')
|
|
240
|
+
return true;
|
|
241
|
+
if (method !== 'item/completed')
|
|
242
|
+
return false;
|
|
243
|
+
const params = raw?.params && typeof raw.params === 'object'
|
|
244
|
+
? raw.params
|
|
245
|
+
: null;
|
|
246
|
+
const item = params?.item && typeof params.item === 'object'
|
|
247
|
+
? params.item
|
|
248
|
+
: null;
|
|
249
|
+
return item?.type === 'agentMessage';
|
|
250
|
+
}
|
|
251
|
+
function isAppServerAgentMessageDeltaChunk(chunk) {
|
|
252
|
+
if (chunk.type !== 'data-supen-event')
|
|
253
|
+
return false;
|
|
254
|
+
const data = chunk.data && typeof chunk.data === 'object'
|
|
255
|
+
? chunk.data
|
|
256
|
+
: null;
|
|
257
|
+
const raw = data?.raw && typeof data.raw === 'object'
|
|
258
|
+
? data.raw
|
|
259
|
+
: null;
|
|
260
|
+
return raw?.method === 'item/agentMessage/delta';
|
|
261
|
+
}
|
|
262
|
+
function extractUiErrorText(chunks) {
|
|
263
|
+
for (const chunk of chunks) {
|
|
264
|
+
if (chunk.type !== 'error')
|
|
265
|
+
continue;
|
|
266
|
+
if (typeof chunk.errorText === 'string' && chunk.errorText.trim()) {
|
|
267
|
+
return chunk.errorText.trim();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return '';
|
|
271
|
+
}
|
|
272
|
+
function truncateText(text, maxChars) {
|
|
273
|
+
if (maxChars <= 0)
|
|
274
|
+
return '';
|
|
275
|
+
const chars = Array.from(text);
|
|
276
|
+
if (chars.length <= maxChars)
|
|
277
|
+
return text;
|
|
278
|
+
return `${chars.slice(0, maxChars).join('').trimEnd()}\n...[truncated]`;
|
|
279
|
+
}
|
|
280
|
+
// Memory constraints
|
|
281
|
+
const RECENT_JOURNAL_COUNT = 3;
|
|
282
|
+
const RECENT_JOURNAL_MAX_CHARS = 2_000;
|
|
283
|
+
const RECENT_JOURNAL_TOTAL_MAX_CHARS = 6_000;
|
|
284
|
+
function resolveAgentRuntimePaths(agentId) {
|
|
285
|
+
return agentPaths(agentId);
|
|
286
|
+
}
|
|
287
|
+
function nativeSessionPrewarmKey(agentId, sessionId, driverId, options) {
|
|
288
|
+
return [
|
|
289
|
+
agentId,
|
|
290
|
+
sessionId,
|
|
291
|
+
driverId,
|
|
292
|
+
options?.model || '',
|
|
293
|
+
options?.effort || '',
|
|
294
|
+
options?.permissionMode || '',
|
|
295
|
+
options?.networkAccess ? 'network' : '',
|
|
296
|
+
(options?.trustedDataHosts || []).join(','),
|
|
297
|
+
].join(':');
|
|
298
|
+
}
|
|
299
|
+
function pruneNativeSessionPrewarmCache(now = Date.now()) {
|
|
300
|
+
for (const [key, entry] of nativeSessionPrewarmCache.entries()) {
|
|
301
|
+
if (entry.expiresAt > now)
|
|
302
|
+
continue;
|
|
303
|
+
nativeSessionPrewarmCache.delete(key);
|
|
304
|
+
entry.promise
|
|
305
|
+
.then((session) => session.close())
|
|
306
|
+
.catch(() => { });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function extractUsageTotals(raw) {
|
|
310
|
+
if (!raw || typeof raw !== 'object')
|
|
311
|
+
return null;
|
|
312
|
+
const obj = raw;
|
|
313
|
+
const candidatesIn = [
|
|
314
|
+
obj.tokensIn,
|
|
315
|
+
obj.inputTokens,
|
|
316
|
+
obj.input_tokens,
|
|
317
|
+
obj.promptTokens,
|
|
318
|
+
obj.prompt_tokens,
|
|
319
|
+
obj.total_input_tokens,
|
|
320
|
+
];
|
|
321
|
+
const candidatesOut = [
|
|
322
|
+
obj.tokensOut,
|
|
323
|
+
obj.outputTokens,
|
|
324
|
+
obj.output_tokens,
|
|
325
|
+
obj.completionTokens,
|
|
326
|
+
obj.completion_tokens,
|
|
327
|
+
obj.total_output_tokens,
|
|
328
|
+
];
|
|
329
|
+
const tokensIn = candidatesIn.find((value) => Number.isFinite(Number(value)));
|
|
330
|
+
const tokensOut = candidatesOut.find((value) => Number.isFinite(Number(value)));
|
|
331
|
+
const input = Number(tokensIn || 0);
|
|
332
|
+
const output = Number(tokensOut || 0);
|
|
333
|
+
if (input <= 0 && output <= 0)
|
|
334
|
+
return null;
|
|
335
|
+
return { tokensIn: input, tokensOut: output };
|
|
336
|
+
}
|
|
337
|
+
function reportUsageToGateway(agentId, sessionId, tokensIn, tokensOut) {
|
|
338
|
+
const gateway = getGatewayInstance();
|
|
339
|
+
if (!gateway || !gateway.isConnected())
|
|
340
|
+
return;
|
|
341
|
+
const selectedModel = getAgentModelConfig(agentId, true)[0];
|
|
342
|
+
const usage = getUsageStats({
|
|
343
|
+
agent_id: agentId,
|
|
344
|
+
tokens_in: tokensIn,
|
|
345
|
+
tokens_out: tokensOut,
|
|
346
|
+
});
|
|
347
|
+
gateway.reportUsage({
|
|
348
|
+
token: getLlmToken(),
|
|
349
|
+
agent_id: agentId,
|
|
350
|
+
thread_id: sessionId,
|
|
351
|
+
provider: selectedModel?.provider_id,
|
|
352
|
+
model: selectedModel?.model,
|
|
353
|
+
input_tokens: tokensIn,
|
|
354
|
+
output_tokens: tokensOut,
|
|
355
|
+
cost_usd: usage.estimated_cost_usd,
|
|
356
|
+
timestamp: new Date().toISOString(),
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
export class AgentCortex {
|
|
360
|
+
state;
|
|
361
|
+
controller = null;
|
|
362
|
+
events;
|
|
363
|
+
lastInputTokens = 0;
|
|
364
|
+
lastOutputTokens = 0;
|
|
365
|
+
loopGuard;
|
|
366
|
+
sessionManager = new SessionManager();
|
|
367
|
+
memorySubsystem;
|
|
368
|
+
sessionRecord;
|
|
369
|
+
constructor(agentId, sessionId, events = {}) {
|
|
370
|
+
this.events = events;
|
|
371
|
+
const sessionRecord = getSessionForAgent(agentId, sessionId) ||
|
|
372
|
+
ensureSession({
|
|
373
|
+
agent_id: agentId,
|
|
374
|
+
session_id: sessionId,
|
|
375
|
+
channel: 'daemon',
|
|
376
|
+
agent_name: agentId,
|
|
377
|
+
});
|
|
378
|
+
this.sessionRecord = sessionRecord;
|
|
379
|
+
this.state = {
|
|
380
|
+
status: 'idle',
|
|
381
|
+
agent_id: agentId,
|
|
382
|
+
session_id: sessionId,
|
|
383
|
+
sdk_session_id: sessionRecord?.sdk_session_id,
|
|
384
|
+
backend_driver_id: sessionRecord?.backend_driver_id,
|
|
385
|
+
activity: { phase: 'idle' },
|
|
386
|
+
recent_logs: [],
|
|
387
|
+
last_activity_at: Date.now(),
|
|
388
|
+
};
|
|
389
|
+
this.loopGuard = new LoopGuard();
|
|
390
|
+
this.memorySubsystem = createFileMemorySubsystem(resolveAgentRuntimePaths(agentId).base);
|
|
391
|
+
}
|
|
392
|
+
getState() {
|
|
393
|
+
return { ...this.state };
|
|
394
|
+
}
|
|
395
|
+
resolveBackendDriverId(explicitDriverId) {
|
|
396
|
+
const driverId = this.sessionManager.resolveDriverId(explicitDriverId || this.state.backend_driver_id);
|
|
397
|
+
if (this.state.backend_driver_id !== driverId) {
|
|
398
|
+
this.state.backend_driver_id = driverId;
|
|
399
|
+
}
|
|
400
|
+
return driverId;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Build mcpServers config for the SDK from the MCP manager.
|
|
404
|
+
* Converts internal McpServerConfig format to SDK's expected format.
|
|
405
|
+
*/
|
|
406
|
+
async buildMcpServersConfig() {
|
|
407
|
+
// The user's global MCP config (own custom servers, catalog toggles, env
|
|
408
|
+
// overrides) is owned by the gateway. Fetch with a short TTL so every
|
|
409
|
+
// session pick-up reflects recent toggles without a per-session
|
|
410
|
+
// round-trip penalty.
|
|
411
|
+
const globalConfig = await fetchGlobalMcpConfig();
|
|
412
|
+
const localEnvOverrides = getMcpEnvOverrides();
|
|
413
|
+
const mergedEnv = {
|
|
414
|
+
...localEnvOverrides,
|
|
415
|
+
...globalConfig.mcp_server_env,
|
|
416
|
+
};
|
|
417
|
+
const disabledIds = new Set(globalConfig.disabled_mcp_server_ids);
|
|
418
|
+
const pluginMcpServers = await resolveInstalledPluginMcpServers();
|
|
419
|
+
// Preload built-in catalog MCP servers for every session, skipping ids
|
|
420
|
+
// the user disabled globally. Skills/manager declarations may override by
|
|
421
|
+
// id below.
|
|
422
|
+
const runtimeEnv = withRuntimeSpaceEnv(process.env);
|
|
423
|
+
const runtimeSpaceEnv = getRuntimeSpaceEnvVars();
|
|
424
|
+
const mergeMcpServerEnv = (config) => {
|
|
425
|
+
const merged = {
|
|
426
|
+
...runtimeSpaceEnv,
|
|
427
|
+
...(config.env || {}),
|
|
428
|
+
};
|
|
429
|
+
return Object.keys(merged).length > 0 ? merged : undefined;
|
|
430
|
+
};
|
|
431
|
+
const mcpServers = {
|
|
432
|
+
...resolveMcpServers(runtimeEnv, mergedEnv, disabledIds),
|
|
433
|
+
...customServersToMcpMap(globalConfig.mcp_servers),
|
|
434
|
+
...pluginMcpServers,
|
|
435
|
+
};
|
|
436
|
+
for (const [serverId, config] of Object.entries(mcpServers)) {
|
|
437
|
+
mcpServers[serverId] = {
|
|
438
|
+
...config,
|
|
439
|
+
env: mergeMcpServerEnv(config),
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
const skillDeclaredServers = resolveEnabledSkillMcpServers(this.state.agent_id);
|
|
443
|
+
for (const [serverId, config] of Object.entries(skillDeclaredServers)) {
|
|
444
|
+
mcpServers[serverId] = {
|
|
445
|
+
type: config.type,
|
|
446
|
+
command: config.command,
|
|
447
|
+
args: config.args,
|
|
448
|
+
env: mergeMcpServerEnv(config),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
if (!this.events.mcpManager) {
|
|
452
|
+
return Object.keys(mcpServers).length > 0 ? mcpServers : undefined;
|
|
453
|
+
}
|
|
454
|
+
const configs = this.events.mcpManager.configs || [];
|
|
455
|
+
if (!Array.isArray(configs) || configs.length === 0) {
|
|
456
|
+
return Object.keys(mcpServers).length > 0 ? mcpServers : undefined;
|
|
457
|
+
}
|
|
458
|
+
for (const config of configs) {
|
|
459
|
+
if (!config.enabled || !config.command)
|
|
460
|
+
continue;
|
|
461
|
+
// Convert env array to Record
|
|
462
|
+
const env = {};
|
|
463
|
+
if (config.env && Array.isArray(config.env)) {
|
|
464
|
+
for (const { key, value } of config.env) {
|
|
465
|
+
env[key] = value;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
mcpServers[config.id] = {
|
|
469
|
+
type: config.type === 'stdio' ? 'stdio' : undefined,
|
|
470
|
+
command: config.command,
|
|
471
|
+
args: config.args,
|
|
472
|
+
env: mergeMcpServerEnv({ env }),
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
return Object.keys(mcpServers).length > 0 ? mcpServers : undefined;
|
|
476
|
+
}
|
|
477
|
+
async createNativeSdkSession(options) {
|
|
478
|
+
const paths = resolveAgentRuntimePaths(this.state.agent_id);
|
|
479
|
+
const artifacts = resolveSessionTaskArtifactPaths(this.sessionRecord, this.state.task_id);
|
|
480
|
+
const sessionKey = `${this.state.agent_id}:${this.state.session_id}`;
|
|
481
|
+
const driverId = this.resolveBackendDriverId();
|
|
482
|
+
const sdkSession = createSession({ id: this.state.session_id });
|
|
483
|
+
const sdkTurn = createTurn({ sessionId: sdkSession.id });
|
|
484
|
+
this.initBrain(paths.base, artifacts.cwd);
|
|
485
|
+
ensureTaskArtifactLayout(artifacts);
|
|
486
|
+
if (shouldWaitForGatewayToken(this.state.agent_id)) {
|
|
487
|
+
// Best-effort token prefetch to reduce first-turn auth churn for backends
|
|
488
|
+
// that depend on gateway-issued provider credentials.
|
|
489
|
+
try {
|
|
490
|
+
await getLlmTokenOrWait(options?.waitForTokenTimeoutMs ?? 5_000);
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
logger.debug('runNativeStream: No LLM token from gateway yet; continuing with local auth path');
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
const mcpServers = await this.buildMcpServersConfig();
|
|
497
|
+
return this.sessionManager.createSessionForTurn({
|
|
498
|
+
driverId,
|
|
499
|
+
agentId: this.state.agent_id,
|
|
500
|
+
session: sdkSession,
|
|
501
|
+
turn: sdkTurn,
|
|
502
|
+
cwd: artifacts.cwd,
|
|
503
|
+
writableRoots: artifacts.writableRoots,
|
|
504
|
+
model: options?.model,
|
|
505
|
+
effort: options?.effort,
|
|
506
|
+
permissionMode: options?.permissionMode,
|
|
507
|
+
networkAccess: options?.networkAccess,
|
|
508
|
+
trustedDataHosts: options?.trustedDataHosts,
|
|
509
|
+
env: this.sessionRecord.environment_snapshot?.environment_variables,
|
|
510
|
+
resume: options?.resume === false ? undefined : this.state.sdk_session_id,
|
|
511
|
+
mcpServers,
|
|
512
|
+
systemPromptAppend: this.preparePrompt(paths.base, artifacts),
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
async ensureNativeSdkSession(options) {
|
|
516
|
+
const now = Date.now();
|
|
517
|
+
pruneNativeSessionPrewarmCache(now);
|
|
518
|
+
const driverId = this.resolveBackendDriverId();
|
|
519
|
+
const key = nativeSessionPrewarmKey(this.state.agent_id, this.state.session_id, driverId, options);
|
|
520
|
+
const prewarmed = nativeSessionPrewarmCache.get(key);
|
|
521
|
+
if (prewarmed && prewarmed.expiresAt > now) {
|
|
522
|
+
nativeSessionPrewarmCache.delete(key);
|
|
523
|
+
try {
|
|
524
|
+
return await prewarmed.promise;
|
|
525
|
+
}
|
|
526
|
+
catch (err) {
|
|
527
|
+
logger.debug({ err, agent_id: this.state.agent_id, session_id: this.state.session_id }, 'Native session prewarm was unavailable; creating a fresh session');
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
return this.createNativeSdkSession(options);
|
|
531
|
+
}
|
|
532
|
+
async prewarmNativeSession(options) {
|
|
533
|
+
const now = Date.now();
|
|
534
|
+
pruneNativeSessionPrewarmCache(now);
|
|
535
|
+
const driverId = this.resolveBackendDriverId();
|
|
536
|
+
const key = nativeSessionPrewarmKey(this.state.agent_id, this.state.session_id, driverId, options);
|
|
537
|
+
const existing = nativeSessionPrewarmCache.get(key);
|
|
538
|
+
if (existing && existing.expiresAt > now) {
|
|
539
|
+
try {
|
|
540
|
+
await existing.promise;
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
catch {
|
|
544
|
+
if (nativeSessionPrewarmCache.get(key) === existing) {
|
|
545
|
+
nativeSessionPrewarmCache.delete(key);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
const entry = {
|
|
550
|
+
expiresAt: now + NATIVE_SESSION_PREWARM_TTL_MS,
|
|
551
|
+
promise: this.createNativeSdkSession({
|
|
552
|
+
model: options?.model,
|
|
553
|
+
effort: options?.effort,
|
|
554
|
+
permissionMode: options?.permissionMode,
|
|
555
|
+
networkAccess: options?.networkAccess,
|
|
556
|
+
trustedDataHosts: options?.trustedDataHosts,
|
|
557
|
+
waitForTokenTimeoutMs: 1_500,
|
|
558
|
+
}).then(async (session) => {
|
|
559
|
+
await session.prepare?.();
|
|
560
|
+
return session;
|
|
561
|
+
}),
|
|
562
|
+
};
|
|
563
|
+
nativeSessionPrewarmCache.set(key, entry);
|
|
564
|
+
const timeout = setTimeout(() => {
|
|
565
|
+
if (nativeSessionPrewarmCache.get(key) !== entry)
|
|
566
|
+
return;
|
|
567
|
+
nativeSessionPrewarmCache.delete(key);
|
|
568
|
+
entry.promise
|
|
569
|
+
.then((session) => session.close())
|
|
570
|
+
.catch(() => { });
|
|
571
|
+
}, NATIVE_SESSION_PREWARM_TTL_MS);
|
|
572
|
+
timeout.unref?.();
|
|
573
|
+
try {
|
|
574
|
+
await entry.promise;
|
|
575
|
+
}
|
|
576
|
+
catch (err) {
|
|
577
|
+
if (nativeSessionPrewarmCache.get(key) === entry) {
|
|
578
|
+
nativeSessionPrewarmCache.delete(key);
|
|
579
|
+
}
|
|
580
|
+
logger.debug({ err, agent_id: this.state.agent_id, session_id: this.state.session_id }, 'Native session prewarm failed');
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async run(taskId, prompt, options) {
|
|
584
|
+
if (this.state.status === 'busy') {
|
|
585
|
+
throw new Error(`Cortex ${this.state.agent_id}:${this.state.session_id} is already busy.`);
|
|
586
|
+
}
|
|
587
|
+
this.state.task_id = taskId || `task-${Date.now()}`;
|
|
588
|
+
this.state.status = 'busy';
|
|
589
|
+
this.state.recent_logs = [];
|
|
590
|
+
this.lastInputTokens = 0;
|
|
591
|
+
this.lastOutputTokens = 0;
|
|
592
|
+
this.controller = new AbortController();
|
|
593
|
+
this.loopGuard.reset();
|
|
594
|
+
if (options?.resume === false && this.state.sdk_session_id) {
|
|
595
|
+
this.state.sdk_session_id = undefined;
|
|
596
|
+
clearSessionSdkId(this.state.agent_id, this.state.session_id);
|
|
597
|
+
}
|
|
598
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'running');
|
|
599
|
+
const paths = resolveAgentRuntimePaths(this.state.agent_id);
|
|
600
|
+
const artifacts = resolveSessionTaskArtifactPaths(this.sessionRecord, this.state.task_id);
|
|
601
|
+
this.initBrain(paths.base, artifacts.cwd);
|
|
602
|
+
ensureTaskArtifactLayout(artifacts);
|
|
603
|
+
logger.info({
|
|
604
|
+
agent_id: this.state.agent_id,
|
|
605
|
+
task_id: this.state.task_id,
|
|
606
|
+
prompt_excerpt: excerptText(prompt, 180),
|
|
607
|
+
}, 'Task started');
|
|
608
|
+
await this.notifyState();
|
|
609
|
+
let runtimeTimeout = null;
|
|
610
|
+
let runtimeTimedOut = false;
|
|
611
|
+
let activeSession = null;
|
|
612
|
+
const runtimeTimeoutMs = typeof options?.timeoutMs === 'number' && Number.isFinite(options.timeoutMs)
|
|
613
|
+
? Math.max(0, options.timeoutMs)
|
|
614
|
+
: 0;
|
|
615
|
+
const runtimeTimeoutMessage = runtimeTimeoutMs > 0
|
|
616
|
+
? `Task timed out after ${Math.round(runtimeTimeoutMs / 1000)}s.`
|
|
617
|
+
: '';
|
|
618
|
+
try {
|
|
619
|
+
if (shouldWaitForGatewayToken(this.state.agent_id)) {
|
|
620
|
+
try {
|
|
621
|
+
await getLlmTokenOrWait(options?.waitForTokenTimeoutMs ?? 5_000);
|
|
622
|
+
}
|
|
623
|
+
catch {
|
|
624
|
+
logger.debug('run: No LLM token from gateway yet; continuing with local auth path');
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const systemPrompt = [
|
|
628
|
+
this.preparePrompt(paths.base, artifacts),
|
|
629
|
+
options?.systemPromptAppend?.trim(),
|
|
630
|
+
]
|
|
631
|
+
.filter(Boolean)
|
|
632
|
+
.join('\n\n');
|
|
633
|
+
const mcpServers = await this.buildMcpServersConfig();
|
|
634
|
+
const driverId = this.resolveBackendDriverId();
|
|
635
|
+
const sdkSession = createSession({ id: this.state.session_id });
|
|
636
|
+
const sdkTurn = createTurn({ sessionId: sdkSession.id });
|
|
637
|
+
const session = await this.sessionManager.createSessionForTurn({
|
|
638
|
+
driverId,
|
|
639
|
+
agentId: this.state.agent_id,
|
|
640
|
+
session: sdkSession,
|
|
641
|
+
turn: sdkTurn,
|
|
642
|
+
cwd: artifacts.cwd,
|
|
643
|
+
writableRoots: artifacts.writableRoots,
|
|
644
|
+
model: options?.model,
|
|
645
|
+
effort: options?.effort,
|
|
646
|
+
permissionMode: options?.permissionMode,
|
|
647
|
+
networkAccess: options?.networkAccess,
|
|
648
|
+
trustedDataHosts: options?.trustedDataHosts,
|
|
649
|
+
env: this.sessionRecord.environment_snapshot?.environment_variables,
|
|
650
|
+
resume: options?.resume === false ? undefined : this.state.sdk_session_id,
|
|
651
|
+
mcpServers,
|
|
652
|
+
systemPromptAppend: systemPrompt,
|
|
653
|
+
});
|
|
654
|
+
activeSession = session;
|
|
655
|
+
if (runtimeTimeoutMs > 0) {
|
|
656
|
+
runtimeTimeout = setTimeout(() => {
|
|
657
|
+
runtimeTimedOut = true;
|
|
658
|
+
this.controller?.abort();
|
|
659
|
+
try {
|
|
660
|
+
activeSession?.close();
|
|
661
|
+
}
|
|
662
|
+
catch {
|
|
663
|
+
// Closing is best-effort; the loop below will surface the timeout.
|
|
664
|
+
}
|
|
665
|
+
}, runtimeTimeoutMs);
|
|
666
|
+
runtimeTimeout.unref?.();
|
|
667
|
+
}
|
|
668
|
+
this.state.activity.action = 'thinking';
|
|
669
|
+
await this.notifyState();
|
|
670
|
+
// Send the prompt to the SDK session
|
|
671
|
+
await session.send(prompt);
|
|
672
|
+
let finalText = '';
|
|
673
|
+
let receivedStreamedText = false;
|
|
674
|
+
const stream = session.stream();
|
|
675
|
+
for await (const message of stream) {
|
|
676
|
+
if (runtimeTimedOut) {
|
|
677
|
+
throw new Error(runtimeTimeoutMessage);
|
|
678
|
+
}
|
|
679
|
+
if (this.controller?.signal.aborted) {
|
|
680
|
+
session.close();
|
|
681
|
+
throw new Error('Aborted');
|
|
682
|
+
}
|
|
683
|
+
const msg = message;
|
|
684
|
+
if (msg.session_id && !this.state.sdk_session_id) {
|
|
685
|
+
this.state.sdk_session_id = msg.session_id;
|
|
686
|
+
updateSessionSdkId(this.state.agent_id, this.state.session_id, msg.session_id);
|
|
687
|
+
}
|
|
688
|
+
const normalizedOutputs = this.sessionManager.normalizeOutput({
|
|
689
|
+
driverId: this.state.backend_driver_id,
|
|
690
|
+
sessionId: this.state.session_id,
|
|
691
|
+
turnId: sdkTurn.id,
|
|
692
|
+
output: msg,
|
|
693
|
+
});
|
|
694
|
+
const normalizedText = appendNormalizedOutputToFinalText(normalizedOutputs, finalText);
|
|
695
|
+
finalText = normalizedText.next;
|
|
696
|
+
if (normalizedText.receivedText) {
|
|
697
|
+
receivedStreamedText = true;
|
|
698
|
+
}
|
|
699
|
+
if (msg.type === 'stream_event') {
|
|
700
|
+
const event = msg.event;
|
|
701
|
+
if (event.type === 'content_block_delta' && event.delta?.type === 'text_delta') {
|
|
702
|
+
const delta = event.delta.text;
|
|
703
|
+
if (!normalizedText.receivedText) {
|
|
704
|
+
finalText += delta;
|
|
705
|
+
}
|
|
706
|
+
if (delta.length > 0 || normalizedText.receivedText) {
|
|
707
|
+
receivedStreamedText = true;
|
|
708
|
+
}
|
|
709
|
+
this.state.activity.action = 'speaking';
|
|
710
|
+
this.state.activity.target = delta;
|
|
711
|
+
logger.info({
|
|
712
|
+
agent_id: this.state.agent_id,
|
|
713
|
+
task_id: this.state.task_id,
|
|
714
|
+
output_excerpt: buildAssistantOutputExcerpt(delta),
|
|
715
|
+
}, 'Task assistant output');
|
|
716
|
+
await this.notifyState();
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
else if (msg.type === 'result') {
|
|
720
|
+
if (msg.subtype === 'success') {
|
|
721
|
+
if (!receivedStreamedText || finalText.trim().length === 0) {
|
|
722
|
+
finalText = msg.result;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
else if (msg.type === 'tool_use') {
|
|
727
|
+
this.state.activity.action = `executing_${msg.name}`;
|
|
728
|
+
logger.info({
|
|
729
|
+
agent_id: this.state.agent_id,
|
|
730
|
+
task_id: this.state.task_id,
|
|
731
|
+
...buildObservableToolDetail({
|
|
732
|
+
tool: msg.name,
|
|
733
|
+
target: msg.input?.path ?? msg.input?.file_path ?? msg.input?.url,
|
|
734
|
+
args: msg.input,
|
|
735
|
+
}),
|
|
736
|
+
}, 'Task tool call');
|
|
737
|
+
await this.notifyState();
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
if (runtimeTimedOut) {
|
|
741
|
+
throw new Error(runtimeTimeoutMessage);
|
|
742
|
+
}
|
|
743
|
+
// Resolve workspace links for frontend
|
|
744
|
+
const wsEscaped = artifacts.artifactRoot.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
745
|
+
const wsPathRegex = new RegExp(`${wsEscaped}/([^\\s)"\']+)`, 'g');
|
|
746
|
+
finalText = finalText.replace(wsPathRegex, (_match, relPath) => {
|
|
747
|
+
const absPath = path.join(artifacts.artifactRoot, relPath);
|
|
748
|
+
if (fs.existsSync(absPath)) {
|
|
749
|
+
return `supen://workspace/${this.state.agent_id}/${relPath}`;
|
|
750
|
+
}
|
|
751
|
+
return _match;
|
|
752
|
+
});
|
|
753
|
+
await this.events.onReply?.(finalText);
|
|
754
|
+
await this.consolidateMemory(paths.base, finalText);
|
|
755
|
+
try {
|
|
756
|
+
const usage = extractUsageTotals(await session.getContextUsage?.());
|
|
757
|
+
if (usage) {
|
|
758
|
+
reportUsageToGateway(this.state.agent_id, this.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
759
|
+
try {
|
|
760
|
+
updateSessionUsage(this.state.agent_id, this.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
appendGlobalUsage(this.state.agent_id, this.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
catch (usageErr) {
|
|
768
|
+
logger.warn({
|
|
769
|
+
usageErr,
|
|
770
|
+
message: usageErr instanceof Error ? usageErr.message : String(usageErr),
|
|
771
|
+
stack: usageErr instanceof Error ? usageErr.stack : undefined,
|
|
772
|
+
agent_id: this.state.agent_id,
|
|
773
|
+
session_id: this.state.session_id,
|
|
774
|
+
}, 'Failed to persist session usage after run');
|
|
775
|
+
}
|
|
776
|
+
this.state.status = 'idle';
|
|
777
|
+
this.state.last_activity_at = Date.now();
|
|
778
|
+
this.state.activity = { phase: 'done' };
|
|
779
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'idle');
|
|
780
|
+
}
|
|
781
|
+
catch (err) {
|
|
782
|
+
if (runtimeTimedOut) {
|
|
783
|
+
this.state.status = 'error';
|
|
784
|
+
this.state.activity = { phase: 'error', action: runtimeTimeoutMessage };
|
|
785
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'error');
|
|
786
|
+
logger.error({ err, agent_id: this.state.agent_id, task_id: this.state.task_id }, 'Cortex: Task timed out');
|
|
787
|
+
try {
|
|
788
|
+
await this.events.onError?.(runtimeTimeoutMessage, new Error(runtimeTimeoutMessage));
|
|
789
|
+
}
|
|
790
|
+
catch (e) { }
|
|
791
|
+
}
|
|
792
|
+
else if (this.controller?.signal.aborted) {
|
|
793
|
+
this.state.status = 'interrupted';
|
|
794
|
+
this.state.activity = { phase: 'interrupted' };
|
|
795
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'idle');
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
this.state.status = 'error';
|
|
799
|
+
this.state.activity = { phase: 'error', action: err.message };
|
|
800
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'error');
|
|
801
|
+
logger.error({ err, agent_id: this.state.agent_id }, 'Cortex: Loop failed');
|
|
802
|
+
const displayError = `> 🚨 **Agent Pipeline Halted:**\n> ${err.message}`;
|
|
803
|
+
try {
|
|
804
|
+
if (this.events.onError) {
|
|
805
|
+
await this.events.onError(displayError, err);
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
await this.events.onReply?.(displayError);
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
catch (e) { }
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
finally {
|
|
815
|
+
if (runtimeTimeout)
|
|
816
|
+
clearTimeout(runtimeTimeout);
|
|
817
|
+
this.controller = null;
|
|
818
|
+
await this.notifyState();
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
interrupt() {
|
|
822
|
+
if (this.controller && this.state.status === 'busy') {
|
|
823
|
+
this.controller.abort();
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
async runNativeStream(taskId, messages, options) {
|
|
827
|
+
if (this.state.status === 'busy') {
|
|
828
|
+
throw new Error(`Cortex ${this.state.agent_id}:${this.state.session_id} is already busy.`);
|
|
829
|
+
}
|
|
830
|
+
this.state.task_id = taskId || `task-${Date.now()}`;
|
|
831
|
+
this.state.status = 'busy';
|
|
832
|
+
this.controller = new AbortController();
|
|
833
|
+
updateSessionStatus(this.state.agent_id, this.state.session_id, 'running');
|
|
834
|
+
const paths = resolveAgentRuntimePaths(this.state.agent_id);
|
|
835
|
+
const artifacts = resolveSessionTaskArtifactPaths(this.sessionRecord, this.state.task_id);
|
|
836
|
+
ensureTaskArtifactLayout(artifacts);
|
|
837
|
+
logger.info({
|
|
838
|
+
agent_id: this.state.agent_id,
|
|
839
|
+
task_id: this.state.task_id,
|
|
840
|
+
workspace: paths.workspace,
|
|
841
|
+
runtime_cwd: artifacts.cwd,
|
|
842
|
+
writable_artifact_root: artifacts.artifactRoot,
|
|
843
|
+
task_folder: artifacts.taskRoot,
|
|
844
|
+
}, 'Task stream setup');
|
|
845
|
+
const latestMessage = messages[messages.length - 1];
|
|
846
|
+
const prompt = typeof latestMessage.content === 'string'
|
|
847
|
+
? latestMessage.content
|
|
848
|
+
: Array.isArray(latestMessage.parts)
|
|
849
|
+
? latestMessage.parts.filter((p) => p.type === 'text').map((p) => p.text).join('')
|
|
850
|
+
: '';
|
|
851
|
+
const promptExcerpt = excerptText(prompt, 180);
|
|
852
|
+
const contextExcerpt = buildTaskContextExcerpt(messages.map((message) => ({
|
|
853
|
+
content: typeof message.content === 'string'
|
|
854
|
+
? message.content
|
|
855
|
+
: Array.isArray(message.parts)
|
|
856
|
+
? message.parts
|
|
857
|
+
.filter((part) => part.type === 'text')
|
|
858
|
+
.map((part) => part.text)
|
|
859
|
+
.join(' ')
|
|
860
|
+
: undefined,
|
|
861
|
+
})));
|
|
862
|
+
logger.info({
|
|
863
|
+
agent_id: this.state.agent_id,
|
|
864
|
+
task_id: this.state.task_id,
|
|
865
|
+
prompt_excerpt: promptExcerpt,
|
|
866
|
+
context_excerpt: contextExcerpt,
|
|
867
|
+
}, 'Task stream context');
|
|
868
|
+
storeSessionUiEvent(this.state.agent_id, this.state.session_id, {
|
|
869
|
+
id: `${this.state.task_id}:task-started:${Date.now()}`,
|
|
870
|
+
timestamp: new Date().toISOString(),
|
|
871
|
+
task_id: this.state.task_id,
|
|
872
|
+
chunk: {
|
|
873
|
+
type: 'data-supen-event',
|
|
874
|
+
data: {
|
|
875
|
+
eventType: 'system',
|
|
876
|
+
subtype: 'status',
|
|
877
|
+
raw: {
|
|
878
|
+
status: 'started',
|
|
879
|
+
message: 'Task started',
|
|
880
|
+
prompt_excerpt: promptExcerpt,
|
|
881
|
+
},
|
|
882
|
+
},
|
|
883
|
+
},
|
|
884
|
+
});
|
|
885
|
+
const encoder = new TextEncoder();
|
|
886
|
+
const agentId = this.state.agent_id;
|
|
887
|
+
const sessionId = this.state.session_id;
|
|
888
|
+
const self = this;
|
|
889
|
+
return new ReadableStream({
|
|
890
|
+
async start(controller) {
|
|
891
|
+
logger.info('runNativeStream: ReadableStream starting');
|
|
892
|
+
let finalText = '';
|
|
893
|
+
let streamError = null;
|
|
894
|
+
let streamErrorNotified = false;
|
|
895
|
+
let sdkSession = null;
|
|
896
|
+
let messageStarted = false;
|
|
897
|
+
let stepStarted = false;
|
|
898
|
+
let textStarted = false;
|
|
899
|
+
let reasoningStarted = false;
|
|
900
|
+
let textPartIndex = 0;
|
|
901
|
+
let currentTextPartId = null;
|
|
902
|
+
let reasoningPartIndex = 0;
|
|
903
|
+
let currentReasoningPartId = null;
|
|
904
|
+
let emittedTextToUi = false;
|
|
905
|
+
let receivedIncrementalText = false;
|
|
906
|
+
let receivedIncrementalReasoning = false;
|
|
907
|
+
const appServerDeltaReasoningItemIds = new Set();
|
|
908
|
+
const appServerCommandOutputByItemId = new Map();
|
|
909
|
+
const assistantMessageId = `${taskId}-assistant`;
|
|
910
|
+
const sdkSessionRecord = createSession({ id: self.state.session_id });
|
|
911
|
+
const sdkTurn = createTurn({ sessionId: sdkSessionRecord.id });
|
|
912
|
+
const isAborted = () => self.controller?.signal.aborted === true;
|
|
913
|
+
const abortSdkSession = () => {
|
|
914
|
+
try {
|
|
915
|
+
sdkSession?.close();
|
|
916
|
+
}
|
|
917
|
+
catch (err) {
|
|
918
|
+
logger.debug({ err }, 'runNativeStream: failed to close SDK session during abort');
|
|
919
|
+
}
|
|
920
|
+
};
|
|
921
|
+
self.controller?.signal.addEventListener('abort', abortSdkSession, { once: true });
|
|
922
|
+
const persistUiChunks = (chunks) => {
|
|
923
|
+
const timestamp = new Date().toISOString();
|
|
924
|
+
for (const chunk of chunks) {
|
|
925
|
+
storeSessionUiEvent(self.state.agent_id, self.state.session_id, {
|
|
926
|
+
id: `${taskId}:${timestamp}:${Math.random().toString(36).slice(2, 8)}`,
|
|
927
|
+
timestamp,
|
|
928
|
+
task_id: taskId,
|
|
929
|
+
chunk,
|
|
930
|
+
});
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
const nextTextPartId = () => {
|
|
934
|
+
textPartIndex += 1;
|
|
935
|
+
return String(textPartIndex);
|
|
936
|
+
};
|
|
937
|
+
const nextReasoningPartId = () => {
|
|
938
|
+
reasoningPartIndex += 1;
|
|
939
|
+
return `reasoning-${reasoningPartIndex}`;
|
|
940
|
+
};
|
|
941
|
+
const isToolChunk = (chunk) => {
|
|
942
|
+
return typeof chunk.type === 'string' && chunk.type.startsWith('tool-');
|
|
943
|
+
};
|
|
944
|
+
const enqueueUiMessageChunks = (chunks) => {
|
|
945
|
+
if (chunks.length === 0)
|
|
946
|
+
return;
|
|
947
|
+
const normalizedChunks = [];
|
|
948
|
+
if (!messageStarted) {
|
|
949
|
+
normalizedChunks.push({ type: 'start', messageId: assistantMessageId });
|
|
950
|
+
messageStarted = true;
|
|
951
|
+
}
|
|
952
|
+
if (!stepStarted) {
|
|
953
|
+
normalizedChunks.push({ type: 'start-step' });
|
|
954
|
+
stepStarted = true;
|
|
955
|
+
}
|
|
956
|
+
for (const chunk of chunks) {
|
|
957
|
+
if (chunk.type === 'text-start') {
|
|
958
|
+
if (textStarted && currentTextPartId) {
|
|
959
|
+
normalizedChunks.push({ type: 'text-end', id: currentTextPartId });
|
|
960
|
+
}
|
|
961
|
+
currentTextPartId = typeof chunk.id === 'string' && chunk.id.trim()
|
|
962
|
+
? chunk.id
|
|
963
|
+
: nextTextPartId();
|
|
964
|
+
textStarted = true;
|
|
965
|
+
normalizedChunks.push({ ...chunk, id: currentTextPartId });
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
if (chunk.type === 'text-delta') {
|
|
969
|
+
if (!textStarted || !currentTextPartId) {
|
|
970
|
+
currentTextPartId = nextTextPartId();
|
|
971
|
+
normalizedChunks.push({ type: 'text-start', id: currentTextPartId });
|
|
972
|
+
textStarted = true;
|
|
973
|
+
}
|
|
974
|
+
normalizedChunks.push({ ...chunk, id: currentTextPartId });
|
|
975
|
+
continue;
|
|
976
|
+
}
|
|
977
|
+
if (chunk.type === 'text-end') {
|
|
978
|
+
const id = currentTextPartId || (typeof chunk.id === 'string' ? chunk.id : undefined);
|
|
979
|
+
if (textStarted && id) {
|
|
980
|
+
normalizedChunks.push({ ...chunk, id });
|
|
981
|
+
}
|
|
982
|
+
textStarted = false;
|
|
983
|
+
currentTextPartId = null;
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
if (chunk.type === 'reasoning-start') {
|
|
987
|
+
if (reasoningStarted && currentReasoningPartId) {
|
|
988
|
+
normalizedChunks.push({ type: 'reasoning-end', id: currentReasoningPartId });
|
|
989
|
+
}
|
|
990
|
+
currentReasoningPartId = typeof chunk.id === 'string' && chunk.id.trim()
|
|
991
|
+
? chunk.id
|
|
992
|
+
: nextReasoningPartId();
|
|
993
|
+
reasoningStarted = true;
|
|
994
|
+
normalizedChunks.push({ ...chunk, id: currentReasoningPartId });
|
|
995
|
+
continue;
|
|
996
|
+
}
|
|
997
|
+
if (chunk.type === 'reasoning-delta') {
|
|
998
|
+
if (!reasoningStarted || !currentReasoningPartId) {
|
|
999
|
+
currentReasoningPartId = nextReasoningPartId();
|
|
1000
|
+
normalizedChunks.push({ type: 'reasoning-start', id: currentReasoningPartId });
|
|
1001
|
+
reasoningStarted = true;
|
|
1002
|
+
}
|
|
1003
|
+
normalizedChunks.push({ ...chunk, id: currentReasoningPartId });
|
|
1004
|
+
continue;
|
|
1005
|
+
}
|
|
1006
|
+
if (chunk.type === 'reasoning-end') {
|
|
1007
|
+
const id = currentReasoningPartId || (typeof chunk.id === 'string' ? chunk.id : undefined);
|
|
1008
|
+
if (reasoningStarted && id) {
|
|
1009
|
+
normalizedChunks.push({ ...chunk, id });
|
|
1010
|
+
}
|
|
1011
|
+
reasoningStarted = false;
|
|
1012
|
+
currentReasoningPartId = null;
|
|
1013
|
+
continue;
|
|
1014
|
+
}
|
|
1015
|
+
if (isToolChunk(chunk) && textStarted && currentTextPartId) {
|
|
1016
|
+
normalizedChunks.push({ type: 'text-end', id: currentTextPartId });
|
|
1017
|
+
textStarted = false;
|
|
1018
|
+
currentTextPartId = null;
|
|
1019
|
+
}
|
|
1020
|
+
normalizedChunks.push(chunk);
|
|
1021
|
+
}
|
|
1022
|
+
if (chunksContainTextDelta(normalizedChunks)) {
|
|
1023
|
+
emittedTextToUi = true;
|
|
1024
|
+
}
|
|
1025
|
+
if (chunksContainAppServerAgentMessage(normalizedChunks)) {
|
|
1026
|
+
emittedTextToUi = true;
|
|
1027
|
+
}
|
|
1028
|
+
persistUiChunks(normalizedChunks);
|
|
1029
|
+
const persistedChunks = normalizedChunks.filter(shouldPersistUiChunkToChat);
|
|
1030
|
+
const payload = serializeUiMessageChunks(persistedChunks);
|
|
1031
|
+
if (payload) {
|
|
1032
|
+
controller.enqueue(encoder.encode(payload));
|
|
1033
|
+
}
|
|
1034
|
+
};
|
|
1035
|
+
const finishUiMessage = (finishReason = 'stop') => {
|
|
1036
|
+
if (!messageStarted)
|
|
1037
|
+
return;
|
|
1038
|
+
const chunks = [];
|
|
1039
|
+
if (textStarted && currentTextPartId) {
|
|
1040
|
+
chunks.push({ type: 'text-end', id: currentTextPartId });
|
|
1041
|
+
textStarted = false;
|
|
1042
|
+
currentTextPartId = null;
|
|
1043
|
+
}
|
|
1044
|
+
if (reasoningStarted && currentReasoningPartId) {
|
|
1045
|
+
chunks.push({ type: 'reasoning-end', id: currentReasoningPartId });
|
|
1046
|
+
reasoningStarted = false;
|
|
1047
|
+
currentReasoningPartId = null;
|
|
1048
|
+
}
|
|
1049
|
+
if (stepStarted) {
|
|
1050
|
+
chunks.push({ type: 'finish-step' });
|
|
1051
|
+
stepStarted = false;
|
|
1052
|
+
}
|
|
1053
|
+
chunks.push({ type: 'finish', finishReason });
|
|
1054
|
+
messageStarted = false;
|
|
1055
|
+
persistUiChunks(chunks);
|
|
1056
|
+
const payload = serializeUiMessageChunks(chunks);
|
|
1057
|
+
if (payload) {
|
|
1058
|
+
controller.enqueue(encoder.encode(payload));
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
const emitStreamError = (errorText) => {
|
|
1062
|
+
const chunks = [];
|
|
1063
|
+
if (textStarted && currentTextPartId) {
|
|
1064
|
+
chunks.push({ type: 'text-end', id: currentTextPartId });
|
|
1065
|
+
textStarted = false;
|
|
1066
|
+
currentTextPartId = null;
|
|
1067
|
+
}
|
|
1068
|
+
if (reasoningStarted && currentReasoningPartId) {
|
|
1069
|
+
chunks.push({ type: 'reasoning-end', id: currentReasoningPartId });
|
|
1070
|
+
reasoningStarted = false;
|
|
1071
|
+
currentReasoningPartId = null;
|
|
1072
|
+
}
|
|
1073
|
+
if (stepStarted) {
|
|
1074
|
+
chunks.push({ type: 'finish-step' });
|
|
1075
|
+
stepStarted = false;
|
|
1076
|
+
}
|
|
1077
|
+
chunks.push({ type: 'error', errorText });
|
|
1078
|
+
persistUiChunks(chunks);
|
|
1079
|
+
const payload = serializeUiMessageChunks(chunks);
|
|
1080
|
+
if (payload) {
|
|
1081
|
+
controller.enqueue(encoder.encode(payload));
|
|
1082
|
+
}
|
|
1083
|
+
};
|
|
1084
|
+
const notifyStreamError = async (error) => {
|
|
1085
|
+
if (streamErrorNotified)
|
|
1086
|
+
return;
|
|
1087
|
+
streamErrorNotified = true;
|
|
1088
|
+
try {
|
|
1089
|
+
await self.events.onError?.(`> 🚨 **Agent Pipeline Halted:**\n> ${error.message || 'Stream execution failed'}`, error);
|
|
1090
|
+
}
|
|
1091
|
+
catch (callbackError) {
|
|
1092
|
+
logger.error({ err: callbackError }, 'runNativeStream: onError failed');
|
|
1093
|
+
}
|
|
1094
|
+
};
|
|
1095
|
+
enqueueUiMessageChunks([
|
|
1096
|
+
{
|
|
1097
|
+
type: 'data-supen-event',
|
|
1098
|
+
data: {
|
|
1099
|
+
eventType: 'system',
|
|
1100
|
+
subtype: 'status',
|
|
1101
|
+
raw: {
|
|
1102
|
+
type: 'system',
|
|
1103
|
+
subtype: 'status',
|
|
1104
|
+
status: 'requesting',
|
|
1105
|
+
message: 'Thinking',
|
|
1106
|
+
},
|
|
1107
|
+
},
|
|
1108
|
+
},
|
|
1109
|
+
]);
|
|
1110
|
+
try {
|
|
1111
|
+
sdkSession = await self.ensureNativeSdkSession({
|
|
1112
|
+
model: options?.model,
|
|
1113
|
+
effort: options?.effort,
|
|
1114
|
+
permissionMode: options?.permissionMode,
|
|
1115
|
+
networkAccess: options?.networkAccess,
|
|
1116
|
+
trustedDataHosts: options?.trustedDataHosts,
|
|
1117
|
+
waitForTokenTimeoutMs: 5_000,
|
|
1118
|
+
});
|
|
1119
|
+
logger.info({
|
|
1120
|
+
agent_id: agentId,
|
|
1121
|
+
task_id: self.state.task_id,
|
|
1122
|
+
prompt_excerpt: excerptText(prompt, 180),
|
|
1123
|
+
}, 'Task prompt sent');
|
|
1124
|
+
if (isAborted()) {
|
|
1125
|
+
abortSdkSession();
|
|
1126
|
+
throw new Error('Aborted');
|
|
1127
|
+
}
|
|
1128
|
+
const visualAttachments = resolveRuntimeAttachments(latestMessage, artifacts);
|
|
1129
|
+
const runtimeInput = visualAttachments.length > 0
|
|
1130
|
+
? { text: prompt, attachments: visualAttachments }
|
|
1131
|
+
: prompt;
|
|
1132
|
+
await sdkSession.send(runtimeInput);
|
|
1133
|
+
const stream = sdkSession.stream();
|
|
1134
|
+
logger.debug('runNativeStream: stream object obtained, starting manual iteration');
|
|
1135
|
+
const iterator = stream[Symbol.asyncIterator]();
|
|
1136
|
+
while (true) {
|
|
1137
|
+
if (isAborted()) {
|
|
1138
|
+
abortSdkSession();
|
|
1139
|
+
throw new Error('Aborted');
|
|
1140
|
+
}
|
|
1141
|
+
logger.debug('runNativeStream: waiting for next stream message...');
|
|
1142
|
+
const nextResult = await iterator.next();
|
|
1143
|
+
if (isAborted()) {
|
|
1144
|
+
abortSdkSession();
|
|
1145
|
+
throw new Error('Aborted');
|
|
1146
|
+
}
|
|
1147
|
+
if (nextResult.done) {
|
|
1148
|
+
logger.debug('runNativeStream: stream done');
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
const message = nextResult.value;
|
|
1152
|
+
if (!message) {
|
|
1153
|
+
logger.debug('runNativeStream: empty SDK message, ending stream');
|
|
1154
|
+
break;
|
|
1155
|
+
}
|
|
1156
|
+
logger.debug({
|
|
1157
|
+
agent_id: agentId,
|
|
1158
|
+
task_id: self.state.task_id,
|
|
1159
|
+
type: message.type,
|
|
1160
|
+
method: typeof message.method === 'string' ? message.method : undefined,
|
|
1161
|
+
}, 'Task stream event');
|
|
1162
|
+
if (message.session_id && !self.state.sdk_session_id) {
|
|
1163
|
+
self.state.sdk_session_id = message.session_id;
|
|
1164
|
+
updateSessionSdkId(self.state.agent_id, self.state.session_id, message.session_id);
|
|
1165
|
+
}
|
|
1166
|
+
if (message.type === 'assistant') {
|
|
1167
|
+
const phase = typeof message.phase === 'string' ? message.phase : '';
|
|
1168
|
+
if (!phase && Array.isArray(message.message?.content)) {
|
|
1169
|
+
for (const block of message.message.content) {
|
|
1170
|
+
if (block.type === 'text') {
|
|
1171
|
+
if (!receivedIncrementalText && typeof block.text === 'string' && block.text.length > 0) {
|
|
1172
|
+
finalText += block.text;
|
|
1173
|
+
logger.info({
|
|
1174
|
+
agent_id: agentId,
|
|
1175
|
+
task_id: self.state.task_id,
|
|
1176
|
+
output_excerpt: buildAssistantOutputExcerpt(block.text),
|
|
1177
|
+
}, 'Task assistant output');
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
else if (message.type === 'stream_event') {
|
|
1184
|
+
const inner = message.event;
|
|
1185
|
+
if (inner.type === 'content_block_delta' && inner.delta?.type === 'text_delta') {
|
|
1186
|
+
if (typeof inner.delta.text === 'string' && inner.delta.text.length > 0) {
|
|
1187
|
+
finalText += inner.delta.text;
|
|
1188
|
+
receivedIncrementalText = true;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
else if (inner.type === 'content_block_delta' &&
|
|
1192
|
+
inner.delta?.type === 'thinking_delta' &&
|
|
1193
|
+
typeof inner.delta.thinking === 'string' &&
|
|
1194
|
+
inner.delta.thinking.length > 0) {
|
|
1195
|
+
receivedIncrementalReasoning = true;
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
const normalizedOutputs = self.sessionManager.normalizeOutput({
|
|
1199
|
+
driverId: self.state.backend_driver_id,
|
|
1200
|
+
sessionId: self.state.session_id,
|
|
1201
|
+
turnId: sdkTurn.id,
|
|
1202
|
+
output: message,
|
|
1203
|
+
});
|
|
1204
|
+
if (normalizedOutputs.length > 0) {
|
|
1205
|
+
logger.debug({
|
|
1206
|
+
agent_id: agentId,
|
|
1207
|
+
task_id: self.state.task_id,
|
|
1208
|
+
normalized_output_count: normalizedOutputs.length,
|
|
1209
|
+
normalized_output_kinds: normalizedOutputs.map((entry) => entry.kind),
|
|
1210
|
+
}, 'Task normalized backend outputs');
|
|
1211
|
+
}
|
|
1212
|
+
if (normalizedOutputs.some((output) => output.kind === 'app-server-event')) {
|
|
1213
|
+
const normalizedText = appendNormalizedOutputToFinalText(normalizedOutputs, finalText);
|
|
1214
|
+
if (normalizedText.receivedText) {
|
|
1215
|
+
finalText = normalizedText.next;
|
|
1216
|
+
receivedIncrementalText = true;
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
const completedReasoningSnapshotIdsWithPriorDeltas = new Set();
|
|
1220
|
+
for (const output of normalizedOutputs) {
|
|
1221
|
+
if (output.kind !== 'app-server-event')
|
|
1222
|
+
continue;
|
|
1223
|
+
const event = output.event;
|
|
1224
|
+
const params = event.params && typeof event.params === 'object'
|
|
1225
|
+
? event.params
|
|
1226
|
+
: {};
|
|
1227
|
+
if (APP_SERVER_REASONING_DELTA_METHODS.has(event.method)) {
|
|
1228
|
+
const itemId = typeof params.itemId === 'string' ? params.itemId : '';
|
|
1229
|
+
if (itemId) {
|
|
1230
|
+
appServerDeltaReasoningItemIds.add(itemId);
|
|
1231
|
+
}
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
if (event.method === 'item/agentMessage/delta') {
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
if (event.method !== 'item/completed')
|
|
1238
|
+
continue;
|
|
1239
|
+
const item = params.item && typeof params.item === 'object'
|
|
1240
|
+
? params.item
|
|
1241
|
+
: {};
|
|
1242
|
+
const itemId = typeof item.id === 'string' ? item.id : '';
|
|
1243
|
+
if (item.type === 'reasoning' && itemId && appServerDeltaReasoningItemIds.has(itemId)) {
|
|
1244
|
+
completedReasoningSnapshotIdsWithPriorDeltas.add(itemId);
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
const normalizedChunksBaseRaw = convertDriverOutputsToUiMessageChunks(normalizedOutputs, {
|
|
1248
|
+
commandOutputByItemId: appServerCommandOutputByItemId,
|
|
1249
|
+
});
|
|
1250
|
+
const normalizedChunksBase = normalizedChunksBaseRaw.filter((chunk) => {
|
|
1251
|
+
if (chunk.type === 'reasoning-delta' &&
|
|
1252
|
+
typeof chunk.id === 'string' &&
|
|
1253
|
+
completedReasoningSnapshotIdsWithPriorDeltas.has(chunk.id)) {
|
|
1254
|
+
return false;
|
|
1255
|
+
}
|
|
1256
|
+
return true;
|
|
1257
|
+
});
|
|
1258
|
+
const fallbackChunksBase = convertSdkEventToUiMessageChunks(message);
|
|
1259
|
+
const baseChunksSource = normalizedChunksBase.length > 0
|
|
1260
|
+
? normalizedChunksBase
|
|
1261
|
+
: fallbackChunksBase;
|
|
1262
|
+
const hasAppServerAgentMessageEvent = normalizedOutputs.some((output) => output.kind === 'app-server-event');
|
|
1263
|
+
const baseChunks = baseChunksSource.filter((chunk) => {
|
|
1264
|
+
if (receivedIncrementalText &&
|
|
1265
|
+
hasAppServerAgentMessageEvent &&
|
|
1266
|
+
isAppServerAgentMessageDeltaChunk(chunk)) {
|
|
1267
|
+
return false;
|
|
1268
|
+
}
|
|
1269
|
+
if (receivedIncrementalText &&
|
|
1270
|
+
message.type === 'assistant' &&
|
|
1271
|
+
normalizedChunksBase.length === 0 &&
|
|
1272
|
+
chunk.type === 'text-delta') {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
if (receivedIncrementalReasoning &&
|
|
1276
|
+
message.type === 'assistant' &&
|
|
1277
|
+
(chunk.type === 'reasoning-start' ||
|
|
1278
|
+
chunk.type === 'reasoning-delta' ||
|
|
1279
|
+
chunk.type === 'reasoning-end')) {
|
|
1280
|
+
return false;
|
|
1281
|
+
}
|
|
1282
|
+
return true;
|
|
1283
|
+
});
|
|
1284
|
+
const chunks = enrichUiMessageChunksWithDocumentRefs(baseChunks, {
|
|
1285
|
+
agentId,
|
|
1286
|
+
workspaceRoot: artifacts.artifactRoot,
|
|
1287
|
+
});
|
|
1288
|
+
const emittedErrorChunk = chunks.some((chunk) => chunk.type === 'error');
|
|
1289
|
+
const uiErrorText = extractUiErrorText(chunks);
|
|
1290
|
+
if (uiErrorText && !streamError) {
|
|
1291
|
+
streamError = new Error(uiErrorText);
|
|
1292
|
+
}
|
|
1293
|
+
if (chunks.length > 0) {
|
|
1294
|
+
logger.debug({
|
|
1295
|
+
agent_id: agentId,
|
|
1296
|
+
task_id: self.state.task_id,
|
|
1297
|
+
output_excerpt: buildAssistantOutputExcerpt(serializeUiMessageChunks(chunks)?.trim() ?? ''),
|
|
1298
|
+
}, 'Task stream chunk');
|
|
1299
|
+
enqueueUiMessageChunks(chunks);
|
|
1300
|
+
}
|
|
1301
|
+
const terminalResultText = extractTerminalResultText(normalizedOutputs);
|
|
1302
|
+
if (terminalResultText && !finalText.trim()) {
|
|
1303
|
+
finalText = terminalResultText;
|
|
1304
|
+
}
|
|
1305
|
+
if (terminalResultText && !emittedTextToUi) {
|
|
1306
|
+
enqueueUiMessageChunks([
|
|
1307
|
+
{ type: 'text-delta', id: '1', delta: terminalResultText },
|
|
1308
|
+
]);
|
|
1309
|
+
}
|
|
1310
|
+
const terminalFailureText = extractTerminalFailureText(normalizedOutputs);
|
|
1311
|
+
if (terminalFailureText && !streamError) {
|
|
1312
|
+
streamError = new Error(terminalFailureText);
|
|
1313
|
+
clearSessionSdkId(self.state.agent_id, self.state.session_id);
|
|
1314
|
+
self.state.sdk_session_id = undefined;
|
|
1315
|
+
}
|
|
1316
|
+
if (message.type === 'result') {
|
|
1317
|
+
logger.info({
|
|
1318
|
+
agent_id: agentId,
|
|
1319
|
+
task_id: self.state.task_id,
|
|
1320
|
+
...buildObservableToolDetail({
|
|
1321
|
+
result: message.result ?? message,
|
|
1322
|
+
}),
|
|
1323
|
+
}, 'Task completed');
|
|
1324
|
+
if (message.subtype === 'success' &&
|
|
1325
|
+
typeof message.result === 'string' &&
|
|
1326
|
+
message.result.length > 0 &&
|
|
1327
|
+
!emittedTextToUi) {
|
|
1328
|
+
finalText = message.result;
|
|
1329
|
+
emittedTextToUi = true;
|
|
1330
|
+
enqueueUiMessageChunks([
|
|
1331
|
+
{ type: 'text-delta', id: '1', delta: message.result },
|
|
1332
|
+
]);
|
|
1333
|
+
}
|
|
1334
|
+
if (message.subtype === 'success' && message.result) {
|
|
1335
|
+
// Background process, no need to await in stream loop
|
|
1336
|
+
self.consolidateMemory(paths.base, message.result).catch(err => {
|
|
1337
|
+
logger.error({ err }, 'runNativeStream: memory consolidation failed');
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
if (message.subtype !== 'success' && !streamError) {
|
|
1341
|
+
const resultText = typeof message.result === 'string' && message.result.trim()
|
|
1342
|
+
? message.result.trim()
|
|
1343
|
+
: 'Agent turn failed before producing a result.';
|
|
1344
|
+
streamError = new Error(resultText);
|
|
1345
|
+
}
|
|
1346
|
+
if (!emittedErrorChunk) {
|
|
1347
|
+
finishUiMessage(message.subtype === 'success' ? 'stop' : 'error');
|
|
1348
|
+
}
|
|
1349
|
+
break;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
if (messageStarted) {
|
|
1353
|
+
if (!emittedTextToUi) {
|
|
1354
|
+
const errorText = streamError?.message || 'Agent stream ended before producing a visible response.';
|
|
1355
|
+
emitStreamError(errorText);
|
|
1356
|
+
streamError = streamError || new Error(errorText);
|
|
1357
|
+
}
|
|
1358
|
+
else {
|
|
1359
|
+
finishUiMessage('stop');
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
catch (err) {
|
|
1364
|
+
if (isAborted()) {
|
|
1365
|
+
logger.info({ agent_id: agentId, task_id: self.state.task_id }, 'runNativeStream: stream aborted');
|
|
1366
|
+
finishUiMessage('stop');
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1369
|
+
logger.error({ err, agent_id: taskId }, 'runNativeStream: error in stream');
|
|
1370
|
+
streamError = err instanceof Error ? err : new Error(String(err || 'Stream execution failed'));
|
|
1371
|
+
emitStreamError(streamError.message || 'Stream execution failed');
|
|
1372
|
+
await notifyStreamError(streamError);
|
|
1373
|
+
}
|
|
1374
|
+
finally {
|
|
1375
|
+
const wasAborted = isAborted();
|
|
1376
|
+
self.controller?.signal.removeEventListener('abort', abortSdkSession);
|
|
1377
|
+
self.state.status = 'idle';
|
|
1378
|
+
self.state.last_activity_at = Date.now();
|
|
1379
|
+
updateSessionStatus(self.state.agent_id, self.state.session_id, 'idle');
|
|
1380
|
+
await self.notifyState();
|
|
1381
|
+
self.controller = null;
|
|
1382
|
+
if (streamError && !wasAborted) {
|
|
1383
|
+
await notifyStreamError(streamError);
|
|
1384
|
+
}
|
|
1385
|
+
if (!streamError && !wasAborted) {
|
|
1386
|
+
try {
|
|
1387
|
+
if (finalText) {
|
|
1388
|
+
await self.events.onReply?.(finalText);
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
catch (err) {
|
|
1392
|
+
logger.error({ err }, 'runNativeStream: onReply failed');
|
|
1393
|
+
}
|
|
1394
|
+
try {
|
|
1395
|
+
const usage = extractUsageTotals(await sdkSession?.getContextUsage?.());
|
|
1396
|
+
if (usage) {
|
|
1397
|
+
reportUsageToGateway(self.state.agent_id, self.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
1398
|
+
try {
|
|
1399
|
+
updateSessionUsage(self.state.agent_id, self.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
1400
|
+
}
|
|
1401
|
+
catch {
|
|
1402
|
+
appendGlobalUsage(self.state.agent_id, self.state.session_id, usage.tokensIn, usage.tokensOut);
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
catch (usageErr) {
|
|
1407
|
+
logger.warn({
|
|
1408
|
+
usageErr,
|
|
1409
|
+
message: usageErr instanceof Error ? usageErr.message : String(usageErr),
|
|
1410
|
+
stack: usageErr instanceof Error ? usageErr.stack : undefined,
|
|
1411
|
+
agent_id: self.state.agent_id,
|
|
1412
|
+
session_id: self.state.session_id,
|
|
1413
|
+
}, 'Failed to persist session usage after native stream run');
|
|
1414
|
+
}
|
|
1415
|
+
try {
|
|
1416
|
+
const taskFolderRemoved = cleanupTaskFolderWithoutMeaningfulArtifacts(self.state.session_id, self.state.task_id);
|
|
1417
|
+
if (taskFolderRemoved) {
|
|
1418
|
+
logger.info({
|
|
1419
|
+
agent_id: self.state.agent_id,
|
|
1420
|
+
session_id: self.state.session_id,
|
|
1421
|
+
task_id: self.state.task_id,
|
|
1422
|
+
}, 'Removed completed task folder without meaningful artifacts');
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
catch (cleanupErr) {
|
|
1426
|
+
logger.warn({
|
|
1427
|
+
cleanupErr,
|
|
1428
|
+
agent_id: self.state.agent_id,
|
|
1429
|
+
session_id: self.state.session_id,
|
|
1430
|
+
task_id: self.state.task_id,
|
|
1431
|
+
}, 'Failed to remove completed task folder without meaningful artifacts');
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
sdkSession?.close?.();
|
|
1435
|
+
controller.close();
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
}
|
|
1440
|
+
initBrain(baseDir, workspaceDir) {
|
|
1441
|
+
if (!fs.existsSync(baseDir))
|
|
1442
|
+
fs.mkdirSync(baseDir, { recursive: true });
|
|
1443
|
+
if (!fs.existsSync(workspaceDir))
|
|
1444
|
+
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
1445
|
+
const memoryDir = path.join(baseDir, 'memory');
|
|
1446
|
+
if (!fs.existsSync(memoryDir))
|
|
1447
|
+
fs.mkdirSync(memoryDir, { recursive: true });
|
|
1448
|
+
}
|
|
1449
|
+
preparePrompt(baseDir, artifacts) {
|
|
1450
|
+
const automationContract = [
|
|
1451
|
+
'Automation contract:',
|
|
1452
|
+
'Use `create_automation` to create schedules, `update_automation` to edit/pause/resume, `list_my_automations` to inspect, and `delete_automation` to remove.',
|
|
1453
|
+
'Do not call removed schedule tool names such as `CronCreate`.',
|
|
1454
|
+
'If the user asks for a reminder phrase, infer an RRULE and pass `name`, `prompt`, `rrule`, and `timezone` to `create_automation`.',
|
|
1455
|
+
'If the user asks to enable, resume, start, pause, disable, or change an automation, call `update_automation` with `id` and the right `status` or fields.',
|
|
1456
|
+
'If scheduling details are ambiguous, ask one clarifying question before creating automation.',
|
|
1457
|
+
];
|
|
1458
|
+
const parts = [
|
|
1459
|
+
artifacts?.source === 'local_folder'
|
|
1460
|
+
? `You are ${ASSISTANT_NAME}. The current working directory is the selected task local folder.`
|
|
1461
|
+
: `You are ${ASSISTANT_NAME}. The current working directory is the Supen task folder.`,
|
|
1462
|
+
artifacts
|
|
1463
|
+
? 'Uploaded task files are already in this folder. Keep generated files here and create subfolders only when the task actually needs them.'
|
|
1464
|
+
: `Use the configured Supen artifact workspace for generated files.`,
|
|
1465
|
+
artifacts
|
|
1466
|
+
? 'When executing a skill, treat this task folder as the artifact workspace. Do not assume or create a standard skill folder structure unless the task or skill explicitly needs one.'
|
|
1467
|
+
: 'When executing a skill, keep generated files in the configured Supen artifact workspace.',
|
|
1468
|
+
artifacts
|
|
1469
|
+
? 'Durable knowledge roots are writable separately from this task folder; modify them only when the user explicitly asks for persistent knowledge, memory, skill, or plugin improvements.'
|
|
1470
|
+
: `Do not write generated files into the knowledge/source workspace.`,
|
|
1471
|
+
artifacts
|
|
1472
|
+
? 'Write generated and intermediate files in the current task folder unless the user or skill asks for a more specific path.'
|
|
1473
|
+
: `Treat task inputs and knowledge/source files as read-only unless explicitly requested otherwise.`,
|
|
1474
|
+
artifacts?.source === 'local_folder'
|
|
1475
|
+
? `Do not create, modify, or interact with files outside the selected local folder unless specifically requested by the user, WITH ONE EXCEPTION:`
|
|
1476
|
+
: `Do not create, modify, or interact with files outside the current task folder unless specifically requested by the user, WITH ONE EXCEPTION:`,
|
|
1477
|
+
`Your core persona, identity, and memory are permanently stored in Markdown files located in your mind directory: ${baseDir}`,
|
|
1478
|
+
`Prefer relative paths from the current working directory over absolute paths in user-facing responses.`,
|
|
1479
|
+
automationContract.join('\n'),
|
|
1480
|
+
];
|
|
1481
|
+
// 1. Inject AGENT_MIND_FILES
|
|
1482
|
+
for (const filename of AGENT_MIND_FILES) {
|
|
1483
|
+
const p = path.join(baseDir, filename);
|
|
1484
|
+
if (fs.existsSync(p)) {
|
|
1485
|
+
const content = fs.readFileSync(p, 'utf-8').trim();
|
|
1486
|
+
if (content)
|
|
1487
|
+
parts.push(`### ${filename}\n${content}`);
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
// 2. Inject Recent Chronological Journal
|
|
1491
|
+
const memoryDir = path.join(baseDir, 'memory');
|
|
1492
|
+
if (fs.existsSync(memoryDir)) {
|
|
1493
|
+
const journals = fs
|
|
1494
|
+
.readdirSync(memoryDir)
|
|
1495
|
+
.filter((f) => f.endsWith('.md'))
|
|
1496
|
+
.sort()
|
|
1497
|
+
.slice(-RECENT_JOURNAL_COUNT);
|
|
1498
|
+
if (journals.length > 0) {
|
|
1499
|
+
parts.push('## Recent Journal (Chronological Memory)');
|
|
1500
|
+
let remainingJournalChars = RECENT_JOURNAL_TOTAL_MAX_CHARS;
|
|
1501
|
+
for (const j of journals) {
|
|
1502
|
+
if (remainingJournalChars <= 0)
|
|
1503
|
+
break;
|
|
1504
|
+
const raw = fs.readFileSync(path.join(memoryDir, j), 'utf-8').trim();
|
|
1505
|
+
if (!raw)
|
|
1506
|
+
continue;
|
|
1507
|
+
const perJournal = truncateText(raw, RECENT_JOURNAL_MAX_CHARS);
|
|
1508
|
+
const clipped = truncateText(perJournal, remainingJournalChars);
|
|
1509
|
+
if (!clipped)
|
|
1510
|
+
continue;
|
|
1511
|
+
parts.push(`### Date: ${j.replace('.md', '')}\n${clipped}`);
|
|
1512
|
+
remainingJournalChars -= clipped.length;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
}
|
|
1516
|
+
return parts.join('\n\n');
|
|
1517
|
+
}
|
|
1518
|
+
async consolidateMemory(baseDir, result) {
|
|
1519
|
+
try {
|
|
1520
|
+
if (!result || result.trim().length < 50)
|
|
1521
|
+
return;
|
|
1522
|
+
const now = new Date();
|
|
1523
|
+
const today = now.toISOString().split('T')[0];
|
|
1524
|
+
const journalPath = path.join(baseDir, 'memory', `${today}.md`);
|
|
1525
|
+
const summaryPrompt = `Analyze the following task result and extract any new information worth remembering.
|
|
1526
|
+
Classify each fact into one of these categories:
|
|
1527
|
+
- [CORE]: Permanent facts about the user, project rules, or fundamental environment settings.
|
|
1528
|
+
- [JOURNAL]: Task-specific progress, transient context, or intermediate status updates.
|
|
1529
|
+
|
|
1530
|
+
Format your output as a bulleted list:
|
|
1531
|
+
- [CATEGORY] Fact description...
|
|
1532
|
+
|
|
1533
|
+
If nothing is worth remembering, output ONLY 'No new facts'.
|
|
1534
|
+
Result:
|
|
1535
|
+
${result}`;
|
|
1536
|
+
const selectedModel = getAgentModelConfig(this.state.agent_id, true)[0];
|
|
1537
|
+
const providerId = String(selectedModel?.provider_id || '').toLowerCase();
|
|
1538
|
+
const gatewayToken = getLlmToken();
|
|
1539
|
+
const configuredApiKey = process.env.ANTHROPIC_API_KEY ||
|
|
1540
|
+
process.env.OPENROUTER_API_KEY ||
|
|
1541
|
+
selectedModel?.api_key ||
|
|
1542
|
+
'';
|
|
1543
|
+
const isGatewayBackedProvider = providerId === 'supen' || providerId === 'babelark';
|
|
1544
|
+
const llmToken = isGatewayBackedProvider
|
|
1545
|
+
? (gatewayToken || configuredApiKey)
|
|
1546
|
+
: (configuredApiKey || gatewayToken);
|
|
1547
|
+
const authSource = llmToken && llmToken === configuredApiKey
|
|
1548
|
+
? (process.env.ANTHROPIC_API_KEY
|
|
1549
|
+
? 'env:ANTHROPIC_API_KEY'
|
|
1550
|
+
: process.env.OPENROUTER_API_KEY
|
|
1551
|
+
? 'env:OPENROUTER_API_KEY'
|
|
1552
|
+
: selectedModel?.api_key
|
|
1553
|
+
? 'model:api_key'
|
|
1554
|
+
: 'unknown')
|
|
1555
|
+
: llmToken && llmToken === gatewayToken
|
|
1556
|
+
? 'gateway:llm_token'
|
|
1557
|
+
: 'none';
|
|
1558
|
+
const headers = {
|
|
1559
|
+
'Content-Type': 'application/json',
|
|
1560
|
+
};
|
|
1561
|
+
if (llmToken) {
|
|
1562
|
+
headers['Authorization'] = `Bearer ${llmToken}`;
|
|
1563
|
+
}
|
|
1564
|
+
let summary;
|
|
1565
|
+
const modelForApiDetection = selectedModel
|
|
1566
|
+
? { ...selectedModel, api_key: llmToken || selectedModel.api_key }
|
|
1567
|
+
: null;
|
|
1568
|
+
if (usesAnthropicMessagesApi(modelForApiDetection)) {
|
|
1569
|
+
const client = new Anthropic({
|
|
1570
|
+
apiKey: llmToken,
|
|
1571
|
+
baseURL: process.env.TEST_ANTHROPIC_BASE_URL || selectedModel?.base_url || undefined,
|
|
1572
|
+
});
|
|
1573
|
+
const response = await client.messages.create({
|
|
1574
|
+
model: selectedModel?.model || 'claude-3-5-sonnet-latest',
|
|
1575
|
+
max_tokens: 400,
|
|
1576
|
+
messages: [{ role: 'user', content: summaryPrompt }],
|
|
1577
|
+
});
|
|
1578
|
+
summary = response.content
|
|
1579
|
+
.filter((block) => block.type === 'text')
|
|
1580
|
+
.map((block) => block.text)
|
|
1581
|
+
.join('\n')
|
|
1582
|
+
.trim();
|
|
1583
|
+
}
|
|
1584
|
+
else {
|
|
1585
|
+
const baseUrl = process.env.TEST_ANTHROPIC_BASE_URL ||
|
|
1586
|
+
selectedModel?.base_url ||
|
|
1587
|
+
'http://127.0.0.1:2755/api/llm/openrouter';
|
|
1588
|
+
const endpoint = baseUrl.endsWith('/v1')
|
|
1589
|
+
? `${baseUrl}/chat/completions`
|
|
1590
|
+
: `${baseUrl}/v1/chat/completions`;
|
|
1591
|
+
const response = await fetch(endpoint, {
|
|
1592
|
+
method: 'POST',
|
|
1593
|
+
headers,
|
|
1594
|
+
body: JSON.stringify({
|
|
1595
|
+
model: selectedModel?.model || 'google/gemini-2.5-flash',
|
|
1596
|
+
messages: [{ role: 'user', content: summaryPrompt }],
|
|
1597
|
+
})
|
|
1598
|
+
});
|
|
1599
|
+
if (!response.ok) {
|
|
1600
|
+
throw new Error(`Failed to call LLM: ${response.status} ${response.statusText}`);
|
|
1601
|
+
}
|
|
1602
|
+
const data = await response.json();
|
|
1603
|
+
summary = data.choices?.[0]?.message?.content?.trim();
|
|
1604
|
+
}
|
|
1605
|
+
if (summary && !summary.toLowerCase().includes('no new facts')) {
|
|
1606
|
+
await this.memorySubsystem.writeEphemeral({
|
|
1607
|
+
scope: 'session',
|
|
1608
|
+
content: summary,
|
|
1609
|
+
tags: ['consolidated', 'task-result'],
|
|
1610
|
+
});
|
|
1611
|
+
const classification = classifySessionInsight({
|
|
1612
|
+
summary,
|
|
1613
|
+
successfulOutcomeCount: 0,
|
|
1614
|
+
repetitionCount: 0,
|
|
1615
|
+
});
|
|
1616
|
+
logger.info({ classification, agent_id: this.state.agent_id }, 'Classified extracted session insight');
|
|
1617
|
+
const entry = `\n- [${now.toISOString()}] Task: ${this.state.task_id}\n Facts: ${summary.replace(/\n/g, '\n ')}\n`;
|
|
1618
|
+
fs.mkdirSync(path.dirname(journalPath), { recursive: true });
|
|
1619
|
+
fs.appendFileSync(journalPath, entry, 'utf-8');
|
|
1620
|
+
if (summary.includes('[CORE]')) {
|
|
1621
|
+
const coreFacts = summary
|
|
1622
|
+
.split('\n')
|
|
1623
|
+
.filter((line) => line.includes('[CORE]'))
|
|
1624
|
+
.map((line) => line.replace(/^-?\s*\[CORE\]/, '').trim())
|
|
1625
|
+
.filter(Boolean)
|
|
1626
|
+
.join('\n');
|
|
1627
|
+
if (coreFacts) {
|
|
1628
|
+
const durable = await this.memorySubsystem.requestDurableWrite({
|
|
1629
|
+
scope: 'agent',
|
|
1630
|
+
content: coreFacts,
|
|
1631
|
+
tags: ['core-candidate'],
|
|
1632
|
+
});
|
|
1633
|
+
if (durable.status === 'denied') {
|
|
1634
|
+
logger.info({ agent_id: this.state.agent_id }, 'Durable memory write candidate requires explicit approval; skipped automatic escalation');
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
catch (err) {
|
|
1641
|
+
const selectedModel = getAgentModelConfig(this.state.agent_id, true)[0];
|
|
1642
|
+
const providerId = String(selectedModel?.provider_id || '').toLowerCase();
|
|
1643
|
+
const gatewayToken = getLlmToken();
|
|
1644
|
+
const configuredApiKey = process.env.ANTHROPIC_API_KEY ||
|
|
1645
|
+
process.env.OPENROUTER_API_KEY ||
|
|
1646
|
+
selectedModel?.api_key ||
|
|
1647
|
+
'';
|
|
1648
|
+
const isGatewayBackedProvider = providerId === 'supen' || providerId === 'babelark';
|
|
1649
|
+
const llmToken = isGatewayBackedProvider
|
|
1650
|
+
? (gatewayToken || configuredApiKey)
|
|
1651
|
+
: (configuredApiKey || gatewayToken);
|
|
1652
|
+
const authSource = llmToken && llmToken === configuredApiKey
|
|
1653
|
+
? (process.env.ANTHROPIC_API_KEY
|
|
1654
|
+
? 'env:ANTHROPIC_API_KEY'
|
|
1655
|
+
: process.env.OPENROUTER_API_KEY
|
|
1656
|
+
? 'env:OPENROUTER_API_KEY'
|
|
1657
|
+
: selectedModel?.api_key
|
|
1658
|
+
? 'model:api_key'
|
|
1659
|
+
: 'unknown')
|
|
1660
|
+
: llmToken && llmToken === gatewayToken
|
|
1661
|
+
? 'gateway:llm_token'
|
|
1662
|
+
: 'none';
|
|
1663
|
+
logger.warn({
|
|
1664
|
+
err: err.message,
|
|
1665
|
+
agent_id: this.state.agent_id,
|
|
1666
|
+
model_id: selectedModel?.id,
|
|
1667
|
+
model_provider: selectedModel?.provider_id,
|
|
1668
|
+
model_name: selectedModel?.model,
|
|
1669
|
+
auth_source: authSource,
|
|
1670
|
+
has_auth_token: Boolean(llmToken),
|
|
1671
|
+
}, 'Failed to consolidate memory');
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
async notifyState() {
|
|
1675
|
+
if (this.events.onStateChange)
|
|
1676
|
+
await this.events.onStateChange(this.getState());
|
|
1677
|
+
}
|
|
1678
|
+
async escalateToCoreMemory(baseDir, newFacts) {
|
|
1679
|
+
const memoryPath = path.join(baseDir, 'MEMORY.md');
|
|
1680
|
+
try {
|
|
1681
|
+
const currentMemory = fs.existsSync(memoryPath) ? fs.readFileSync(memoryPath, 'utf-8') : '';
|
|
1682
|
+
const updatedContent = currentMemory + '\n' + newFacts;
|
|
1683
|
+
fs.writeFileSync(memoryPath, updatedContent, 'utf-8');
|
|
1684
|
+
}
|
|
1685
|
+
catch (err) {
|
|
1686
|
+
logger.warn({ err: err.message }, 'Failed to escalate facts');
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
//# sourceMappingURL=cortex.js.map
|