@roj-ai/sdk 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap.js +191 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/builtin-events.js +8 -0
- package/dist/builtin-events.js.map +1 -0
- package/dist/bun-platform/fs.js +39 -0
- package/dist/bun-platform/fs.js.map +1 -0
- package/dist/bun-platform/index.js +18 -0
- package/dist/bun-platform/index.js.map +1 -0
- package/dist/bun-platform/process.js +21 -0
- package/dist/bun-platform/process.js.map +1 -0
- package/dist/config.js +54 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.js +155 -0
- package/dist/config.test.js.map +1 -0
- package/dist/core/agent-loop.integration.test.js +414 -0
- package/dist/core/agent-loop.integration.test.js.map +1 -0
- package/dist/core/agents/agent-config.test.js +194 -0
- package/dist/core/agents/agent-config.test.js.map +1 -0
- package/dist/core/agents/agent-roles.js +25 -0
- package/dist/core/agents/agent-roles.js.map +1 -0
- package/dist/core/agents/agent-shutdown.test.js +180 -0
- package/dist/core/agents/agent-shutdown.test.js.map +1 -0
- package/dist/core/agents/agent.js +1205 -0
- package/dist/core/agents/agent.js.map +1 -0
- package/dist/core/agents/agent.test.js +313 -0
- package/dist/core/agents/agent.test.js.map +1 -0
- package/dist/core/agents/communicator.js +13 -0
- package/dist/core/agents/communicator.js.map +1 -0
- package/dist/core/agents/config.js +5 -0
- package/dist/core/agents/config.js.map +1 -0
- package/dist/core/agents/context.js +2 -0
- package/dist/core/agents/context.js.map +1 -0
- package/dist/core/agents/debounce.js +74 -0
- package/dist/core/agents/debounce.js.map +1 -0
- package/dist/core/agents/handler-events.test.js +115 -0
- package/dist/core/agents/handler-events.test.js.map +1 -0
- package/dist/core/agents/index.js +2 -0
- package/dist/core/agents/index.js.map +1 -0
- package/dist/core/agents/response-sanitizer.js +46 -0
- package/dist/core/agents/response-sanitizer.js.map +1 -0
- package/dist/core/agents/response-sanitizer.test.js +101 -0
- package/dist/core/agents/response-sanitizer.test.js.map +1 -0
- package/dist/core/agents/retry.js +105 -0
- package/dist/core/agents/retry.js.map +1 -0
- package/dist/core/agents/schema.js +39 -0
- package/dist/core/agents/schema.js.map +1 -0
- package/dist/core/agents/state.js +90 -0
- package/dist/core/agents/state.js.map +1 -0
- package/dist/core/context/state.js +23 -0
- package/dist/core/context/state.js.map +1 -0
- package/dist/core/errors.js +38 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/event-sourcing.integration.test.js +154 -0
- package/dist/core/event-sourcing.integration.test.js.map +1 -0
- package/dist/core/events/base-event-store.js +201 -0
- package/dist/core/events/base-event-store.js.map +1 -0
- package/dist/core/events/event-store.js +26 -0
- package/dist/core/events/event-store.js.map +1 -0
- package/dist/core/events/file.js +320 -0
- package/dist/core/events/file.js.map +1 -0
- package/dist/core/events/file.test.js +284 -0
- package/dist/core/events/file.test.js.map +1 -0
- package/dist/core/events/index.js +3 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/events/memory.js +101 -0
- package/dist/core/events/memory.js.map +1 -0
- package/dist/core/events/memory.test.js +502 -0
- package/dist/core/events/memory.test.js.map +1 -0
- package/dist/core/events/metadata-utils.js +107 -0
- package/dist/core/events/metadata-utils.js.map +1 -0
- package/dist/core/events/test-helpers.js +15 -0
- package/dist/core/events/test-helpers.js.map +1 -0
- package/dist/core/events/types.js +21 -0
- package/dist/core/events/types.js.map +1 -0
- package/dist/core/file-store/file-store.js +250 -0
- package/dist/core/file-store/file-store.js.map +1 -0
- package/dist/core/file-store/types.js +7 -0
- package/dist/core/file-store/types.js.map +1 -0
- package/dist/core/image/image-processor.js +106 -0
- package/dist/core/image/image-processor.js.map +1 -0
- package/dist/core/image/image-processor.test.js +171 -0
- package/dist/core/image/image-processor.test.js.map +1 -0
- package/dist/core/image/index.js +4 -0
- package/dist/core/image/index.js.map +1 -0
- package/dist/core/image/noop-resizer.js +6 -0
- package/dist/core/image/noop-resizer.js.map +1 -0
- package/dist/core/image/types.js +2 -0
- package/dist/core/image/types.js.map +1 -0
- package/dist/core/image/vips-resizer.js +100 -0
- package/dist/core/image/vips-resizer.js.map +1 -0
- package/dist/core/image/vips-resizer.test.js +324 -0
- package/dist/core/image/vips-resizer.test.js.map +1 -0
- package/dist/core/llm/anthropic.js +396 -0
- package/dist/core/llm/anthropic.js.map +1 -0
- package/dist/core/llm/anthropic.test.js +434 -0
- package/dist/core/llm/anthropic.test.js.map +1 -0
- package/dist/core/llm/cache-breakpoints.js +37 -0
- package/dist/core/llm/cache-breakpoints.js.map +1 -0
- package/dist/core/llm/cache-live.test.js +137 -0
- package/dist/core/llm/cache-live.test.js.map +1 -0
- package/dist/core/llm/index.js +9 -0
- package/dist/core/llm/index.js.map +1 -0
- package/dist/core/llm/llm-log-types.js +12 -0
- package/dist/core/llm/llm-log-types.js.map +1 -0
- package/dist/core/llm/logger.js +241 -0
- package/dist/core/llm/logger.js.map +1 -0
- package/dist/core/llm/logger.test.js +228 -0
- package/dist/core/llm/logger.test.js.map +1 -0
- package/dist/core/llm/logging-provider.js +49 -0
- package/dist/core/llm/logging-provider.js.map +1 -0
- package/dist/core/llm/middleware.js +114 -0
- package/dist/core/llm/middleware.js.map +1 -0
- package/dist/core/llm/mock.js +186 -0
- package/dist/core/llm/mock.js.map +1 -0
- package/dist/core/llm/mock.test.js +318 -0
- package/dist/core/llm/mock.test.js.map +1 -0
- package/dist/core/llm/openrouter-mapping.test.js +125 -0
- package/dist/core/llm/openrouter-mapping.test.js.map +1 -0
- package/dist/core/llm/openrouter.js +298 -0
- package/dist/core/llm/openrouter.js.map +1 -0
- package/dist/core/llm/openrouter.test.js +377 -0
- package/dist/core/llm/openrouter.test.js.map +1 -0
- package/dist/core/llm/provider-integration.test.js +350 -0
- package/dist/core/llm/provider-integration.test.js.map +1 -0
- package/dist/core/llm/provider.js +18 -0
- package/dist/core/llm/provider.js.map +1 -0
- package/dist/core/llm/routing-provider.js +52 -0
- package/dist/core/llm/routing-provider.js.map +1 -0
- package/dist/core/llm/routing-provider.test.js +94 -0
- package/dist/core/llm/routing-provider.test.js.map +1 -0
- package/dist/core/llm/schema.js +31 -0
- package/dist/core/llm/schema.js.map +1 -0
- package/dist/core/llm/snapshot-fetch.js +122 -0
- package/dist/core/llm/snapshot-fetch.js.map +1 -0
- package/dist/core/llm/snapshot-middleware.js +142 -0
- package/dist/core/llm/snapshot-middleware.js.map +1 -0
- package/dist/core/llm/snapshot-middleware.test.js +144 -0
- package/dist/core/llm/snapshot-middleware.test.js.map +1 -0
- package/dist/core/llm/state.js +48 -0
- package/dist/core/llm/state.js.map +1 -0
- package/dist/core/llm/tokens.js +40 -0
- package/dist/core/llm/tokens.js.map +1 -0
- package/dist/core/multi-agent.integration.test.js +298 -0
- package/dist/core/multi-agent.integration.test.js.map +1 -0
- package/dist/core/plugin-hooks.integration.test.js +344 -0
- package/dist/core/plugin-hooks.integration.test.js.map +1 -0
- package/dist/core/plugins/hook-types.js +5 -0
- package/dist/core/plugins/hook-types.js.map +1 -0
- package/dist/core/plugins/index.js +5 -0
- package/dist/core/plugins/index.js.map +1 -0
- package/dist/core/plugins/plugin-builder.js +321 -0
- package/dist/core/plugins/plugin-builder.js.map +1 -0
- package/dist/core/preset/config.js +54 -0
- package/dist/core/preset/config.js.map +1 -0
- package/dist/core/preset/index.js +6 -0
- package/dist/core/preset/index.js.map +1 -0
- package/dist/core/preset/preset-builder.js +63 -0
- package/dist/core/preset/preset-builder.js.map +1 -0
- package/dist/core/session-lifecycle.integration.test.js +159 -0
- package/dist/core/session-lifecycle.integration.test.js.map +1 -0
- package/dist/core/sessions/apply-event.js +41 -0
- package/dist/core/sessions/apply-event.js.map +1 -0
- package/dist/core/sessions/context.js +2 -0
- package/dist/core/sessions/context.js.map +1 -0
- package/dist/core/sessions/fork-utils.js +42 -0
- package/dist/core/sessions/fork-utils.js.map +1 -0
- package/dist/core/sessions/fork-utils.test.js +129 -0
- package/dist/core/sessions/fork-utils.test.js.map +1 -0
- package/dist/core/sessions/reducer.js +55 -0
- package/dist/core/sessions/reducer.js.map +1 -0
- package/dist/core/sessions/schema.js +66 -0
- package/dist/core/sessions/schema.js.map +1 -0
- package/dist/core/sessions/session-environment.js +2 -0
- package/dist/core/sessions/session-environment.js.map +1 -0
- package/dist/core/sessions/session-manager.js +650 -0
- package/dist/core/sessions/session-manager.js.map +1 -0
- package/dist/core/sessions/session-store.js +118 -0
- package/dist/core/sessions/session-store.js.map +1 -0
- package/dist/core/sessions/session.js +675 -0
- package/dist/core/sessions/session.js.map +1 -0
- package/dist/core/sessions/session.test.js +1095 -0
- package/dist/core/sessions/session.test.js.map +1 -0
- package/dist/core/sessions/state.js +377 -0
- package/dist/core/sessions/state.js.map +1 -0
- package/dist/core/system.js +66 -0
- package/dist/core/system.js.map +1 -0
- package/dist/core/tools/context.js +2 -0
- package/dist/core/tools/context.js.map +1 -0
- package/dist/core/tools/definition.js +4 -0
- package/dist/core/tools/definition.js.map +1 -0
- package/dist/core/tools/executor.js +82 -0
- package/dist/core/tools/executor.js.map +1 -0
- package/dist/core/tools/executor.test.js +143 -0
- package/dist/core/tools/executor.test.js.map +1 -0
- package/dist/core/tools/index.js +4 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/schema.js +20 -0
- package/dist/core/tools/schema.js.map +1 -0
- package/dist/core/tools/state.js +29 -0
- package/dist/core/tools/state.js.map +1 -0
- package/dist/index.js +70 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/json/index.js +5 -0
- package/dist/lib/json/index.js.map +1 -0
- package/dist/lib/logger/console.js +147 -0
- package/dist/lib/logger/console.js.map +1 -0
- package/dist/lib/logger/console.test.js +258 -0
- package/dist/lib/logger/console.test.js.map +1 -0
- package/dist/lib/logger/file.js +54 -0
- package/dist/lib/logger/file.js.map +1 -0
- package/dist/lib/logger/index.js +4 -0
- package/dist/lib/logger/index.js.map +1 -0
- package/dist/lib/logger/logger.js +28 -0
- package/dist/lib/logger/logger.js.map +1 -0
- package/dist/lib/logger/ring-buffer.js +61 -0
- package/dist/lib/logger/ring-buffer.js.map +1 -0
- package/dist/lib/logger/tee.js +43 -0
- package/dist/lib/logger/tee.js.map +1 -0
- package/dist/lib/mime.js +22 -0
- package/dist/lib/mime.js.map +1 -0
- package/dist/lib/never.js +4 -0
- package/dist/lib/never.js.map +1 -0
- package/dist/lib/utils/hash.js +35 -0
- package/dist/lib/utils/hash.js.map +1 -0
- package/dist/lib/utils/result.js +21 -0
- package/dist/lib/utils/result.js.map +1 -0
- package/dist/platform/fs.js +8 -0
- package/dist/platform/fs.js.map +1 -0
- package/dist/platform/index.js +9 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/process.js +8 -0
- package/dist/platform/process.js.map +1 -0
- package/dist/plugins/agent-status/plugin.js +77 -0
- package/dist/plugins/agent-status/plugin.js.map +1 -0
- package/dist/plugins/agents/agents.integration.test.js +683 -0
- package/dist/plugins/agents/agents.integration.test.js.map +1 -0
- package/dist/plugins/agents/index.js +2 -0
- package/dist/plugins/agents/index.js.map +1 -0
- package/dist/plugins/agents/plugin.js +199 -0
- package/dist/plugins/agents/plugin.js.map +1 -0
- package/dist/plugins/context-compact/context-compact.integration.test.js +174 -0
- package/dist/plugins/context-compact/context-compact.integration.test.js.map +1 -0
- package/dist/plugins/context-compact/context-compactor.js +238 -0
- package/dist/plugins/context-compact/context-compactor.js.map +1 -0
- package/dist/plugins/context-compact/context-compactor.test.js +763 -0
- package/dist/plugins/context-compact/context-compactor.test.js.map +1 -0
- package/dist/plugins/context-compact/history-offloader.js +42 -0
- package/dist/plugins/context-compact/history-offloader.js.map +1 -0
- package/dist/plugins/context-compact/history-offloader.test.js +77 -0
- package/dist/plugins/context-compact/history-offloader.test.js.map +1 -0
- package/dist/plugins/context-compact/index.js +4 -0
- package/dist/plugins/context-compact/index.js.map +1 -0
- package/dist/plugins/context-compact/plugin.js +37 -0
- package/dist/plugins/context-compact/plugin.js.map +1 -0
- package/dist/plugins/filesystem/filesystem.integration.test.js +411 -0
- package/dist/plugins/filesystem/filesystem.integration.test.js.map +1 -0
- package/dist/plugins/filesystem/helpers.js +170 -0
- package/dist/plugins/filesystem/helpers.js.map +1 -0
- package/dist/plugins/filesystem/index.js +3 -0
- package/dist/plugins/filesystem/index.js.map +1 -0
- package/dist/plugins/filesystem/listing.js +247 -0
- package/dist/plugins/filesystem/listing.js.map +1 -0
- package/dist/plugins/filesystem/plugin.js +364 -0
- package/dist/plugins/filesystem/plugin.js.map +1 -0
- package/dist/plugins/filesystem/schema.js +2 -0
- package/dist/plugins/filesystem/schema.js.map +1 -0
- package/dist/plugins/git-status/index.js +2 -0
- package/dist/plugins/git-status/index.js.map +1 -0
- package/dist/plugins/git-status/plugin.js +144 -0
- package/dist/plugins/git-status/plugin.js.map +1 -0
- package/dist/plugins/limits-guard/config.js +5 -0
- package/dist/plugins/limits-guard/config.js.map +1 -0
- package/dist/plugins/limits-guard/index.js +3 -0
- package/dist/plugins/limits-guard/index.js.map +1 -0
- package/dist/plugins/limits-guard/limit-guard.js +125 -0
- package/dist/plugins/limits-guard/limit-guard.js.map +1 -0
- package/dist/plugins/limits-guard/limit-guard.test.js +121 -0
- package/dist/plugins/limits-guard/limit-guard.test.js.map +1 -0
- package/dist/plugins/limits-guard/limits-guard.integration.test.js +378 -0
- package/dist/plugins/limits-guard/limits-guard.integration.test.js.map +1 -0
- package/dist/plugins/limits-guard/plugin.js +240 -0
- package/dist/plugins/limits-guard/plugin.js.map +1 -0
- package/dist/plugins/llm-debug/index.js +2 -0
- package/dist/plugins/llm-debug/index.js.map +1 -0
- package/dist/plugins/llm-debug/llm-debug.integration.test.js +157 -0
- package/dist/plugins/llm-debug/llm-debug.integration.test.js.map +1 -0
- package/dist/plugins/llm-debug/plugin.js +148 -0
- package/dist/plugins/llm-debug/plugin.js.map +1 -0
- package/dist/plugins/logs/index.js +2 -0
- package/dist/plugins/logs/index.js.map +1 -0
- package/dist/plugins/logs/plugin.js +38 -0
- package/dist/plugins/logs/plugin.js.map +1 -0
- package/dist/plugins/mailbox/helpers.js +66 -0
- package/dist/plugins/mailbox/helpers.js.map +1 -0
- package/dist/plugins/mailbox/index.js +9 -0
- package/dist/plugins/mailbox/index.js.map +1 -0
- package/dist/plugins/mailbox/mailbox.integration.test.js +605 -0
- package/dist/plugins/mailbox/mailbox.integration.test.js.map +1 -0
- package/dist/plugins/mailbox/plugin.js +204 -0
- package/dist/plugins/mailbox/plugin.js.map +1 -0
- package/dist/plugins/mailbox/prompts.js +93 -0
- package/dist/plugins/mailbox/prompts.js.map +1 -0
- package/dist/plugins/mailbox/query.js +38 -0
- package/dist/plugins/mailbox/query.js.map +1 -0
- package/dist/plugins/mailbox/schema.js +32 -0
- package/dist/plugins/mailbox/schema.js.map +1 -0
- package/dist/plugins/mailbox/state.js +41 -0
- package/dist/plugins/mailbox/state.js.map +1 -0
- package/dist/plugins/resources/index.js +4 -0
- package/dist/plugins/resources/index.js.map +1 -0
- package/dist/plugins/resources/manifest.js +20 -0
- package/dist/plugins/resources/manifest.js.map +1 -0
- package/dist/plugins/resources/plugin.js +171 -0
- package/dist/plugins/resources/plugin.js.map +1 -0
- package/dist/plugins/resources/post-inject.js +32 -0
- package/dist/plugins/resources/post-inject.js.map +1 -0
- package/dist/plugins/resources/state.js +16 -0
- package/dist/plugins/resources/state.js.map +1 -0
- package/dist/plugins/result-eviction/index.js +2 -0
- package/dist/plugins/result-eviction/index.js.map +1 -0
- package/dist/plugins/result-eviction/plugin.js +43 -0
- package/dist/plugins/result-eviction/plugin.js.map +1 -0
- package/dist/plugins/result-eviction/result-eviction.integration.test.js +217 -0
- package/dist/plugins/result-eviction/result-eviction.integration.test.js.map +1 -0
- package/dist/plugins/services/plugin.js +453 -0
- package/dist/plugins/services/plugin.js.map +1 -0
- package/dist/plugins/services/port-pool.js +70 -0
- package/dist/plugins/services/port-pool.js.map +1 -0
- package/dist/plugins/services/prompt.js +40 -0
- package/dist/plugins/services/prompt.js.map +1 -0
- package/dist/plugins/services/schema.js +9 -0
- package/dist/plugins/services/schema.js.map +1 -0
- package/dist/plugins/services/service.js +470 -0
- package/dist/plugins/services/service.js.map +1 -0
- package/dist/plugins/services/services.integration.test.js +485 -0
- package/dist/plugins/services/services.integration.test.js.map +1 -0
- package/dist/plugins/session-lifecycle/index.js +2 -0
- package/dist/plugins/session-lifecycle/index.js.map +1 -0
- package/dist/plugins/session-lifecycle/plugin.js +273 -0
- package/dist/plugins/session-lifecycle/plugin.js.map +1 -0
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js +498 -0
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.js.map +1 -0
- package/dist/plugins/session-state/plugin.js +159 -0
- package/dist/plugins/session-state/plugin.js.map +1 -0
- package/dist/plugins/session-stats/index.js +3 -0
- package/dist/plugins/session-stats/index.js.map +1 -0
- package/dist/plugins/session-stats/plugin.js +81 -0
- package/dist/plugins/session-stats/plugin.js.map +1 -0
- package/dist/plugins/shell/executor.js +339 -0
- package/dist/plugins/shell/executor.js.map +1 -0
- package/dist/plugins/shell/index.js +6 -0
- package/dist/plugins/shell/index.js.map +1 -0
- package/dist/plugins/shell/plugin.js +66 -0
- package/dist/plugins/shell/plugin.js.map +1 -0
- package/dist/plugins/shell/shell.integration.test.js +234 -0
- package/dist/plugins/shell/shell.integration.test.js.map +1 -0
- package/dist/plugins/shell/shell.test.js +236 -0
- package/dist/plugins/shell/shell.test.js.map +1 -0
- package/dist/plugins/skills/discovery.js +205 -0
- package/dist/plugins/skills/discovery.js.map +1 -0
- package/dist/plugins/skills/discovery.test.js +312 -0
- package/dist/plugins/skills/discovery.test.js.map +1 -0
- package/dist/plugins/skills/index.js +12 -0
- package/dist/plugins/skills/index.js.map +1 -0
- package/dist/plugins/skills/plugin.js +293 -0
- package/dist/plugins/skills/plugin.js.map +1 -0
- package/dist/plugins/skills/prompts.js +70 -0
- package/dist/plugins/skills/prompts.js.map +1 -0
- package/dist/plugins/skills/schema.js +18 -0
- package/dist/plugins/skills/schema.js.map +1 -0
- package/dist/plugins/skills/skills.integration.test.js +475 -0
- package/dist/plugins/skills/skills.integration.test.js.map +1 -0
- package/dist/plugins/snapshotting/index.js +3 -0
- package/dist/plugins/snapshotting/index.js.map +1 -0
- package/dist/plugins/snapshotting/jj-snapshotter.js +106 -0
- package/dist/plugins/snapshotting/jj-snapshotter.js.map +1 -0
- package/dist/plugins/snapshotting/plugin.js +28 -0
- package/dist/plugins/snapshotting/plugin.js.map +1 -0
- package/dist/plugins/snapshotting/snapshotter.js +2 -0
- package/dist/plugins/snapshotting/snapshotter.js.map +1 -0
- package/dist/plugins/todo/index.js +7 -0
- package/dist/plugins/todo/index.js.map +1 -0
- package/dist/plugins/todo/plugin.js +319 -0
- package/dist/plugins/todo/plugin.js.map +1 -0
- package/dist/plugins/todo/prompts.js +54 -0
- package/dist/plugins/todo/prompts.js.map +1 -0
- package/dist/plugins/todo/schema.js +18 -0
- package/dist/plugins/todo/schema.js.map +1 -0
- package/dist/plugins/todo/todo.integration.test.js +605 -0
- package/dist/plugins/todo/todo.integration.test.js.map +1 -0
- package/dist/plugins/uploads/index.js +8 -0
- package/dist/plugins/uploads/index.js.map +1 -0
- package/dist/plugins/uploads/plugin.js +346 -0
- package/dist/plugins/uploads/plugin.js.map +1 -0
- package/dist/plugins/uploads/preprocessor.js +44 -0
- package/dist/plugins/uploads/preprocessor.js.map +1 -0
- package/dist/plugins/uploads/preprocessors/image-classifier.js +127 -0
- package/dist/plugins/uploads/preprocessors/image-classifier.js.map +1 -0
- package/dist/plugins/uploads/preprocessors/index.js +7 -0
- package/dist/plugins/uploads/preprocessors/index.js.map +1 -0
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js +204 -0
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.js.map +1 -0
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.js +172 -0
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.js.map +1 -0
- package/dist/plugins/uploads/schema.js +20 -0
- package/dist/plugins/uploads/schema.js.map +1 -0
- package/dist/plugins/uploads/state.js +22 -0
- package/dist/plugins/uploads/state.js.map +1 -0
- package/dist/plugins/uploads/uploads.integration.test.js +496 -0
- package/dist/plugins/uploads/uploads.integration.test.js.map +1 -0
- package/dist/plugins/user-chat/index.js +5 -0
- package/dist/plugins/user-chat/index.js.map +1 -0
- package/dist/plugins/user-chat/plugin.js +544 -0
- package/dist/plugins/user-chat/plugin.js.map +1 -0
- package/dist/plugins/user-chat/prompts.js +29 -0
- package/dist/plugins/user-chat/prompts.js.map +1 -0
- package/dist/plugins/user-chat/schema.js +46 -0
- package/dist/plugins/user-chat/schema.js.map +1 -0
- package/dist/plugins/user-chat/user-chat.integration.test.js +668 -0
- package/dist/plugins/user-chat/user-chat.integration.test.js.map +1 -0
- package/dist/plugins/workers/context.js +143 -0
- package/dist/plugins/workers/context.js.map +1 -0
- package/dist/plugins/workers/definition.js +30 -0
- package/dist/plugins/workers/definition.js.map +1 -0
- package/dist/plugins/workers/index.js +7 -0
- package/dist/plugins/workers/index.js.map +1 -0
- package/dist/plugins/workers/plugin.js +578 -0
- package/dist/plugins/workers/plugin.js.map +1 -0
- package/dist/plugins/workers/worker.js +18 -0
- package/dist/plugins/workers/worker.js.map +1 -0
- package/dist/plugins/workers/workers.integration.test.js +629 -0
- package/dist/plugins/workers/workers.integration.test.js.map +1 -0
- package/dist/prompts/base.js +239 -0
- package/dist/prompts/base.js.map +1 -0
- package/dist/prompts/builder.js +131 -0
- package/dist/prompts/builder.js.map +1 -0
- package/dist/prompts/index.js +20 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/prompts/macros.js +26 -0
- package/dist/prompts/macros.js.map +1 -0
- package/dist/prompts/macros.test.js +80 -0
- package/dist/prompts/macros.test.js.map +1 -0
- package/dist/testing/bootstrap-for-testing.js +28 -0
- package/dist/testing/bootstrap-for-testing.js.map +1 -0
- package/dist/testing/index.js +7 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/node-platform.js +65 -0
- package/dist/testing/node-platform.js.map +1 -0
- package/dist/testing/notification-collector.js +82 -0
- package/dist/testing/notification-collector.js.map +1 -0
- package/dist/testing/preset-helpers.js +37 -0
- package/dist/testing/preset-helpers.js.map +1 -0
- package/dist/testing/test-harness.js +226 -0
- package/dist/testing/test-harness.js.map +1 -0
- package/dist/testing/test-harness.test.js +51 -0
- package/dist/testing/test-harness.test.js.map +1 -0
- package/dist/testing/wait-helpers.js +64 -0
- package/dist/testing/wait-helpers.js.map +1 -0
- package/dist/transport/adapter/client-adapter.js +64 -0
- package/dist/transport/adapter/client-adapter.js.map +1 -0
- package/dist/transport/adapter/index.js +24 -0
- package/dist/transport/adapter/index.js.map +1 -0
- package/dist/transport/adapter/server-adapter.js +73 -0
- package/dist/transport/adapter/server-adapter.js.map +1 -0
- package/dist/transport/adapter/types.js +8 -0
- package/dist/transport/adapter/types.js.map +1 -0
- package/dist/transport/http/app.js +86 -0
- package/dist/transport/http/app.js.map +1 -0
- package/dist/transport/http/index.js +6 -0
- package/dist/transport/http/index.js.map +1 -0
- package/dist/transport/http/middleware/bearer-auth.js +33 -0
- package/dist/transport/http/middleware/bearer-auth.js.map +1 -0
- package/dist/transport/http/middleware/error-handler.js +56 -0
- package/dist/transport/http/middleware/error-handler.js.map +1 -0
- package/dist/transport/http/routes/files.js +237 -0
- package/dist/transport/http/routes/files.js.map +1 -0
- package/dist/transport/http/routes/resources.js +77 -0
- package/dist/transport/http/routes/resources.js.map +1 -0
- package/dist/transport/http/routes/rpc.integration.test.js +189 -0
- package/dist/transport/http/routes/rpc.integration.test.js.map +1 -0
- package/dist/transport/http/routes/rpc.js +110 -0
- package/dist/transport/http/routes/rpc.js.map +1 -0
- package/dist/transport/http/routes/rpc.test.js +316 -0
- package/dist/transport/http/routes/rpc.test.js.map +1 -0
- package/dist/transport/http/routes/upload.js +205 -0
- package/dist/transport/http/routes/upload.js.map +1 -0
- package/dist/transport/rpc/index.js +7 -0
- package/dist/transport/rpc/index.js.map +1 -0
- package/dist/transport/rpc/methods.js +8 -0
- package/dist/transport/rpc/methods.js.map +1 -0
- package/dist/user-config.js +14 -0
- package/dist/user-config.js.map +1 -0
- package/package.json +47 -57
|
@@ -0,0 +1,650 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionManager - Session lifecycle and cache management.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Create and cache sessions
|
|
6
|
+
* - Load sessions from event store
|
|
7
|
+
* - Shutdown and cleanup
|
|
8
|
+
*/
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { COMMUNICATOR_ROLE, ORCHESTRATOR_ROLE } from '../../core/agents/agent-roles.js';
|
|
11
|
+
import { generateAgentId } from '../../core/agents/schema.js';
|
|
12
|
+
import { agentEvents } from '../../core/agents/state.js';
|
|
13
|
+
import { PresetErrors, SessionErrors, ValidationErrors } from '../../core/errors.js';
|
|
14
|
+
import { withSessionId } from '../../core/events/test-helpers.js';
|
|
15
|
+
import { generateSessionId } from '../../core/sessions/schema.js';
|
|
16
|
+
import { checkRecoveryNeeded, isSessionCreatedEvent, reconstructSessionState, sessionEvents } from '../../core/sessions/state.js';
|
|
17
|
+
import { FileLogger } from '../../lib/logger/file.js';
|
|
18
|
+
import { TeeLogger } from '../../lib/logger/tee.js';
|
|
19
|
+
import { Err, Ok } from '../../lib/utils/result.js';
|
|
20
|
+
import { getAgentUnconsumedMailbox, selectMailboxState } from '../../plugins/mailbox/query.js';
|
|
21
|
+
import { selectSessionStats } from '../../plugins/session-stats/index.js';
|
|
22
|
+
import { createApplyEvent } from './apply-event.js';
|
|
23
|
+
import { rewriteEventsForFork } from './fork-utils.js';
|
|
24
|
+
import { SessionStore } from './session-store.js';
|
|
25
|
+
import { Session } from './session.js';
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// Errors
|
|
28
|
+
// ============================================================================
|
|
29
|
+
/**
|
|
30
|
+
* Internal error for session loading failures.
|
|
31
|
+
* Wraps DomainError for proper error handling in async loading.
|
|
32
|
+
*/
|
|
33
|
+
class SessionLoadError extends Error {
|
|
34
|
+
domainError;
|
|
35
|
+
constructor(domainError) {
|
|
36
|
+
super(`Session load error: ${domainError.type}`);
|
|
37
|
+
this.domainError = domainError;
|
|
38
|
+
this.name = 'SessionLoadError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* SessionManager manages session lifecycle and caching.
|
|
43
|
+
*/
|
|
44
|
+
export class SessionManager {
|
|
45
|
+
sessions = new Map();
|
|
46
|
+
/** Unsubscribe functions for session event listeners, keyed by sessionId */
|
|
47
|
+
sessionListenerCleanup = new Map();
|
|
48
|
+
/** Manager-level methods collected from plugin definitions across all presets */
|
|
49
|
+
managerMethods;
|
|
50
|
+
eventStore;
|
|
51
|
+
llmProvider;
|
|
52
|
+
llmProviders;
|
|
53
|
+
toolExecutor;
|
|
54
|
+
presets;
|
|
55
|
+
logger;
|
|
56
|
+
basePath;
|
|
57
|
+
dataFileStore;
|
|
58
|
+
onUserOutput;
|
|
59
|
+
preprocessorRegistry;
|
|
60
|
+
llmLogger;
|
|
61
|
+
portPool;
|
|
62
|
+
platform;
|
|
63
|
+
systemPlugins;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
this.eventStore = options.eventStore;
|
|
66
|
+
this.llmProvider = options.llmProvider;
|
|
67
|
+
this.llmProviders = options.llmProviders ?? new Map();
|
|
68
|
+
this.toolExecutor = options.toolExecutor;
|
|
69
|
+
this.presets = options.presets;
|
|
70
|
+
this.logger = options.logger;
|
|
71
|
+
this.basePath = options.basePath;
|
|
72
|
+
this.dataFileStore = options.dataFileStore;
|
|
73
|
+
this.onUserOutput = options.onUserOutput;
|
|
74
|
+
this.preprocessorRegistry = options.preprocessorRegistry;
|
|
75
|
+
this.llmLogger = options.llmLogger;
|
|
76
|
+
this.portPool = options.portPool;
|
|
77
|
+
this.platform = options.platform;
|
|
78
|
+
this.systemPlugins = options.systemPlugins ?? [];
|
|
79
|
+
this.managerMethods = this.collectManagerMethods();
|
|
80
|
+
}
|
|
81
|
+
/** Expose platform adapters (used by Session for building contexts). */
|
|
82
|
+
getPlatform() {
|
|
83
|
+
return this.platform;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Create a new session with the given preset.
|
|
87
|
+
*/
|
|
88
|
+
async createSession(presetId, options) {
|
|
89
|
+
const preset = this.presets.get(presetId);
|
|
90
|
+
if (!preset) {
|
|
91
|
+
return Err(PresetErrors.notFound(presetId));
|
|
92
|
+
}
|
|
93
|
+
const sessionId = options?.sessionId ? options.sessionId : generateSessionId();
|
|
94
|
+
// First orchestrator gets seq 1
|
|
95
|
+
const orchestratorId = generateAgentId(ORCHESTRATOR_ROLE, 1);
|
|
96
|
+
// Resolve workspaceDir: API input overrides preset default
|
|
97
|
+
// Interpolate {sessionId} placeholder if present
|
|
98
|
+
const rawWorkspaceDir = options?.workspaceDir ?? preset.workspaceDir;
|
|
99
|
+
const workspaceDir = rawWorkspaceDir?.replace('{sessionId}', String(sessionId));
|
|
100
|
+
this.logger.info('Creating session', {
|
|
101
|
+
sessionId,
|
|
102
|
+
presetId,
|
|
103
|
+
optionsWorkspaceDir: options?.workspaceDir ?? null,
|
|
104
|
+
presetWorkspaceDir: preset.workspaceDir ?? null,
|
|
105
|
+
resolvedWorkspaceDir: workspaceDir ?? null,
|
|
106
|
+
});
|
|
107
|
+
const events = [
|
|
108
|
+
withSessionId(sessionId, sessionEvents.create('session_created', {
|
|
109
|
+
presetId,
|
|
110
|
+
...(workspaceDir ? { workspaceDir } : {}),
|
|
111
|
+
})),
|
|
112
|
+
withSessionId(sessionId, agentEvents.create('agent_spawned', {
|
|
113
|
+
agentId: orchestratorId,
|
|
114
|
+
definitionName: ORCHESTRATOR_ROLE,
|
|
115
|
+
parentId: null,
|
|
116
|
+
})),
|
|
117
|
+
];
|
|
118
|
+
// Spawn communicator if configured
|
|
119
|
+
const hasCommunicator = !!preset.communicator;
|
|
120
|
+
if (hasCommunicator) {
|
|
121
|
+
// First communicator gets seq 1
|
|
122
|
+
const communicatorId = generateAgentId(COMMUNICATOR_ROLE, 1);
|
|
123
|
+
events.push(withSessionId(sessionId, agentEvents.create('agent_spawned', {
|
|
124
|
+
agentId: communicatorId,
|
|
125
|
+
definitionName: COMMUNICATOR_ROLE,
|
|
126
|
+
parentId: null,
|
|
127
|
+
})));
|
|
128
|
+
// Link communicator to orchestrator
|
|
129
|
+
events.push(withSessionId(sessionId, agentEvents.create('communicator_linked', {
|
|
130
|
+
communicatorId,
|
|
131
|
+
orchestratorId,
|
|
132
|
+
})));
|
|
133
|
+
}
|
|
134
|
+
// Write events to event store
|
|
135
|
+
await this.eventStore.appendBatch(sessionId, events);
|
|
136
|
+
// Build plugins and composed reducer so plugin state slices are applied
|
|
137
|
+
const plugins = this.buildPlugins(preset);
|
|
138
|
+
const composedReducer = createApplyEvent(plugins);
|
|
139
|
+
// Reconstruct state with composed reducer (includes plugin state slices)
|
|
140
|
+
const state = reconstructSessionState(events, composedReducer);
|
|
141
|
+
if (!state) {
|
|
142
|
+
return Err(ValidationErrors.invalid('Failed to reconstruct session'));
|
|
143
|
+
}
|
|
144
|
+
// Create store and session (initPluginContexts + onSessionReady hooks run inside)
|
|
145
|
+
const store = new SessionStore(sessionId, this.eventStore, state, composedReducer);
|
|
146
|
+
const session = await this.createSessionInstance(store, preset, plugins);
|
|
147
|
+
// Cache session (wrap in resolved promise for consistency)
|
|
148
|
+
this.sessions.set(sessionId, Promise.resolve(session));
|
|
149
|
+
this.logger.info('Session created', {
|
|
150
|
+
sessionId,
|
|
151
|
+
presetId,
|
|
152
|
+
hasCommunicator,
|
|
153
|
+
});
|
|
154
|
+
return Ok(session);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Fork a session from a specific event index into a new independent session.
|
|
158
|
+
* The forked session gets a copy of all events up to the fork point.
|
|
159
|
+
*/
|
|
160
|
+
async forkSession(sourceSessionId, eventIndex) {
|
|
161
|
+
// Load source events
|
|
162
|
+
const sourceEvents = await this.eventStore.load(sourceSessionId);
|
|
163
|
+
if (sourceEvents.length === 0) {
|
|
164
|
+
return Err(SessionErrors.notFound(String(sourceSessionId)));
|
|
165
|
+
}
|
|
166
|
+
// Validate eventIndex range
|
|
167
|
+
if (eventIndex < 0 || eventIndex >= sourceEvents.length) {
|
|
168
|
+
return Err(ValidationErrors.invalid(`eventIndex ${eventIndex} out of range [0, ${sourceEvents.length - 1}]`));
|
|
169
|
+
}
|
|
170
|
+
// Get source preset
|
|
171
|
+
const firstEvent = sourceEvents[0];
|
|
172
|
+
if (!isSessionCreatedEvent(firstEvent)) {
|
|
173
|
+
return Err(ValidationErrors.invalid('First event must be session_created'));
|
|
174
|
+
}
|
|
175
|
+
const preset = this.presets.get(firstEvent.presetId);
|
|
176
|
+
if (!preset) {
|
|
177
|
+
return Err(PresetErrors.notFound(firstEvent.presetId));
|
|
178
|
+
}
|
|
179
|
+
// Generate new session ID
|
|
180
|
+
const newSessionId = generateSessionId();
|
|
181
|
+
// Resolve workspace dir for the new session
|
|
182
|
+
const rawWorkspaceDir = preset.workspaceDir;
|
|
183
|
+
const sourceWorkspaceDir = firstEvent.workspaceDir;
|
|
184
|
+
if (sourceWorkspaceDir && rawWorkspaceDir && !rawWorkspaceDir.includes('{sessionId}')) {
|
|
185
|
+
return Err(ValidationErrors.invalid('Cannot fork: preset workspaceDir has no {sessionId} placeholder, forked session would share the same workspace directory'));
|
|
186
|
+
}
|
|
187
|
+
const newWorkspaceDir = rawWorkspaceDir?.replace('{sessionId}', String(newSessionId));
|
|
188
|
+
// Rewrite events for the fork
|
|
189
|
+
let forkedEvents = rewriteEventsForFork(sourceEvents, eventIndex, newSessionId, sourceSessionId);
|
|
190
|
+
// Update workspaceDir in session_created if it changed
|
|
191
|
+
if (newWorkspaceDir !== sourceWorkspaceDir) {
|
|
192
|
+
forkedEvents = forkedEvents.map((event) => {
|
|
193
|
+
if (event.type === 'session_created') {
|
|
194
|
+
return { ...event, workspaceDir: newWorkspaceDir };
|
|
195
|
+
}
|
|
196
|
+
return event;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
// Write forked events to event store
|
|
200
|
+
await this.eventStore.appendBatch(newSessionId, forkedEvents);
|
|
201
|
+
// Build plugins and composed reducer so plugin state slices are applied
|
|
202
|
+
const plugins = this.buildPlugins(preset);
|
|
203
|
+
const composedReducer = createApplyEvent(plugins);
|
|
204
|
+
// Reconstruct state with composed reducer (includes plugin state slices)
|
|
205
|
+
const state = reconstructSessionState(forkedEvents, composedReducer);
|
|
206
|
+
if (!state) {
|
|
207
|
+
return Err(ValidationErrors.invalid('Failed to reconstruct forked session'));
|
|
208
|
+
}
|
|
209
|
+
// Create store
|
|
210
|
+
const store = new SessionStore(newSessionId, this.eventStore, state, composedReducer);
|
|
211
|
+
// Normalize stuck agents via session_restarted event
|
|
212
|
+
const recoveryData = checkRecoveryNeeded(state);
|
|
213
|
+
if (recoveryData) {
|
|
214
|
+
await store.emit(withSessionId(newSessionId, sessionEvents.create('session_restarted', {
|
|
215
|
+
resetAgentIds: recoveryData.resetAgentIds,
|
|
216
|
+
clearedToolAgentIds: recoveryData.clearedToolAgentIds,
|
|
217
|
+
})));
|
|
218
|
+
}
|
|
219
|
+
// Create session instance (auto-start services run via onSessionReady)
|
|
220
|
+
const session = await this.createSessionInstance(store, preset, plugins);
|
|
221
|
+
// Check for pending agents
|
|
222
|
+
session.checkPendingAgents();
|
|
223
|
+
// Cache session
|
|
224
|
+
this.sessions.set(newSessionId, Promise.resolve(session));
|
|
225
|
+
this.logger.info('Session forked', {
|
|
226
|
+
sourceSessionId,
|
|
227
|
+
newSessionId,
|
|
228
|
+
eventIndex,
|
|
229
|
+
});
|
|
230
|
+
return Ok(session);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Get a session by ID - from cache or load from event store.
|
|
234
|
+
*/
|
|
235
|
+
async getSession(sessionId) {
|
|
236
|
+
// Check cache first
|
|
237
|
+
const cached = this.sessions.get(sessionId);
|
|
238
|
+
if (cached) {
|
|
239
|
+
try {
|
|
240
|
+
return Ok(await cached);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
// Previous load failed, remove from cache and try again
|
|
244
|
+
this.sessions.delete(sessionId);
|
|
245
|
+
if (error instanceof SessionLoadError) {
|
|
246
|
+
return Err(error.domainError);
|
|
247
|
+
}
|
|
248
|
+
throw error;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
// Store promise immediately to prevent concurrent loads
|
|
252
|
+
const loadPromise = this.loadSession(sessionId);
|
|
253
|
+
this.sessions.set(sessionId, loadPromise);
|
|
254
|
+
try {
|
|
255
|
+
return Ok(await loadPromise);
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
this.sessions.delete(sessionId);
|
|
259
|
+
if (error instanceof SessionLoadError) {
|
|
260
|
+
return Err(error.domainError);
|
|
261
|
+
}
|
|
262
|
+
throw error;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Internal session loading - throws SessionLoadError on domain errors.
|
|
267
|
+
*/
|
|
268
|
+
async loadSession(sessionId) {
|
|
269
|
+
// We need to peek at events first to determine the preset, so we can build plugins
|
|
270
|
+
// and compose the reducer before loading the store
|
|
271
|
+
const events = await this.eventStore.load(sessionId);
|
|
272
|
+
if (events.length === 0) {
|
|
273
|
+
throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
|
|
274
|
+
}
|
|
275
|
+
const firstEvent = events[0];
|
|
276
|
+
if (!isSessionCreatedEvent(firstEvent)) {
|
|
277
|
+
throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
|
|
278
|
+
}
|
|
279
|
+
const preset = this.presets.get(firstEvent.presetId);
|
|
280
|
+
if (!preset) {
|
|
281
|
+
throw new SessionLoadError(PresetErrors.notFound(firstEvent.presetId));
|
|
282
|
+
}
|
|
283
|
+
// Build plugins and composed reducer so plugin state slices are applied
|
|
284
|
+
const plugins = this.buildPlugins(preset);
|
|
285
|
+
const composedReducer = createApplyEvent(plugins);
|
|
286
|
+
// Load store with composed reducer
|
|
287
|
+
const store = await SessionStore.load(sessionId, this.eventStore, composedReducer);
|
|
288
|
+
if (!store) {
|
|
289
|
+
throw new SessionLoadError(SessionErrors.notFound(String(sessionId)));
|
|
290
|
+
}
|
|
291
|
+
const state = store.getState();
|
|
292
|
+
// Don't cache closed sessions
|
|
293
|
+
if (state.status === 'closed') {
|
|
294
|
+
// Remove from cache since we don't cache closed sessions
|
|
295
|
+
this.sessions.delete(sessionId);
|
|
296
|
+
// Skip onSessionReady hooks — closed sessions are immutable, firing hooks
|
|
297
|
+
// would emit events to a sealed event log on every read / restart.
|
|
298
|
+
return await this.createSessionInstance(store, preset, plugins, { skipReadyHooks: true });
|
|
299
|
+
}
|
|
300
|
+
// Check if recovery is needed after restart
|
|
301
|
+
const recoveryData = checkRecoveryNeeded(state);
|
|
302
|
+
if (recoveryData) {
|
|
303
|
+
await store.emit(withSessionId(sessionId, sessionEvents.create('session_restarted', {
|
|
304
|
+
resetAgentIds: recoveryData.resetAgentIds,
|
|
305
|
+
clearedToolAgentIds: recoveryData.clearedToolAgentIds,
|
|
306
|
+
})));
|
|
307
|
+
this.logger.info('Session recovered after restart', {
|
|
308
|
+
sessionId,
|
|
309
|
+
resetAgents: recoveryData.resetAgentIds.length,
|
|
310
|
+
clearedToolAgents: recoveryData.clearedToolAgentIds.length,
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
// Create session (auto-start services run via onSessionReady)
|
|
314
|
+
const session = await this.createSessionInstance(store, preset, plugins);
|
|
315
|
+
// Check for pending agents
|
|
316
|
+
session.checkPendingAgents();
|
|
317
|
+
return session;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Call a plugin method on a session.
|
|
321
|
+
* @param sessionId - Session ID
|
|
322
|
+
* @param method - Full method name (e.g., "services.start")
|
|
323
|
+
* @param input - Method input (must include sessionId field)
|
|
324
|
+
* @param agentId - Agent ID (optional — some methods don't operate on a specific agent)
|
|
325
|
+
*/
|
|
326
|
+
async callPluginMethod(sessionId, method, input, agentId, caller) {
|
|
327
|
+
const sessionResult = await this.getSession(sessionId);
|
|
328
|
+
if (!sessionResult.ok)
|
|
329
|
+
return sessionResult;
|
|
330
|
+
return sessionResult.value.callPluginMethod(method, input, agentId, caller);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Call a manager-level plugin method.
|
|
334
|
+
* These methods operate outside session context (e.g., session creation, listing).
|
|
335
|
+
*/
|
|
336
|
+
async callManagerMethod(method, input) {
|
|
337
|
+
const methodDef = this.managerMethods.get(method);
|
|
338
|
+
if (!methodDef) {
|
|
339
|
+
return Err(ValidationErrors.invalid(`Unknown manager method: ${method}`));
|
|
340
|
+
}
|
|
341
|
+
const parsed = methodDef.input.safeParse(input);
|
|
342
|
+
if (!parsed.success) {
|
|
343
|
+
return Err(ValidationErrors.invalid(`Invalid input for ${method}: ${parsed.error.message}`));
|
|
344
|
+
}
|
|
345
|
+
const ctx = {
|
|
346
|
+
sessionManager: this,
|
|
347
|
+
eventStore: this.eventStore,
|
|
348
|
+
presets: this.presets,
|
|
349
|
+
logger: this.logger.child({ method }),
|
|
350
|
+
llmLogger: this.llmLogger,
|
|
351
|
+
platform: this.platform,
|
|
352
|
+
};
|
|
353
|
+
return await methodDef.handler(ctx, parsed.data);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Get all registered manager methods.
|
|
357
|
+
*/
|
|
358
|
+
getManagerMethods() {
|
|
359
|
+
const result = new Map();
|
|
360
|
+
for (const [name, def] of this.managerMethods) {
|
|
361
|
+
result.set(name, { input: def.input, output: def.output });
|
|
362
|
+
}
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Load all active sessions from event store (for restart recovery).
|
|
367
|
+
*
|
|
368
|
+
* Closed sessions are skipped — they have no runtime to restore. Loading them
|
|
369
|
+
* would trigger callSessionReadyHooks and emit events to an immutable session log,
|
|
370
|
+
* causing write amplification on every agent startup.
|
|
371
|
+
*/
|
|
372
|
+
async loadAllSessions() {
|
|
373
|
+
const sessionIds = await this.eventStore.listSessions();
|
|
374
|
+
let loaded = 0;
|
|
375
|
+
let skipped = 0;
|
|
376
|
+
for (const sessionId of sessionIds) {
|
|
377
|
+
try {
|
|
378
|
+
const metadata = await this.eventStore.getMetadata(sessionId);
|
|
379
|
+
if (metadata?.status === 'closed') {
|
|
380
|
+
skipped++;
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
await this.getSession(sessionId);
|
|
384
|
+
loaded++;
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
this.logger.error('Failed to load session', error instanceof Error ? error : new Error(String(error)), { sessionId });
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
this.logger.info('Loaded sessions', { loaded, skipped, total: sessionIds.length });
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Get runtime stats including last activity timestamp and per-session metrics.
|
|
394
|
+
*
|
|
395
|
+
* Only open (non-closed) sessions contribute to activity metrics. Closed sessions
|
|
396
|
+
* are immutable artifacts — their event log timestamps must not be interpreted as
|
|
397
|
+
* "the sandbox is doing work", otherwise the worker alarm sees stale activity and
|
|
398
|
+
* keeps the sandbox alive forever.
|
|
399
|
+
*/
|
|
400
|
+
async getStats() {
|
|
401
|
+
let pendingAgents = 0;
|
|
402
|
+
let processingAgents = 0;
|
|
403
|
+
let lastActivityAt = null;
|
|
404
|
+
// Wait for all sessions, ignoring failures
|
|
405
|
+
const sessions = await Promise.all(Array.from(this.sessions.values()).map((p) => p.catch(() => null)));
|
|
406
|
+
// Filter out closed sessions — they do not contribute to activity
|
|
407
|
+
const openSessions = sessions.filter((s) => s !== null && s.state.status !== 'closed');
|
|
408
|
+
// Fetch metadata only for open sessions
|
|
409
|
+
const metadataResults = await Promise.all(openSessions.map((s) => this.eventStore.getMetadata(s.state.id).catch(() => null)));
|
|
410
|
+
for (const metadata of metadataResults) {
|
|
411
|
+
if (metadata?.lastActivityAt) {
|
|
412
|
+
if (lastActivityAt === null
|
|
413
|
+
|| metadata.lastActivityAt > lastActivityAt) {
|
|
414
|
+
lastActivityAt = metadata.lastActivityAt;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const sessionStats = [];
|
|
419
|
+
for (const session of openSessions) {
|
|
420
|
+
for (const [agentId, agentState] of session.state.agents) {
|
|
421
|
+
if (agentState.status === 'pending') {
|
|
422
|
+
const hasUnconsumed = getAgentUnconsumedMailbox(selectMailboxState(session.state), agentId).length > 0;
|
|
423
|
+
if (hasUnconsumed) {
|
|
424
|
+
pendingAgents++;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (agentState.status === 'inferring'
|
|
428
|
+
|| agentState.status === 'tool_exec') {
|
|
429
|
+
processingAgents++;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
sessionStats.push({
|
|
433
|
+
id: session.state.id,
|
|
434
|
+
presetId: session.state.presetId,
|
|
435
|
+
status: session.state.status,
|
|
436
|
+
metrics: selectSessionStats(session.state),
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
return {
|
|
440
|
+
sessionCount: openSessions.length,
|
|
441
|
+
pendingAgents,
|
|
442
|
+
processingAgents,
|
|
443
|
+
lastActivityAt,
|
|
444
|
+
sessions: sessionStats,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* Shutdown - clean up all sessions.
|
|
449
|
+
*/
|
|
450
|
+
async shutdown() {
|
|
451
|
+
// Wait for all sessions, ignoring failures
|
|
452
|
+
const sessions = await Promise.all(Array.from(this.sessions.values()).map((p) => p.catch(() => null)));
|
|
453
|
+
for (const session of sessions) {
|
|
454
|
+
if (session) {
|
|
455
|
+
session.shutdown();
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
this.sessions.clear();
|
|
459
|
+
for (const cleanup of this.sessionListenerCleanup.values()) {
|
|
460
|
+
cleanup();
|
|
461
|
+
}
|
|
462
|
+
this.sessionListenerCleanup.clear();
|
|
463
|
+
this.logger.info('SessionManager shutdown complete');
|
|
464
|
+
}
|
|
465
|
+
// ============================================================================
|
|
466
|
+
// Private methods
|
|
467
|
+
// ============================================================================
|
|
468
|
+
/**
|
|
469
|
+
* Build ConfiguredPlugin[] for a session.
|
|
470
|
+
*
|
|
471
|
+
* Iterates all system-registered plugins. For each:
|
|
472
|
+
* 1. Check if preset has explicit SessionPluginConfig → use that config
|
|
473
|
+
* 2. If not, try auto-deriving infrastructure config (agents, uploads, services)
|
|
474
|
+
* 3. If no config at all → call .create() with no args (void config)
|
|
475
|
+
* 4. Check isSessionEnabled — skip plugin if not enabled
|
|
476
|
+
*/
|
|
477
|
+
buildPlugins(preset) {
|
|
478
|
+
// Build a lookup from preset Sessionplugins
|
|
479
|
+
const presetConfigs = new Map();
|
|
480
|
+
for (const pluginConfig of preset.plugins ?? []) {
|
|
481
|
+
presetConfigs.set(pluginConfig.pluginName, pluginConfig.config);
|
|
482
|
+
}
|
|
483
|
+
// Build infra-derived configs
|
|
484
|
+
const infraConfigs = this.buildInfraConfigs(preset);
|
|
485
|
+
const plugins = [];
|
|
486
|
+
for (const pluginDef of this.systemPlugins) {
|
|
487
|
+
// Determine config: preset explicit > infra auto-derived > no config (void)
|
|
488
|
+
let config;
|
|
489
|
+
let hasConfig = false;
|
|
490
|
+
if (presetConfigs.has(pluginDef.name)) {
|
|
491
|
+
config = presetConfigs.get(pluginDef.name);
|
|
492
|
+
hasConfig = true;
|
|
493
|
+
}
|
|
494
|
+
else if (infraConfigs.has(pluginDef.name)) {
|
|
495
|
+
config = infraConfigs.get(pluginDef.name);
|
|
496
|
+
hasConfig = true;
|
|
497
|
+
}
|
|
498
|
+
const configured = hasConfig
|
|
499
|
+
? pluginDef.create(config)
|
|
500
|
+
: pluginDef.create();
|
|
501
|
+
// Check isSessionEnabled — skip plugin if not enabled
|
|
502
|
+
if (configured.isSessionEnabled && !configured.isSessionEnabled({ pluginConfig: config })) {
|
|
503
|
+
continue;
|
|
504
|
+
}
|
|
505
|
+
plugins.push(configured);
|
|
506
|
+
}
|
|
507
|
+
// Process preset-only plugins (not registered as system plugins)
|
|
508
|
+
const registeredNames = new Set(plugins.map(p => p.name));
|
|
509
|
+
for (const pluginConfig of preset.plugins ?? []) {
|
|
510
|
+
if (registeredNames.has(pluginConfig.pluginName))
|
|
511
|
+
continue;
|
|
512
|
+
const configured = pluginConfig.definition.create(pluginConfig.config);
|
|
513
|
+
if (configured.isSessionEnabled && !configured.isSessionEnabled({ pluginConfig: pluginConfig.config })) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
plugins.push(configured);
|
|
517
|
+
registeredNames.add(configured.name);
|
|
518
|
+
}
|
|
519
|
+
// Validate that all declared dependencies are registered
|
|
520
|
+
for (const plugin of plugins) {
|
|
521
|
+
for (const depName of plugin.dependencyNames) {
|
|
522
|
+
if (!registeredNames.has(depName)) {
|
|
523
|
+
throw new Error(`Plugin "${plugin.name}" declares dependency on "${depName}", but "${depName}" is not registered. Add it to systemPlugins.`);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return plugins;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Build infrastructure-derived plugin configs from preset data.
|
|
531
|
+
* These are auto-derived for well-known plugins that need preset-level data.
|
|
532
|
+
*/
|
|
533
|
+
buildInfraConfigs(preset) {
|
|
534
|
+
const configs = new Map();
|
|
535
|
+
// agents plugin — derive agentDefinitions from preset.agents
|
|
536
|
+
const agentDefinitions = new Map();
|
|
537
|
+
for (const agentDef of preset.agents) {
|
|
538
|
+
agentDefinitions.set(agentDef.name, {
|
|
539
|
+
name: agentDef.name,
|
|
540
|
+
inputSchema: agentDef.input,
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
configs.set('agents', { agentDefinitions });
|
|
544
|
+
// user-chat plugin — empty config
|
|
545
|
+
configs.set('user-chat', {});
|
|
546
|
+
// uploads plugin — needs dataFileStore and preprocessorRegistry from SessionManager
|
|
547
|
+
configs.set('uploads', {
|
|
548
|
+
dataFileStore: this.dataFileStore,
|
|
549
|
+
preprocessorRegistry: this.preprocessorRegistry,
|
|
550
|
+
});
|
|
551
|
+
// services plugin — collect services from all agent definitions
|
|
552
|
+
const allAgentConfigs = [preset.orchestrator, ...(preset.communicator ? [preset.communicator] : []), ...preset.agents];
|
|
553
|
+
const servicesByType = new Map();
|
|
554
|
+
for (const agentConfig of allAgentConfigs) {
|
|
555
|
+
for (const svc of agentConfig.services ?? []) {
|
|
556
|
+
servicesByType.set(svc.type, svc);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
if (servicesByType.size > 0 && this.portPool) {
|
|
560
|
+
configs.set('services', { services: [...servicesByType.values()], portPool: this.portPool });
|
|
561
|
+
}
|
|
562
|
+
return configs;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Create a Session instance with all dependencies.
|
|
566
|
+
* Plugins must be pre-built via buildPlugins() so the composed reducer
|
|
567
|
+
* can be used for SessionStore before this method is called.
|
|
568
|
+
*
|
|
569
|
+
* @param opts.skipReadyHooks - Skip onSessionReady hooks. Used for closed sessions,
|
|
570
|
+
* which must remain immutable: running hooks would emit session_handler_* events
|
|
571
|
+
* to a sealed event log on every introspection / restart cycle.
|
|
572
|
+
*/
|
|
573
|
+
async createSessionInstance(store, preset, plugins, opts = {}) {
|
|
574
|
+
// Only register cache eviction listener for active sessions (not closed)
|
|
575
|
+
if (store.getState().status !== 'closed') {
|
|
576
|
+
this.registerSessionEventListener(store.sessionId, store);
|
|
577
|
+
}
|
|
578
|
+
const sessionDir = this.getSessionDir(store.sessionId);
|
|
579
|
+
const sessionLogger = new TeeLogger([
|
|
580
|
+
this.logger.child({ sessionId: store.sessionId }),
|
|
581
|
+
new FileLogger(join(sessionDir, 'session.log'), this.platform.fs, { sessionId: String(store.sessionId) }),
|
|
582
|
+
]);
|
|
583
|
+
// Create session
|
|
584
|
+
const session = new Session({
|
|
585
|
+
store,
|
|
586
|
+
preset,
|
|
587
|
+
llmProvider: this.llmProvider,
|
|
588
|
+
llmProviders: this.llmProviders,
|
|
589
|
+
toolExecutor: this.toolExecutor,
|
|
590
|
+
logger: sessionLogger,
|
|
591
|
+
onUserOutput: this.onUserOutput,
|
|
592
|
+
sessionDir,
|
|
593
|
+
plugins,
|
|
594
|
+
eventStore: this.eventStore,
|
|
595
|
+
llmLogger: this.llmLogger,
|
|
596
|
+
platform: this.platform,
|
|
597
|
+
});
|
|
598
|
+
// Ensure session and workspace directories exist before plugins run
|
|
599
|
+
await this.platform.fs.mkdir(sessionDir, { recursive: true });
|
|
600
|
+
const workspaceDir = store.getState().workspaceDir;
|
|
601
|
+
if (workspaceDir) {
|
|
602
|
+
await this.platform.fs.mkdir(workspaceDir, { recursive: true });
|
|
603
|
+
}
|
|
604
|
+
// Initialize plugin contexts (calls createContext for each plugin).
|
|
605
|
+
// Safe for closed sessions — createContext is pure local setup, no event emit.
|
|
606
|
+
await session.initPluginContexts();
|
|
607
|
+
// Call onSessionReady hooks with full context.
|
|
608
|
+
// Skipped for closed sessions to preserve event log immutability.
|
|
609
|
+
if (!opts.skipReadyHooks) {
|
|
610
|
+
await session.callSessionReadyHooks();
|
|
611
|
+
}
|
|
612
|
+
return session;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Collect manager methods from all system plugin definitions.
|
|
616
|
+
*/
|
|
617
|
+
collectManagerMethods() {
|
|
618
|
+
const methods = new Map();
|
|
619
|
+
for (const pluginDef of this.systemPlugins) {
|
|
620
|
+
for (const [methodName, methodDef] of Object.entries(pluginDef.managerMethods)) {
|
|
621
|
+
methods.set(`${pluginDef.name}.${methodName}`, methodDef);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return methods;
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Register event listener on a session's store for automatic cache eviction.
|
|
628
|
+
* When session_closed or session_reopened events fire, the session is evicted
|
|
629
|
+
* so next getSession() triggers a full load with recovery.
|
|
630
|
+
*
|
|
631
|
+
* Cleans up any previous listener for this sessionId (from a prior load)
|
|
632
|
+
* to prevent duplicate listeners firing on old stores.
|
|
633
|
+
*/
|
|
634
|
+
registerSessionEventListener(sessionId, store) {
|
|
635
|
+
const prevCleanup = this.sessionListenerCleanup.get(sessionId);
|
|
636
|
+
if (prevCleanup)
|
|
637
|
+
prevCleanup();
|
|
638
|
+
const unsubscribe = store.onEvent((event) => {
|
|
639
|
+
if (event.type === 'session_closed' || event.type === 'session_reopened') {
|
|
640
|
+
this.sessions.delete(sessionId);
|
|
641
|
+
this.sessionListenerCleanup.delete(sessionId);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
this.sessionListenerCleanup.set(sessionId, unsubscribe);
|
|
645
|
+
}
|
|
646
|
+
getSessionDir(sessionId) {
|
|
647
|
+
return join(this.basePath, 'sessions', String(sessionId));
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
//# sourceMappingURL=session-manager.js.map
|