@stoneforge/smithy 0.1.0
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/LICENSE +13 -0
- package/README.md +114 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +7 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/orchestrator-api.d.ts +153 -0
- package/dist/api/orchestrator-api.d.ts.map +1 -0
- package/dist/api/orchestrator-api.js +374 -0
- package/dist/api/orchestrator-api.js.map +1 -0
- package/dist/bin/sf.d.ts +3 -0
- package/dist/bin/sf.d.ts.map +1 -0
- package/dist/bin/sf.js +10 -0
- package/dist/bin/sf.js.map +1 -0
- package/dist/cli/commands/agent.d.ts +20 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +861 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/daemon.d.ts +14 -0
- package/dist/cli/commands/daemon.d.ts.map +1 -0
- package/dist/cli/commands/daemon.js +272 -0
- package/dist/cli/commands/daemon.js.map +1 -0
- package/dist/cli/commands/dispatch.d.ts +9 -0
- package/dist/cli/commands/dispatch.d.ts.map +1 -0
- package/dist/cli/commands/dispatch.js +128 -0
- package/dist/cli/commands/dispatch.js.map +1 -0
- package/dist/cli/commands/merge.d.ts +11 -0
- package/dist/cli/commands/merge.d.ts.map +1 -0
- package/dist/cli/commands/merge.js +246 -0
- package/dist/cli/commands/merge.js.map +1 -0
- package/dist/cli/commands/pool.d.ts +21 -0
- package/dist/cli/commands/pool.d.ts.map +1 -0
- package/dist/cli/commands/pool.js +762 -0
- package/dist/cli/commands/pool.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +54 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +57 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/task.d.ts +36 -0
- package/dist/cli/commands/task.d.ts.map +1 -0
- package/dist/cli/commands/task.js +889 -0
- package/dist/cli/commands/task.js.map +1 -0
- package/dist/cli/commands/test-orchestration.d.ts +32 -0
- package/dist/cli/commands/test-orchestration.d.ts.map +1 -0
- package/dist/cli/commands/test-orchestration.js +392 -0
- package/dist/cli/commands/test-orchestration.js.map +1 -0
- package/dist/cli/index.d.ts +13 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +15 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/plugin.d.ts +23 -0
- package/dist/cli/plugin.d.ts.map +1 -0
- package/dist/cli/plugin.js +36 -0
- package/dist/cli/plugin.js.map +1 -0
- package/dist/git/index.d.ts +10 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +12 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/merge.d.ts +79 -0
- package/dist/git/merge.d.ts.map +1 -0
- package/dist/git/merge.js +254 -0
- package/dist/git/merge.js.map +1 -0
- package/dist/git/worktree-manager.d.ts +299 -0
- package/dist/git/worktree-manager.d.ts.map +1 -0
- package/dist/git/worktree-manager.js +744 -0
- package/dist/git/worktree-manager.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/director.md +272 -0
- package/dist/prompts/index.d.ts +100 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +294 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/message-triage.md +50 -0
- package/dist/prompts/persistent-worker.md +240 -0
- package/dist/prompts/steward-base.md +64 -0
- package/dist/prompts/steward-docs.md +118 -0
- package/dist/prompts/steward-health.md +39 -0
- package/dist/prompts/steward-merge.md +168 -0
- package/dist/prompts/steward-ops.md +28 -0
- package/dist/prompts/steward-reminder.md +26 -0
- package/dist/prompts/worker.md +282 -0
- package/dist/providers/claude/headless.d.ts +18 -0
- package/dist/providers/claude/headless.d.ts.map +1 -0
- package/dist/providers/claude/headless.js +307 -0
- package/dist/providers/claude/headless.js.map +1 -0
- package/dist/providers/claude/index.d.ts +24 -0
- package/dist/providers/claude/index.d.ts.map +1 -0
- package/dist/providers/claude/index.js +80 -0
- package/dist/providers/claude/index.js.map +1 -0
- package/dist/providers/claude/interactive.d.ts +21 -0
- package/dist/providers/claude/interactive.d.ts.map +1 -0
- package/dist/providers/claude/interactive.js +142 -0
- package/dist/providers/claude/interactive.js.map +1 -0
- package/dist/providers/codex/event-mapper.d.ts +91 -0
- package/dist/providers/codex/event-mapper.d.ts.map +1 -0
- package/dist/providers/codex/event-mapper.js +299 -0
- package/dist/providers/codex/event-mapper.js.map +1 -0
- package/dist/providers/codex/headless.d.ts +20 -0
- package/dist/providers/codex/headless.d.ts.map +1 -0
- package/dist/providers/codex/headless.js +174 -0
- package/dist/providers/codex/headless.js.map +1 -0
- package/dist/providers/codex/index.d.ts +30 -0
- package/dist/providers/codex/index.d.ts.map +1 -0
- package/dist/providers/codex/index.js +55 -0
- package/dist/providers/codex/index.js.map +1 -0
- package/dist/providers/codex/interactive.d.ts +21 -0
- package/dist/providers/codex/interactive.d.ts.map +1 -0
- package/dist/providers/codex/interactive.js +141 -0
- package/dist/providers/codex/interactive.js.map +1 -0
- package/dist/providers/codex/jsonrpc-client.d.ts +52 -0
- package/dist/providers/codex/jsonrpc-client.d.ts.map +1 -0
- package/dist/providers/codex/jsonrpc-client.js +141 -0
- package/dist/providers/codex/jsonrpc-client.js.map +1 -0
- package/dist/providers/codex/server-manager.d.ts +100 -0
- package/dist/providers/codex/server-manager.d.ts.map +1 -0
- package/dist/providers/codex/server-manager.js +153 -0
- package/dist/providers/codex/server-manager.js.map +1 -0
- package/dist/providers/index.d.ts +15 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/opencode/async-queue.d.ts +21 -0
- package/dist/providers/opencode/async-queue.d.ts.map +1 -0
- package/dist/providers/opencode/async-queue.js +51 -0
- package/dist/providers/opencode/async-queue.js.map +1 -0
- package/dist/providers/opencode/event-mapper.d.ts +132 -0
- package/dist/providers/opencode/event-mapper.d.ts.map +1 -0
- package/dist/providers/opencode/event-mapper.js +204 -0
- package/dist/providers/opencode/event-mapper.js.map +1 -0
- package/dist/providers/opencode/headless.d.ts +25 -0
- package/dist/providers/opencode/headless.d.ts.map +1 -0
- package/dist/providers/opencode/headless.js +190 -0
- package/dist/providers/opencode/headless.js.map +1 -0
- package/dist/providers/opencode/index.d.ts +33 -0
- package/dist/providers/opencode/index.d.ts.map +1 -0
- package/dist/providers/opencode/index.js +42 -0
- package/dist/providers/opencode/index.js.map +1 -0
- package/dist/providers/opencode/interactive.d.ts +21 -0
- package/dist/providers/opencode/interactive.d.ts.map +1 -0
- package/dist/providers/opencode/interactive.js +135 -0
- package/dist/providers/opencode/interactive.js.map +1 -0
- package/dist/providers/opencode/server-manager.d.ts +145 -0
- package/dist/providers/opencode/server-manager.d.ts.map +1 -0
- package/dist/providers/opencode/server-manager.js +163 -0
- package/dist/providers/opencode/server-manager.js.map +1 -0
- package/dist/providers/registry.d.ts +38 -0
- package/dist/providers/registry.d.ts.map +1 -0
- package/dist/providers/registry.js +82 -0
- package/dist/providers/registry.js.map +1 -0
- package/dist/providers/types.d.ts +144 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +25 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/runtime/event-utils.d.ts +8 -0
- package/dist/runtime/event-utils.d.ts.map +1 -0
- package/dist/runtime/event-utils.js +23 -0
- package/dist/runtime/event-utils.js.map +1 -0
- package/dist/runtime/handoff.d.ts +195 -0
- package/dist/runtime/handoff.d.ts.map +1 -0
- package/dist/runtime/handoff.js +332 -0
- package/dist/runtime/handoff.js.map +1 -0
- package/dist/runtime/index.d.ts +17 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +60 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/message-mapper.d.ts +99 -0
- package/dist/runtime/message-mapper.d.ts.map +1 -0
- package/dist/runtime/message-mapper.js +202 -0
- package/dist/runtime/message-mapper.js.map +1 -0
- package/dist/runtime/predecessor-query.d.ts +212 -0
- package/dist/runtime/predecessor-query.d.ts.map +1 -0
- package/dist/runtime/predecessor-query.js +283 -0
- package/dist/runtime/predecessor-query.js.map +1 -0
- package/dist/runtime/session-manager.d.ts +466 -0
- package/dist/runtime/session-manager.d.ts.map +1 -0
- package/dist/runtime/session-manager.js +986 -0
- package/dist/runtime/session-manager.js.map +1 -0
- package/dist/runtime/spawner.d.ts +407 -0
- package/dist/runtime/spawner.d.ts.map +1 -0
- package/dist/runtime/spawner.js +781 -0
- package/dist/runtime/spawner.js.map +1 -0
- package/dist/server/config.d.ts +22 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +59 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/daemon-state.d.ts +50 -0
- package/dist/server/daemon-state.d.ts.map +1 -0
- package/dist/server/daemon-state.js +100 -0
- package/dist/server/daemon-state.js.map +1 -0
- package/dist/server/events-websocket.d.ts +32 -0
- package/dist/server/events-websocket.d.ts.map +1 -0
- package/dist/server/events-websocket.js +96 -0
- package/dist/server/events-websocket.js.map +1 -0
- package/dist/server/formatters.d.ts +94 -0
- package/dist/server/formatters.d.ts.map +1 -0
- package/dist/server/formatters.js +142 -0
- package/dist/server/formatters.js.map +1 -0
- package/dist/server/index.d.ts +17 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +153 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/lsp-websocket.d.ts +33 -0
- package/dist/server/lsp-websocket.d.ts.map +1 -0
- package/dist/server/lsp-websocket.js +161 -0
- package/dist/server/lsp-websocket.js.map +1 -0
- package/dist/server/routes/agents.d.ts +9 -0
- package/dist/server/routes/agents.d.ts.map +1 -0
- package/dist/server/routes/agents.js +369 -0
- package/dist/server/routes/agents.js.map +1 -0
- package/dist/server/routes/daemon.d.ts +13 -0
- package/dist/server/routes/daemon.d.ts.map +1 -0
- package/dist/server/routes/daemon.js +187 -0
- package/dist/server/routes/daemon.js.map +1 -0
- package/dist/server/routes/events.d.ts +23 -0
- package/dist/server/routes/events.d.ts.map +1 -0
- package/dist/server/routes/events.js +282 -0
- package/dist/server/routes/events.js.map +1 -0
- package/dist/server/routes/extensions.d.ts +9 -0
- package/dist/server/routes/extensions.d.ts.map +1 -0
- package/dist/server/routes/extensions.js +202 -0
- package/dist/server/routes/extensions.js.map +1 -0
- package/dist/server/routes/health.d.ts +7 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +33 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/index.d.ts +21 -0
- package/dist/server/routes/index.d.ts.map +1 -0
- package/dist/server/routes/index.js +21 -0
- package/dist/server/routes/index.js.map +1 -0
- package/dist/server/routes/lsp.d.ts +9 -0
- package/dist/server/routes/lsp.d.ts.map +1 -0
- package/dist/server/routes/lsp.js +50 -0
- package/dist/server/routes/lsp.js.map +1 -0
- package/dist/server/routes/plugins.d.ts +9 -0
- package/dist/server/routes/plugins.d.ts.map +1 -0
- package/dist/server/routes/plugins.js +109 -0
- package/dist/server/routes/plugins.js.map +1 -0
- package/dist/server/routes/pools.d.ts +9 -0
- package/dist/server/routes/pools.d.ts.map +1 -0
- package/dist/server/routes/pools.js +189 -0
- package/dist/server/routes/pools.js.map +1 -0
- package/dist/server/routes/scheduler.d.ts +9 -0
- package/dist/server/routes/scheduler.d.ts.map +1 -0
- package/dist/server/routes/scheduler.js +162 -0
- package/dist/server/routes/scheduler.js.map +1 -0
- package/dist/server/routes/sessions.d.ts +27 -0
- package/dist/server/routes/sessions.d.ts.map +1 -0
- package/dist/server/routes/sessions.js +773 -0
- package/dist/server/routes/sessions.js.map +1 -0
- package/dist/server/routes/tasks.d.ts +9 -0
- package/dist/server/routes/tasks.d.ts.map +1 -0
- package/dist/server/routes/tasks.js +954 -0
- package/dist/server/routes/tasks.js.map +1 -0
- package/dist/server/routes/upload.d.ts +8 -0
- package/dist/server/routes/upload.d.ts.map +1 -0
- package/dist/server/routes/upload.js +40 -0
- package/dist/server/routes/upload.js.map +1 -0
- package/dist/server/routes/workflows.d.ts +9 -0
- package/dist/server/routes/workflows.d.ts.map +1 -0
- package/dist/server/routes/workflows.js +532 -0
- package/dist/server/routes/workflows.js.map +1 -0
- package/dist/server/routes/workspace-files.d.ts +12 -0
- package/dist/server/routes/workspace-files.d.ts.map +1 -0
- package/dist/server/routes/workspace-files.js +520 -0
- package/dist/server/routes/workspace-files.js.map +1 -0
- package/dist/server/routes/worktrees.d.ts +9 -0
- package/dist/server/routes/worktrees.d.ts.map +1 -0
- package/dist/server/routes/worktrees.js +94 -0
- package/dist/server/routes/worktrees.js.map +1 -0
- package/dist/server/server.d.ts +14 -0
- package/dist/server/server.d.ts.map +1 -0
- package/dist/server/server.js +258 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/services/lsp-manager.d.ts +93 -0
- package/dist/server/services/lsp-manager.d.ts.map +1 -0
- package/dist/server/services/lsp-manager.js +291 -0
- package/dist/server/services/lsp-manager.js.map +1 -0
- package/dist/server/services/session-messages.d.ts +61 -0
- package/dist/server/services/session-messages.d.ts.map +1 -0
- package/dist/server/services/session-messages.js +101 -0
- package/dist/server/services/session-messages.js.map +1 -0
- package/dist/server/services.d.ts +35 -0
- package/dist/server/services.d.ts.map +1 -0
- package/dist/server/services.js +159 -0
- package/dist/server/services.js.map +1 -0
- package/dist/server/static.d.ts +18 -0
- package/dist/server/static.d.ts.map +1 -0
- package/dist/server/static.js +71 -0
- package/dist/server/static.js.map +1 -0
- package/dist/server/types.d.ts +20 -0
- package/dist/server/types.d.ts.map +1 -0
- package/dist/server/types.js +7 -0
- package/dist/server/types.js.map +1 -0
- package/dist/server/websocket.d.ts +16 -0
- package/dist/server/websocket.d.ts.map +1 -0
- package/dist/server/websocket.js +143 -0
- package/dist/server/websocket.js.map +1 -0
- package/dist/services/agent-pool-service.d.ts +181 -0
- package/dist/services/agent-pool-service.d.ts.map +1 -0
- package/dist/services/agent-pool-service.js +590 -0
- package/dist/services/agent-pool-service.js.map +1 -0
- package/dist/services/agent-registry.d.ts +185 -0
- package/dist/services/agent-registry.d.ts.map +1 -0
- package/dist/services/agent-registry.js +432 -0
- package/dist/services/agent-registry.js.map +1 -0
- package/dist/services/dispatch-daemon.d.ts +429 -0
- package/dist/services/dispatch-daemon.d.ts.map +1 -0
- package/dist/services/dispatch-daemon.js +1833 -0
- package/dist/services/dispatch-daemon.js.map +1 -0
- package/dist/services/dispatch-service.d.ts +148 -0
- package/dist/services/dispatch-service.d.ts.map +1 -0
- package/dist/services/dispatch-service.js +170 -0
- package/dist/services/dispatch-service.js.map +1 -0
- package/dist/services/docs-steward-service.d.ts +199 -0
- package/dist/services/docs-steward-service.d.ts.map +1 -0
- package/dist/services/docs-steward-service.js +599 -0
- package/dist/services/docs-steward-service.js.map +1 -0
- package/dist/services/health-steward-service.d.ts +446 -0
- package/dist/services/health-steward-service.d.ts.map +1 -0
- package/dist/services/health-steward-service.js +866 -0
- package/dist/services/health-steward-service.js.map +1 -0
- package/dist/services/index.d.ts +26 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +111 -0
- package/dist/services/index.js.map +1 -0
- package/dist/services/merge-request-provider.d.ts +59 -0
- package/dist/services/merge-request-provider.d.ts.map +1 -0
- package/dist/services/merge-request-provider.js +89 -0
- package/dist/services/merge-request-provider.js.map +1 -0
- package/dist/services/merge-steward-service.d.ts +268 -0
- package/dist/services/merge-steward-service.d.ts.map +1 -0
- package/dist/services/merge-steward-service.js +568 -0
- package/dist/services/merge-steward-service.js.map +1 -0
- package/dist/services/plugin-executor.d.ts +247 -0
- package/dist/services/plugin-executor.d.ts.map +1 -0
- package/dist/services/plugin-executor.js +451 -0
- package/dist/services/plugin-executor.js.map +1 -0
- package/dist/services/role-definition-service.d.ts +117 -0
- package/dist/services/role-definition-service.d.ts.map +1 -0
- package/dist/services/role-definition-service.js +289 -0
- package/dist/services/role-definition-service.js.map +1 -0
- package/dist/services/steward-scheduler.d.ts +336 -0
- package/dist/services/steward-scheduler.d.ts.map +1 -0
- package/dist/services/steward-scheduler.js +732 -0
- package/dist/services/steward-scheduler.js.map +1 -0
- package/dist/services/task-assignment-service.d.ts +291 -0
- package/dist/services/task-assignment-service.d.ts.map +1 -0
- package/dist/services/task-assignment-service.js +454 -0
- package/dist/services/task-assignment-service.js.map +1 -0
- package/dist/services/worker-task-service.d.ts +202 -0
- package/dist/services/worker-task-service.d.ts.map +1 -0
- package/dist/services/worker-task-service.js +228 -0
- package/dist/services/worker-task-service.js.map +1 -0
- package/dist/testing/index.d.ts +13 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +17 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/orchestration-tests.d.ts +62 -0
- package/dist/testing/orchestration-tests.d.ts.map +1 -0
- package/dist/testing/orchestration-tests.js +1115 -0
- package/dist/testing/orchestration-tests.js.map +1 -0
- package/dist/testing/test-context.d.ts +171 -0
- package/dist/testing/test-context.d.ts.map +1 -0
- package/dist/testing/test-context.js +665 -0
- package/dist/testing/test-context.js.map +1 -0
- package/dist/testing/test-prompts.d.ts +46 -0
- package/dist/testing/test-prompts.d.ts.map +1 -0
- package/dist/testing/test-prompts.js +140 -0
- package/dist/testing/test-prompts.js.map +1 -0
- package/dist/testing/test-utils.d.ts +200 -0
- package/dist/testing/test-utils.d.ts.map +1 -0
- package/dist/testing/test-utils.js +378 -0
- package/dist/testing/test-utils.js.map +1 -0
- package/dist/types/agent-pool.d.ts +215 -0
- package/dist/types/agent-pool.d.ts.map +1 -0
- package/dist/types/agent-pool.js +143 -0
- package/dist/types/agent-pool.js.map +1 -0
- package/dist/types/agent.d.ts +265 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +127 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +40 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/message-types.d.ts +294 -0
- package/dist/types/message-types.d.ts.map +1 -0
- package/dist/types/message-types.js +354 -0
- package/dist/types/message-types.js.map +1 -0
- package/dist/types/role-definition.d.ts +272 -0
- package/dist/types/role-definition.d.ts.map +1 -0
- package/dist/types/role-definition.js +144 -0
- package/dist/types/role-definition.js.map +1 -0
- package/dist/types/task-meta.d.ts +248 -0
- package/dist/types/task-meta.d.ts.map +1 -0
- package/dist/types/task-meta.js +213 -0
- package/dist/types/task-meta.js.map +1 -0
- package/package.json +120 -0
- package/web/assets/abap-BrgZPUOV.js +6 -0
- package/web/assets/apex-DyP6w7ZV.js +6 -0
- package/web/assets/azcli-BaLxmfj-.js +6 -0
- package/web/assets/bat-CFOPXBzS.js +6 -0
- package/web/assets/bicep-BfEKNvv3.js +7 -0
- package/web/assets/cameligo-BFG1Mk7z.js +6 -0
- package/web/assets/clojure-DTECt2xU.js +6 -0
- package/web/assets/codicon-DCmgc-ay.ttf +0 -0
- package/web/assets/coffee-CDGzqUPQ.js +6 -0
- package/web/assets/cpp-CLLBncYj.js +6 -0
- package/web/assets/csharp-dUCx_-0o.js +6 -0
- package/web/assets/csp-5Rap-vPy.js +6 -0
- package/web/assets/css-D3h14YRZ.js +8 -0
- package/web/assets/cssMode-DMo-5YLA.js +9 -0
- package/web/assets/cypher-DrQuvNYM.js +6 -0
- package/web/assets/dart-CFKIUWau.js +6 -0
- package/web/assets/dockerfile-Zznr-cwX.js +6 -0
- package/web/assets/ecl-Ce3n6wWz.js +6 -0
- package/web/assets/elixir-deUWdS0T.js +6 -0
- package/web/assets/flow9-i9-g7ZhI.js +6 -0
- package/web/assets/freemarker2-D4qgkQzN.js +8 -0
- package/web/assets/fsharp-CzKuDChf.js +6 -0
- package/web/assets/go-Cphgjts3.js +6 -0
- package/web/assets/graphql-Cg7bfA9N.js +6 -0
- package/web/assets/handlebars-CXFvNjQC.js +6 -0
- package/web/assets/hcl-0cvrggvQ.js +6 -0
- package/web/assets/html-oyuB_D-B.js +6 -0
- package/web/assets/htmlMode-iWuZ24-r.js +9 -0
- package/web/assets/index-DqP-_E4F.css +32 -0
- package/web/assets/index-R1cylSgw.js +1665 -0
- package/web/assets/ini-Drc7WvVn.js +6 -0
- package/web/assets/java-B_fMsGYe.js +6 -0
- package/web/assets/javascript-CRIkN2Pg.js +6 -0
- package/web/assets/jsonMode-DVDkDgex.js +15 -0
- package/web/assets/julia-Bqgm2twL.js +6 -0
- package/web/assets/kotlin-BSkB5QuD.js +6 -0
- package/web/assets/less-BsTHnhdd.js +7 -0
- package/web/assets/lexon-YWi4-JPR.js +6 -0
- package/web/assets/liquid-CSfldbB5.js +6 -0
- package/web/assets/lua-nf6ki56Z.js +6 -0
- package/web/assets/m3-Cpb6xl2v.js +6 -0
- package/web/assets/markdown-DSZPf7rp.js +6 -0
- package/web/assets/mdx-Dd58iymR.js +6 -0
- package/web/assets/mips-B_c3zf-v.js +6 -0
- package/web/assets/monaco-editor-B4lwqA13.js +751 -0
- package/web/assets/monaco-editor-CQpyCxOA.css +1 -0
- package/web/assets/msdax-rUNN04Wq.js +6 -0
- package/web/assets/mysql-DDwshQtU.js +6 -0
- package/web/assets/objective-c-B5zXfXm9.js +6 -0
- package/web/assets/pascal-CXOwvkN_.js +6 -0
- package/web/assets/pascaligo-Bc-ZgV77.js +6 -0
- package/web/assets/perl-CwNk8-XU.js +6 -0
- package/web/assets/pgsql-tGk8EFnU.js +6 -0
- package/web/assets/php-CpIb_Oan.js +6 -0
- package/web/assets/pla-B03wrqEc.js +6 -0
- package/web/assets/postiats-BKlk5iyT.js +6 -0
- package/web/assets/powerquery-Bhzvs7bI.js +6 -0
- package/web/assets/powershell-Dd3NCNK9.js +6 -0
- package/web/assets/protobuf-COyEY5Pt.js +7 -0
- package/web/assets/pug-BaJupSGV.js +6 -0
- package/web/assets/python-XWrMqdhO.js +6 -0
- package/web/assets/qsharp-DXyYeYxl.js +6 -0
- package/web/assets/r-CdQndTaG.js +6 -0
- package/web/assets/razor-DPlhCpIs.js +6 -0
- package/web/assets/redis-CVwtpugi.js +6 -0
- package/web/assets/redshift-25W9uPmb.js +6 -0
- package/web/assets/restructuredtext-DfzH4Xui.js +6 -0
- package/web/assets/router-vendor-DHlGizSU.js +41 -0
- package/web/assets/ruby-Cp1zYvxS.js +6 -0
- package/web/assets/rust-D5C2fndG.js +6 -0
- package/web/assets/sb-CDntyWJ8.js +6 -0
- package/web/assets/scala-BoFRg7Ot.js +6 -0
- package/web/assets/scheme-Bio4gycK.js +6 -0
- package/web/assets/scss-4Ik7cdeQ.js +8 -0
- package/web/assets/shell-CX-rkNHf.js +6 -0
- package/web/assets/solidity-Tw7wswEv.js +6 -0
- package/web/assets/sophia-C5WLch3f.js +6 -0
- package/web/assets/sparql-DHaeiCBh.js +6 -0
- package/web/assets/sql-CCSDG5nI.js +6 -0
- package/web/assets/st-pnP8ivHi.js +6 -0
- package/web/assets/swift-DwJ7jVG9.js +8 -0
- package/web/assets/systemverilog-B9Xyijhd.js +6 -0
- package/web/assets/tcl-DnHyzjbg.js +6 -0
- package/web/assets/tsMode-BbA1Jbf3.js +16 -0
- package/web/assets/twig-CPajHgWi.js +6 -0
- package/web/assets/typescript-DcLHYzvH.js +6 -0
- package/web/assets/typespec-D-MeaMDU.js +6 -0
- package/web/assets/ui-vendor-BSco96uv.js +51 -0
- package/web/assets/utils-vendor-DaJ2Dubl.js +911 -0
- package/web/assets/vb-DgyLZaXg.js +6 -0
- package/web/assets/wgsl-DYQUnd45.js +303 -0
- package/web/assets/xml-xKYS3dO6.js +6 -0
- package/web/assets/yaml-CNmlXqzH.js +6 -0
- package/web/favicon.ico +0 -0
- package/web/index.html +22 -0
- package/web/logo.png +0 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Routes
|
|
3
|
+
*
|
|
4
|
+
* Agent session management (start, stop, resume, stream).
|
|
5
|
+
*/
|
|
6
|
+
import { Hono } from 'hono';
|
|
7
|
+
import { streamSSE } from 'hono/streaming';
|
|
8
|
+
import { createTimestamp, ElementType } from '@stoneforge/core';
|
|
9
|
+
import { loadRolePrompt, getAgentMetadata, generateSessionBranchName, generateSessionWorktreePath, trackListeners } from '../../index.js';
|
|
10
|
+
import { formatSessionRecord } from '../formatters.js';
|
|
11
|
+
import { notifySSEClientsOfNewSession } from './events.js';
|
|
12
|
+
/**
|
|
13
|
+
* Extract and save a session event to the database.
|
|
14
|
+
* This is called immediately when events are emitted to ensure all messages
|
|
15
|
+
* are persisted, even before any SSE client connects.
|
|
16
|
+
*/
|
|
17
|
+
function saveSessionEvent(event, sessionId, agentId, sessionMessageService) {
|
|
18
|
+
const msgId = `${event.type}-${sessionId}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
19
|
+
// Skip saving system and result events (not displayed in UI)
|
|
20
|
+
if (event.type === 'system' || event.type === 'result') {
|
|
21
|
+
return msgId;
|
|
22
|
+
}
|
|
23
|
+
// Extract content from event (match client-side logic)
|
|
24
|
+
// Content can be in: event.message, event.raw?.message, event.raw?.content (if string)
|
|
25
|
+
// IMPORTANT: content MUST be a string or undefined, never an object (SQLite can't bind objects)
|
|
26
|
+
let content = typeof event.message === 'string' ? event.message : undefined;
|
|
27
|
+
if (!content && event.raw) {
|
|
28
|
+
const raw = event.raw;
|
|
29
|
+
// Only use raw.message if it's actually a string
|
|
30
|
+
if (typeof raw.message === 'string') {
|
|
31
|
+
content = raw.message;
|
|
32
|
+
}
|
|
33
|
+
else if (typeof raw.content === 'string') {
|
|
34
|
+
content = raw.content;
|
|
35
|
+
}
|
|
36
|
+
// If raw.content is an array (Claude API format), extract text from text blocks
|
|
37
|
+
if (!content && Array.isArray(raw.content)) {
|
|
38
|
+
const textParts = [];
|
|
39
|
+
for (const block of raw.content) {
|
|
40
|
+
if (typeof block === 'object' && block !== null && 'type' in block) {
|
|
41
|
+
const b = block;
|
|
42
|
+
if (b.type === 'text' && typeof b.text === 'string') {
|
|
43
|
+
textParts.push(b.text);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (textParts.length > 0) {
|
|
48
|
+
content = textParts.join('');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Extract tool info from event
|
|
53
|
+
// Check multiple locations to match client-side extraction in StreamViewer.tsx
|
|
54
|
+
const eventAny = event;
|
|
55
|
+
const eventData = eventAny.data;
|
|
56
|
+
const rawTool = event.raw?.tool;
|
|
57
|
+
const rawToolInput = event.raw?.tool_input;
|
|
58
|
+
let toolName = event.tool?.name || eventData?.name || eventAny.toolName || rawTool;
|
|
59
|
+
let toolInput = event.tool?.input || eventData?.input || eventAny.toolInput || rawToolInput;
|
|
60
|
+
let toolOutput;
|
|
61
|
+
let actualType = event.type;
|
|
62
|
+
// Check for tool_use/tool_result blocks in content arrays (Claude API format)
|
|
63
|
+
// Content array can be in multiple locations depending on event source
|
|
64
|
+
// Must match the same locations the client checks in StreamViewer.tsx
|
|
65
|
+
const raw = event.raw;
|
|
66
|
+
const rawMessage = raw?.message;
|
|
67
|
+
const eventMessage = event.message;
|
|
68
|
+
const eventContent = event.content;
|
|
69
|
+
const rawContentArray = rawMessage?.content || // raw.message.content
|
|
70
|
+
raw?.content || // raw.content
|
|
71
|
+
(typeof eventMessage === 'object' && eventMessage !== null
|
|
72
|
+
? eventMessage.content
|
|
73
|
+
: undefined) || // event.message.content
|
|
74
|
+
eventContent; // event.content
|
|
75
|
+
if (Array.isArray(rawContentArray)) {
|
|
76
|
+
for (const block of rawContentArray) {
|
|
77
|
+
if (typeof block === 'object' && block !== null && 'type' in block) {
|
|
78
|
+
const b = block;
|
|
79
|
+
if (b.type === 'tool_use' && b.name) {
|
|
80
|
+
toolName = toolName || b.name;
|
|
81
|
+
toolInput = toolInput || b.input;
|
|
82
|
+
// Override type if we found tool info but type was 'assistant'
|
|
83
|
+
if (actualType === 'assistant') {
|
|
84
|
+
actualType = 'tool_use';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (b.type === 'tool_result') {
|
|
88
|
+
toolOutput = typeof b.content === 'string' ? b.content : undefined;
|
|
89
|
+
if (actualType === 'user') {
|
|
90
|
+
actualType = 'tool_result';
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// For tool_result, check additional fallback locations (match client-side logic)
|
|
97
|
+
if (!toolOutput) {
|
|
98
|
+
toolOutput =
|
|
99
|
+
eventAny.output ||
|
|
100
|
+
eventData?.output ||
|
|
101
|
+
(actualType === 'tool_result' && typeof raw?.content === 'string' ? raw.content : undefined);
|
|
102
|
+
}
|
|
103
|
+
// For tool_result events, content should be empty (output is in toolOutput)
|
|
104
|
+
const finalContent = (actualType === 'tool_result' && toolOutput) ? undefined : content;
|
|
105
|
+
// Safely stringify tool input (JSON.stringify can return undefined for functions)
|
|
106
|
+
let toolInputStr;
|
|
107
|
+
if (toolInput !== undefined && toolInput !== null) {
|
|
108
|
+
try {
|
|
109
|
+
const str = JSON.stringify(toolInput);
|
|
110
|
+
toolInputStr = typeof str === 'string' ? str : undefined;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
toolInputStr = String(toolInput);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
sessionMessageService.saveMessage({
|
|
117
|
+
id: msgId,
|
|
118
|
+
sessionId: sessionId,
|
|
119
|
+
agentId,
|
|
120
|
+
type: actualType,
|
|
121
|
+
content: finalContent,
|
|
122
|
+
toolName: toolName,
|
|
123
|
+
toolInput: toolInputStr,
|
|
124
|
+
toolOutput: toolOutput,
|
|
125
|
+
isError: actualType === 'error',
|
|
126
|
+
});
|
|
127
|
+
return msgId;
|
|
128
|
+
}
|
|
129
|
+
// Track sessions that already have the event saver attached to avoid duplicate listeners
|
|
130
|
+
const sessionsWithEventSaver = new Set();
|
|
131
|
+
/**
|
|
132
|
+
* Clean up the session event saver tracking for a session.
|
|
133
|
+
* Call this when a session ends to allow re-attachment if the session restarts.
|
|
134
|
+
*/
|
|
135
|
+
export function cleanupSessionEventSaver(sessionId) {
|
|
136
|
+
sessionsWithEventSaver.delete(sessionId);
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Attach an event listener to save session events immediately.
|
|
140
|
+
* This ensures all events are persisted even before any SSE client connects.
|
|
141
|
+
* Uses a Set to track attached sessions and avoid duplicate listeners.
|
|
142
|
+
* Exported for use by the dispatch daemon callback.
|
|
143
|
+
*/
|
|
144
|
+
export function attachSessionEventSaver(events, sessionId, agentId, sessionMessageService) {
|
|
145
|
+
// Skip if already attached for this session
|
|
146
|
+
if (sessionsWithEventSaver.has(sessionId)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
sessionsWithEventSaver.add(sessionId);
|
|
150
|
+
const onEvent = (event) => {
|
|
151
|
+
const msgId = saveSessionEvent(event, sessionId, agentId, sessionMessageService);
|
|
152
|
+
// Attach the msgId to the event so SSE handlers can use the same ID for deduplication
|
|
153
|
+
event.msgId = msgId;
|
|
154
|
+
};
|
|
155
|
+
const onError = (error) => {
|
|
156
|
+
const msgId = `error-${sessionId}-${Date.now()}`;
|
|
157
|
+
sessionMessageService.saveMessage({
|
|
158
|
+
id: msgId,
|
|
159
|
+
sessionId: sessionId,
|
|
160
|
+
agentId,
|
|
161
|
+
type: 'error',
|
|
162
|
+
content: error.message,
|
|
163
|
+
isError: true,
|
|
164
|
+
});
|
|
165
|
+
// Attach msgId for SSE deduplication
|
|
166
|
+
error.msgId = msgId;
|
|
167
|
+
};
|
|
168
|
+
trackListeners(events, { 'event': onEvent, 'error': onError });
|
|
169
|
+
}
|
|
170
|
+
export function createSessionRoutes(services, notifyClientsOfNewSession) {
|
|
171
|
+
const { api, orchestratorApi, agentRegistry, sessionManager, spawnerService, sessionInitialPrompts, sessionMessageService } = services;
|
|
172
|
+
const app = new Hono();
|
|
173
|
+
// POST /api/agents/:id/start
|
|
174
|
+
app.post('/api/agents/:id/start', async (c) => {
|
|
175
|
+
try {
|
|
176
|
+
const agentId = c.req.param('id');
|
|
177
|
+
const body = (await c.req.json().catch(() => ({})));
|
|
178
|
+
const agent = await agentRegistry.getAgent(agentId);
|
|
179
|
+
if (!agent) {
|
|
180
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Agent not found' } }, 404);
|
|
181
|
+
}
|
|
182
|
+
const existingSession = sessionManager.getActiveSession(agentId);
|
|
183
|
+
if (existingSession) {
|
|
184
|
+
return c.json({
|
|
185
|
+
error: { code: 'SESSION_EXISTS', message: 'Agent already has an active session' },
|
|
186
|
+
existingSession: formatSessionRecord(existingSession),
|
|
187
|
+
}, 409);
|
|
188
|
+
}
|
|
189
|
+
// Get agent metadata to determine role
|
|
190
|
+
const agentMeta = getAgentMetadata(agent);
|
|
191
|
+
const agentRole = agentMeta?.agentRole;
|
|
192
|
+
const workerMode = agentRole === 'worker'
|
|
193
|
+
? agentMeta?.workerMode
|
|
194
|
+
: undefined;
|
|
195
|
+
const stewardFocus = agentRole === 'steward'
|
|
196
|
+
? agentMeta?.stewardFocus
|
|
197
|
+
: undefined;
|
|
198
|
+
console.log('[sessions] Agent metadata:', agentMeta ? `role=${agentMeta.agentRole}${workerMode ? ` mode=${workerMode}` : ''}` : 'undefined');
|
|
199
|
+
// Create worktree for persistent workers
|
|
200
|
+
let worktreePath;
|
|
201
|
+
if (workerMode === 'persistent' && services.worktreeManager) {
|
|
202
|
+
try {
|
|
203
|
+
const now = new Date();
|
|
204
|
+
const timestamp = now.getFullYear().toString()
|
|
205
|
+
+ String(now.getMonth() + 1).padStart(2, '0')
|
|
206
|
+
+ String(now.getDate()).padStart(2, '0')
|
|
207
|
+
+ String(now.getHours()).padStart(2, '0')
|
|
208
|
+
+ String(now.getMinutes()).padStart(2, '0')
|
|
209
|
+
+ String(now.getSeconds()).padStart(2, '0');
|
|
210
|
+
const agentName = agent.name ?? agentId;
|
|
211
|
+
const sessionBranch = generateSessionBranchName(agentName, timestamp);
|
|
212
|
+
const sessionPath = generateSessionWorktreePath(agentName, timestamp);
|
|
213
|
+
const worktreeResult = await services.worktreeManager.createWorktree({
|
|
214
|
+
agentName,
|
|
215
|
+
taskId: `session-${timestamp}`,
|
|
216
|
+
customBranch: sessionBranch,
|
|
217
|
+
customPath: sessionPath,
|
|
218
|
+
});
|
|
219
|
+
worktreePath = worktreeResult.worktree.path;
|
|
220
|
+
console.log(`[sessions] Created persistent worker worktree: ${worktreePath} on branch ${sessionBranch}`);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
console.warn('[sessions] Failed to create worktree for persistent worker:', err);
|
|
224
|
+
// Continue without worktree — don't block session start
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Load role-specific prompt for interactive agents (Director, persistent workers)
|
|
228
|
+
// This is prepended to any other prompt content
|
|
229
|
+
let rolePrompt;
|
|
230
|
+
if (agentRole) {
|
|
231
|
+
const roleResult = loadRolePrompt(agentRole, stewardFocus, { projectRoot: process.cwd(), workerMode });
|
|
232
|
+
console.log('[sessions] Role prompt result:', roleResult ? `${roleResult.prompt.length} chars from ${roleResult.source}` : 'undefined');
|
|
233
|
+
if (roleResult) {
|
|
234
|
+
rolePrompt = roleResult.prompt;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
let effectivePrompt = body.initialPrompt;
|
|
238
|
+
let assignedTask;
|
|
239
|
+
// Get director ID for worker prompts
|
|
240
|
+
let directorId;
|
|
241
|
+
if (agentRole === 'worker') {
|
|
242
|
+
const director = await agentRegistry.getDirector();
|
|
243
|
+
directorId = director?.id ?? 'unknown';
|
|
244
|
+
}
|
|
245
|
+
if (body.taskId) {
|
|
246
|
+
const taskResult = await api.get(body.taskId);
|
|
247
|
+
if (!taskResult || taskResult.type !== ElementType.TASK) {
|
|
248
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Task not found' } }, 404);
|
|
249
|
+
}
|
|
250
|
+
await orchestratorApi.assignTaskToAgent(body.taskId, agentId);
|
|
251
|
+
const taskPrompt = `You have been assigned the following task:
|
|
252
|
+
|
|
253
|
+
**Worker ID:** ${agentId}
|
|
254
|
+
**Director ID:** ${directorId ?? 'unknown'}
|
|
255
|
+
**Task ID**: ${taskResult.id}
|
|
256
|
+
**Title**: ${taskResult.title}
|
|
257
|
+
**Priority**: ${taskResult.priority ?? 'Not set'}
|
|
258
|
+
${taskResult.acceptanceCriteria ? `**Acceptance Criteria**: ${taskResult.acceptanceCriteria}` : ''}
|
|
259
|
+
|
|
260
|
+
Please begin working on this task. Use \`sf task get ${taskResult.id}\` to see full details if needed.`;
|
|
261
|
+
effectivePrompt = body.initialMessage
|
|
262
|
+
? `${taskPrompt}\n\n**Additional Instructions**:\n${body.initialMessage}${body.initialPrompt ? `\n\n${body.initialPrompt}` : ''}`
|
|
263
|
+
: body.initialPrompt
|
|
264
|
+
? `${taskPrompt}\n\n${body.initialPrompt}`
|
|
265
|
+
: taskPrompt;
|
|
266
|
+
assignedTask = { id: taskResult.id, title: taskResult.title };
|
|
267
|
+
}
|
|
268
|
+
else if (body.initialMessage) {
|
|
269
|
+
effectivePrompt = body.initialPrompt
|
|
270
|
+
? `${body.initialMessage}\n\n${body.initialPrompt}`
|
|
271
|
+
: body.initialMessage;
|
|
272
|
+
}
|
|
273
|
+
// Prepend role prompt if available, wrapped with clear instructions
|
|
274
|
+
// so Claude understands this is its operating instructions, not a file being opened
|
|
275
|
+
if (rolePrompt) {
|
|
276
|
+
const framedRolePrompt = `Please read and internalize the following operating instructions. These define your role and how you should behave in this session:\n\n${rolePrompt}`;
|
|
277
|
+
// Add identity section after the role prompt for directors and workers (when not already in task prompt)
|
|
278
|
+
let idSection = '';
|
|
279
|
+
if (agentRole === 'director') {
|
|
280
|
+
idSection = `\n\n**Director ID:** ${agentId}`;
|
|
281
|
+
}
|
|
282
|
+
else if (agentRole === 'worker' && !body.taskId) {
|
|
283
|
+
// Only add here if no taskId (task prompt already includes IDs)
|
|
284
|
+
idSection = `\n\n**Worker ID:** ${agentId}\n**Director ID:** ${directorId ?? 'unknown'}`;
|
|
285
|
+
}
|
|
286
|
+
effectivePrompt = effectivePrompt
|
|
287
|
+
? `${framedRolePrompt}${idSection}\n\n---\n\n${effectivePrompt}`
|
|
288
|
+
: `${framedRolePrompt}${idSection}`;
|
|
289
|
+
}
|
|
290
|
+
const { session, events } = await sessionManager.startSession(agentId, {
|
|
291
|
+
workingDirectory: worktreePath ?? body.workingDirectory,
|
|
292
|
+
worktree: body.worktree ?? worktreePath,
|
|
293
|
+
initialPrompt: effectivePrompt,
|
|
294
|
+
interactive: body.interactive,
|
|
295
|
+
cols: body.cols,
|
|
296
|
+
rows: body.rows,
|
|
297
|
+
});
|
|
298
|
+
// Attach event saver immediately to capture all events, including the first assistant response
|
|
299
|
+
// This must happen before any events are emitted to avoid missing early messages
|
|
300
|
+
attachSessionEventSaver(events, session.id, agentId, sessionMessageService);
|
|
301
|
+
if (effectivePrompt) {
|
|
302
|
+
sessionInitialPrompts.set(session.id, effectivePrompt);
|
|
303
|
+
// Save initial prompt to database immediately (don't wait for SSE connection)
|
|
304
|
+
const initialMsgId = `user-${session.id}-initial`;
|
|
305
|
+
sessionMessageService.saveMessage({
|
|
306
|
+
id: initialMsgId,
|
|
307
|
+
sessionId: session.id,
|
|
308
|
+
agentId,
|
|
309
|
+
type: 'user',
|
|
310
|
+
content: effectivePrompt,
|
|
311
|
+
isError: false,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
notifyClientsOfNewSession(agentId, session, events);
|
|
315
|
+
// Notify SSE stream clients so they dynamically subscribe to this session's events
|
|
316
|
+
notifySSEClientsOfNewSession({
|
|
317
|
+
sessionId: session.id,
|
|
318
|
+
agentId,
|
|
319
|
+
agentRole: agentRole || 'worker',
|
|
320
|
+
events,
|
|
321
|
+
});
|
|
322
|
+
return c.json({
|
|
323
|
+
success: true,
|
|
324
|
+
session: formatSessionRecord(session),
|
|
325
|
+
...(assignedTask && { assignedTask }),
|
|
326
|
+
}, 201);
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
console.error('[orchestrator] Failed to start session:', error);
|
|
330
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
// POST /api/agents/:id/stop
|
|
334
|
+
app.post('/api/agents/:id/stop', async (c) => {
|
|
335
|
+
try {
|
|
336
|
+
const agentId = c.req.param('id');
|
|
337
|
+
const body = (await c.req.json().catch(() => ({})));
|
|
338
|
+
const activeSession = sessionManager.getActiveSession(agentId);
|
|
339
|
+
if (!activeSession) {
|
|
340
|
+
try {
|
|
341
|
+
await agentRegistry.updateAgentSession(agentId, undefined, 'idle');
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Agent may not exist
|
|
345
|
+
}
|
|
346
|
+
return c.json({ success: true, message: 'No active session to stop' });
|
|
347
|
+
}
|
|
348
|
+
await sessionManager.stopSession(activeSession.id, {
|
|
349
|
+
graceful: body.graceful,
|
|
350
|
+
reason: body.reason,
|
|
351
|
+
});
|
|
352
|
+
// Clean up initial prompt and event saver tracking for this session
|
|
353
|
+
sessionInitialPrompts.delete(activeSession.id);
|
|
354
|
+
sessionsWithEventSaver.delete(activeSession.id);
|
|
355
|
+
return c.json({ success: true, sessionId: activeSession.id });
|
|
356
|
+
}
|
|
357
|
+
catch (error) {
|
|
358
|
+
console.error('[orchestrator] Failed to stop session:', error);
|
|
359
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
// POST /api/sessions/stop-all
|
|
363
|
+
app.post('/api/sessions/stop-all', async (c) => {
|
|
364
|
+
try {
|
|
365
|
+
const body = (await c.req.json().catch(() => ({})));
|
|
366
|
+
// Get all running sessions
|
|
367
|
+
const runningSessions = sessionManager.listSessions({
|
|
368
|
+
status: ['starting', 'running']
|
|
369
|
+
});
|
|
370
|
+
if (runningSessions.length === 0) {
|
|
371
|
+
return c.json({ success: true, stoppedCount: 0, message: 'No running sessions' });
|
|
372
|
+
}
|
|
373
|
+
// Stop each session
|
|
374
|
+
const results = [];
|
|
375
|
+
for (const session of runningSessions) {
|
|
376
|
+
try {
|
|
377
|
+
await sessionManager.stopSession(session.id, {
|
|
378
|
+
graceful: body.graceful,
|
|
379
|
+
reason: body.reason || 'Stopped by user via Stop All',
|
|
380
|
+
});
|
|
381
|
+
sessionInitialPrompts.delete(session.id);
|
|
382
|
+
sessionsWithEventSaver.delete(session.id);
|
|
383
|
+
results.push({ sessionId: session.id, agentId: session.agentId, success: true });
|
|
384
|
+
}
|
|
385
|
+
catch (error) {
|
|
386
|
+
results.push({
|
|
387
|
+
sessionId: session.id,
|
|
388
|
+
agentId: session.agentId,
|
|
389
|
+
success: false,
|
|
390
|
+
error: String(error)
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const stoppedCount = results.filter(r => r.success).length;
|
|
395
|
+
const failedCount = results.filter(r => !r.success).length;
|
|
396
|
+
return c.json({
|
|
397
|
+
success: failedCount === 0,
|
|
398
|
+
stoppedCount,
|
|
399
|
+
failedCount,
|
|
400
|
+
results
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
catch (error) {
|
|
404
|
+
console.error('[orchestrator] Failed to stop all sessions:', error);
|
|
405
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
// POST /api/agents/:id/interrupt
|
|
409
|
+
app.post('/api/agents/:id/interrupt', async (c) => {
|
|
410
|
+
try {
|
|
411
|
+
const agentId = c.req.param('id');
|
|
412
|
+
const activeSession = sessionManager.getActiveSession(agentId);
|
|
413
|
+
if (!activeSession) {
|
|
414
|
+
return c.json({ error: { code: 'NO_SESSION', message: 'No active session to interrupt' } }, 404);
|
|
415
|
+
}
|
|
416
|
+
await sessionManager.interruptSession(activeSession.id);
|
|
417
|
+
return c.json({ success: true, sessionId: activeSession.id });
|
|
418
|
+
}
|
|
419
|
+
catch (error) {
|
|
420
|
+
console.error('[orchestrator] Failed to interrupt session:', error);
|
|
421
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
// POST /api/agents/:id/resume
|
|
425
|
+
app.post('/api/agents/:id/resume', async (c) => {
|
|
426
|
+
try {
|
|
427
|
+
const agentId = c.req.param('id');
|
|
428
|
+
const body = (await c.req.json().catch(() => ({})));
|
|
429
|
+
const agent = await agentRegistry.getAgent(agentId);
|
|
430
|
+
if (!agent) {
|
|
431
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Agent not found' } }, 404);
|
|
432
|
+
}
|
|
433
|
+
const existingSession = sessionManager.getActiveSession(agentId);
|
|
434
|
+
if (existingSession) {
|
|
435
|
+
return c.json({
|
|
436
|
+
error: { code: 'SESSION_EXISTS', message: 'Agent already has an active session' },
|
|
437
|
+
existingSession: formatSessionRecord(existingSession),
|
|
438
|
+
}, 409);
|
|
439
|
+
}
|
|
440
|
+
let providerSessionId = body.providerSessionId;
|
|
441
|
+
if (!providerSessionId) {
|
|
442
|
+
const resumable = sessionManager.getMostRecentResumableSession(agentId);
|
|
443
|
+
if (!resumable?.providerSessionId) {
|
|
444
|
+
return c.json({ error: { code: 'NO_RESUMABLE_SESSION', message: 'No resumable session found' } }, 404);
|
|
445
|
+
}
|
|
446
|
+
providerSessionId = resumable.providerSessionId;
|
|
447
|
+
}
|
|
448
|
+
const { session, events, uwpCheck } = await sessionManager.resumeSession(agentId, {
|
|
449
|
+
providerSessionId,
|
|
450
|
+
workingDirectory: body.workingDirectory,
|
|
451
|
+
worktree: body.worktree,
|
|
452
|
+
resumePrompt: body.resumePrompt,
|
|
453
|
+
checkReadyQueue: body.checkReadyQueue,
|
|
454
|
+
});
|
|
455
|
+
// Attach event saver immediately to capture all events, including the first assistant response
|
|
456
|
+
attachSessionEventSaver(events, session.id, agentId, sessionMessageService);
|
|
457
|
+
// Save resume prompt to database if provided
|
|
458
|
+
// Use same ID pattern as start session so SSE deduplication works
|
|
459
|
+
if (body.resumePrompt) {
|
|
460
|
+
sessionInitialPrompts.set(session.id, body.resumePrompt);
|
|
461
|
+
const initialMsgId = `user-${session.id}-initial`;
|
|
462
|
+
sessionMessageService.saveMessage({
|
|
463
|
+
id: initialMsgId,
|
|
464
|
+
sessionId: session.id,
|
|
465
|
+
agentId,
|
|
466
|
+
type: 'user',
|
|
467
|
+
content: body.resumePrompt,
|
|
468
|
+
isError: false,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
notifyClientsOfNewSession(agentId, session, events);
|
|
472
|
+
// Notify SSE stream clients so they dynamically subscribe to this session's events
|
|
473
|
+
notifySSEClientsOfNewSession({
|
|
474
|
+
sessionId: session.id,
|
|
475
|
+
agentId,
|
|
476
|
+
agentRole: session.agentRole || 'worker',
|
|
477
|
+
events,
|
|
478
|
+
});
|
|
479
|
+
return c.json({ success: true, session: formatSessionRecord(session), uwpCheck }, 201);
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
console.error('[orchestrator] Failed to resume session:', error);
|
|
483
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
// GET /api/agents/:id/stream
|
|
487
|
+
app.get('/api/agents/:id/stream', async (c) => {
|
|
488
|
+
const agentId = c.req.param('id');
|
|
489
|
+
const activeSession = sessionManager.getActiveSession(agentId);
|
|
490
|
+
if (!activeSession) {
|
|
491
|
+
return c.json({ error: { code: 'NO_SESSION', message: 'Agent has no active session' } }, 404);
|
|
492
|
+
}
|
|
493
|
+
const events = sessionManager.getEventEmitter(activeSession.id);
|
|
494
|
+
if (!events) {
|
|
495
|
+
return c.json({ error: { code: 'NO_EVENTS', message: 'Session event emitter not available' } }, 404);
|
|
496
|
+
}
|
|
497
|
+
// Ensure event saver is attached for this session (handles existing sessions
|
|
498
|
+
// that were started before this code change, or if the saver wasn't attached)
|
|
499
|
+
attachSessionEventSaver(events, activeSession.id, agentId, sessionMessageService);
|
|
500
|
+
return streamSSE(c, async (stream) => {
|
|
501
|
+
let eventId = 0;
|
|
502
|
+
try {
|
|
503
|
+
await stream.writeSSE({
|
|
504
|
+
id: String(++eventId),
|
|
505
|
+
event: 'connected',
|
|
506
|
+
data: JSON.stringify({
|
|
507
|
+
sessionId: activeSession.id,
|
|
508
|
+
agentId,
|
|
509
|
+
timestamp: createTimestamp(),
|
|
510
|
+
}),
|
|
511
|
+
});
|
|
512
|
+
// Send initial prompt to every connecting client (for real-time display)
|
|
513
|
+
// Note: The initial prompt is already saved to database when session starts
|
|
514
|
+
// We keep the prompt in the map for the session duration so reconnecting clients also get it via SSE
|
|
515
|
+
const initialPrompt = sessionInitialPrompts.get(activeSession.id);
|
|
516
|
+
if (initialPrompt) {
|
|
517
|
+
const initialMsgId = `user-${activeSession.id}-initial`;
|
|
518
|
+
await stream.writeSSE({
|
|
519
|
+
id: initialMsgId,
|
|
520
|
+
event: 'agent_user',
|
|
521
|
+
data: JSON.stringify({
|
|
522
|
+
type: 'user',
|
|
523
|
+
message: initialPrompt,
|
|
524
|
+
msgId: initialMsgId, // Include ID in data for deduplication
|
|
525
|
+
raw: { type: 'user', content: initialPrompt },
|
|
526
|
+
}),
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
// Note: Events are already being saved to the database by the attachSessionEventSaver
|
|
530
|
+
// listener that was attached when the session started. The SSE handler only needs to
|
|
531
|
+
// stream events to connected clients for real-time display.
|
|
532
|
+
const onEvent = async (event) => {
|
|
533
|
+
// Use the msgId attached by saveSessionEvent if available, otherwise generate one
|
|
534
|
+
const eventWithMsgId = event;
|
|
535
|
+
const msgId = eventWithMsgId.msgId || `${event.type}-${activeSession.id}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
536
|
+
await stream.writeSSE({
|
|
537
|
+
id: msgId,
|
|
538
|
+
event: `agent_${event.type}`,
|
|
539
|
+
data: JSON.stringify({ ...event, msgId }), // Include ID in data for deduplication
|
|
540
|
+
});
|
|
541
|
+
};
|
|
542
|
+
const onError = async (error) => {
|
|
543
|
+
// Use msgId from error if attached by saveSessionEvent, otherwise generate one
|
|
544
|
+
const errorWithMsgId = error;
|
|
545
|
+
const msgId = errorWithMsgId.msgId || `error-${activeSession.id}-${Date.now()}`;
|
|
546
|
+
await stream.writeSSE({
|
|
547
|
+
id: msgId,
|
|
548
|
+
event: 'agent_error',
|
|
549
|
+
data: JSON.stringify({ error: error.message, msgId }),
|
|
550
|
+
});
|
|
551
|
+
};
|
|
552
|
+
const onExit = async (code, signal) => {
|
|
553
|
+
await stream.writeSSE({
|
|
554
|
+
id: String(++eventId),
|
|
555
|
+
event: 'agent_exit',
|
|
556
|
+
data: JSON.stringify({ code, signal }),
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
const cleanupListeners = trackListeners(events, {
|
|
560
|
+
'event': onEvent,
|
|
561
|
+
'error': onError,
|
|
562
|
+
'exit': onExit,
|
|
563
|
+
});
|
|
564
|
+
const heartbeatInterval = setInterval(async () => {
|
|
565
|
+
try {
|
|
566
|
+
await stream.writeSSE({
|
|
567
|
+
id: String(++eventId),
|
|
568
|
+
event: 'heartbeat',
|
|
569
|
+
data: JSON.stringify({ timestamp: createTimestamp() }),
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
catch {
|
|
573
|
+
clearInterval(heartbeatInterval);
|
|
574
|
+
}
|
|
575
|
+
}, 30000);
|
|
576
|
+
stream.onAbort(() => {
|
|
577
|
+
clearInterval(heartbeatInterval);
|
|
578
|
+
cleanupListeners();
|
|
579
|
+
});
|
|
580
|
+
await new Promise(() => { });
|
|
581
|
+
}
|
|
582
|
+
catch (error) {
|
|
583
|
+
console.error(`[orchestrator] SSE: Error in stream:`, error);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
// POST /api/agents/:id/input
|
|
588
|
+
app.post('/api/agents/:id/input', async (c) => {
|
|
589
|
+
try {
|
|
590
|
+
const agentId = c.req.param('id');
|
|
591
|
+
const body = (await c.req.json());
|
|
592
|
+
if (!body.input) {
|
|
593
|
+
return c.json({ error: { code: 'INVALID_INPUT', message: 'Input is required' } }, 400);
|
|
594
|
+
}
|
|
595
|
+
const activeSession = sessionManager.getActiveSession(agentId);
|
|
596
|
+
if (!activeSession) {
|
|
597
|
+
return c.json({ error: { code: 'NO_SESSION', message: 'Agent has no active session' } }, 404);
|
|
598
|
+
}
|
|
599
|
+
await spawnerService.sendInput(activeSession.id, body.input, {
|
|
600
|
+
isUserMessage: body.isUserMessage,
|
|
601
|
+
});
|
|
602
|
+
// Save user input to database if it's a user message
|
|
603
|
+
if (body.isUserMessage) {
|
|
604
|
+
const inputMsgId = `user-${activeSession.id}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
605
|
+
sessionMessageService.saveMessage({
|
|
606
|
+
id: inputMsgId,
|
|
607
|
+
sessionId: activeSession.id,
|
|
608
|
+
agentId,
|
|
609
|
+
type: 'user',
|
|
610
|
+
content: body.input,
|
|
611
|
+
isError: false,
|
|
612
|
+
});
|
|
613
|
+
}
|
|
614
|
+
return c.json({ success: true, sessionId: activeSession.id }, 202);
|
|
615
|
+
}
|
|
616
|
+
catch (error) {
|
|
617
|
+
console.error('[orchestrator] Failed to send input:', error);
|
|
618
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
619
|
+
}
|
|
620
|
+
});
|
|
621
|
+
// GET /api/sessions
|
|
622
|
+
app.get('/api/sessions', async (c) => {
|
|
623
|
+
try {
|
|
624
|
+
const url = new URL(c.req.url);
|
|
625
|
+
const agentIdParam = url.searchParams.get('agentId');
|
|
626
|
+
const roleParam = url.searchParams.get('role');
|
|
627
|
+
const statusParam = url.searchParams.get('status');
|
|
628
|
+
const resumableParam = url.searchParams.get('resumable');
|
|
629
|
+
const filter = {
|
|
630
|
+
...(agentIdParam && { agentId: agentIdParam }),
|
|
631
|
+
...(roleParam && { role: roleParam }),
|
|
632
|
+
...(statusParam && {
|
|
633
|
+
status: statusParam.includes(',')
|
|
634
|
+
? statusParam.split(',')
|
|
635
|
+
: statusParam,
|
|
636
|
+
}),
|
|
637
|
+
...(resumableParam === 'true' && { resumable: true }),
|
|
638
|
+
};
|
|
639
|
+
const sessions = sessionManager.listSessions(filter);
|
|
640
|
+
return c.json({ sessions: sessions.map(formatSessionRecord) });
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
console.error('[orchestrator] Failed to list sessions:', error);
|
|
644
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
645
|
+
}
|
|
646
|
+
});
|
|
647
|
+
// GET /api/sessions/latest-messages?sessionIds=id1,id2,...
|
|
648
|
+
// Returns the latest displayable message per session for status display on agent cards
|
|
649
|
+
app.get('/api/sessions/latest-messages', async (c) => {
|
|
650
|
+
try {
|
|
651
|
+
const url = new URL(c.req.url);
|
|
652
|
+
const sessionIdsParam = url.searchParams.get('sessionIds');
|
|
653
|
+
if (!sessionIdsParam) {
|
|
654
|
+
return c.json({ error: { code: 'INVALID_INPUT', message: 'sessionIds parameter is required' } }, 400);
|
|
655
|
+
}
|
|
656
|
+
const sessionIds = sessionIdsParam.split(',').filter(Boolean);
|
|
657
|
+
if (sessionIds.length === 0) {
|
|
658
|
+
return c.json({ messages: {} });
|
|
659
|
+
}
|
|
660
|
+
// Cap at 50 sessions to prevent abuse
|
|
661
|
+
const cappedIds = sessionIds.slice(0, 50);
|
|
662
|
+
const latestMessages = sessionMessageService.getLatestDisplayableMessages(cappedIds);
|
|
663
|
+
// Convert map to plain object for JSON serialization
|
|
664
|
+
const messagesObj = {};
|
|
665
|
+
for (const [sid, msg] of latestMessages) {
|
|
666
|
+
// Generate display content: use content if available, otherwise generate from tool info
|
|
667
|
+
let displayContent = msg.content;
|
|
668
|
+
if (!displayContent && msg.type === 'tool_use' && msg.toolName) {
|
|
669
|
+
const displayName = msg.toolName.charAt(0).toUpperCase() + msg.toolName.slice(1);
|
|
670
|
+
displayContent = `Using ${displayName}...`;
|
|
671
|
+
}
|
|
672
|
+
else if (!displayContent && msg.type === 'tool_result') {
|
|
673
|
+
displayContent = 'Tool completed';
|
|
674
|
+
}
|
|
675
|
+
messagesObj[sid] = {
|
|
676
|
+
content: displayContent,
|
|
677
|
+
type: msg.type,
|
|
678
|
+
toolName: msg.toolName,
|
|
679
|
+
timestamp: msg.createdAt,
|
|
680
|
+
agentId: msg.agentId,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
return c.json({ messages: messagesObj });
|
|
684
|
+
}
|
|
685
|
+
catch (error) {
|
|
686
|
+
console.error('[orchestrator] Failed to get latest messages:', error);
|
|
687
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
688
|
+
}
|
|
689
|
+
});
|
|
690
|
+
// GET /api/sessions/:id
|
|
691
|
+
app.get('/api/sessions/:id', async (c) => {
|
|
692
|
+
try {
|
|
693
|
+
const sessionId = c.req.param('id');
|
|
694
|
+
const session = sessionManager.getSession(sessionId);
|
|
695
|
+
if (!session) {
|
|
696
|
+
return c.json({ error: { code: 'NOT_FOUND', message: 'Session not found' } }, 404);
|
|
697
|
+
}
|
|
698
|
+
return c.json({ session: formatSessionRecord(session) });
|
|
699
|
+
}
|
|
700
|
+
catch (error) {
|
|
701
|
+
console.error('[orchestrator] Failed to get session:', error);
|
|
702
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
// GET /api/sessions/:id/messages
|
|
706
|
+
// Retrieve all messages for a session (for transcript restoration)
|
|
707
|
+
// Also loads messages from related sessions (those with the same providerSessionId)
|
|
708
|
+
// to support viewing full history of resumed sessions
|
|
709
|
+
app.get('/api/sessions/:id/messages', async (c) => {
|
|
710
|
+
try {
|
|
711
|
+
const sessionId = c.req.param('id');
|
|
712
|
+
const url = new URL(c.req.url);
|
|
713
|
+
const afterId = url.searchParams.get('after');
|
|
714
|
+
// Get the session to check for providerSessionId
|
|
715
|
+
// First check in-memory sessions, then check persisted session history
|
|
716
|
+
let providerSessionId;
|
|
717
|
+
const inMemorySession = sessionManager.getSession(sessionId);
|
|
718
|
+
if (inMemorySession?.providerSessionId) {
|
|
719
|
+
providerSessionId = inMemorySession.providerSessionId;
|
|
720
|
+
}
|
|
721
|
+
else {
|
|
722
|
+
// Session not in memory - check persisted session history for all agents
|
|
723
|
+
// This is needed when viewing historical sessions after server restart
|
|
724
|
+
const agents = await agentRegistry.listAgents();
|
|
725
|
+
for (const agent of agents) {
|
|
726
|
+
const history = await sessionManager.getSessionHistory(agent.id, 50);
|
|
727
|
+
const historyEntry = history.find(h => h.id === sessionId);
|
|
728
|
+
if (historyEntry?.providerSessionId) {
|
|
729
|
+
providerSessionId = historyEntry.providerSessionId;
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
// If we found a providerSessionId, find all related sessions and load their messages
|
|
735
|
+
if (providerSessionId) {
|
|
736
|
+
// Collect all session IDs with the same providerSessionId
|
|
737
|
+
const relatedSessionIds = new Set();
|
|
738
|
+
relatedSessionIds.add(sessionId); // Always include the requested session
|
|
739
|
+
// Check in-memory sessions
|
|
740
|
+
const allSessions = sessionManager.listSessions({});
|
|
741
|
+
for (const s of allSessions) {
|
|
742
|
+
if (s.providerSessionId === providerSessionId) {
|
|
743
|
+
relatedSessionIds.add(s.id);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// Also check persisted session history
|
|
747
|
+
const agents = await agentRegistry.listAgents();
|
|
748
|
+
for (const agent of agents) {
|
|
749
|
+
const history = await sessionManager.getSessionHistory(agent.id, 50);
|
|
750
|
+
for (const entry of history) {
|
|
751
|
+
if (entry.providerSessionId === providerSessionId) {
|
|
752
|
+
relatedSessionIds.add(entry.id);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
// Load messages from all related sessions
|
|
757
|
+
const messages = sessionMessageService.getMessagesForSessions(Array.from(relatedSessionIds));
|
|
758
|
+
return c.json({ messages });
|
|
759
|
+
}
|
|
760
|
+
// Fallback to just loading messages for this session
|
|
761
|
+
const messages = afterId
|
|
762
|
+
? sessionMessageService.getSessionMessagesAfter(sessionId, afterId)
|
|
763
|
+
: sessionMessageService.getSessionMessages(sessionId);
|
|
764
|
+
return c.json({ messages });
|
|
765
|
+
}
|
|
766
|
+
catch (error) {
|
|
767
|
+
console.error('[orchestrator] Failed to get session messages:', error);
|
|
768
|
+
return c.json({ error: { code: 'INTERNAL_ERROR', message: String(error) } }, 500);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
return app;
|
|
772
|
+
}
|
|
773
|
+
//# sourceMappingURL=sessions.js.map
|