@roj-ai/sdk 0.0.2
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.d.ts +453 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/builtin-events.d.ts +16 -0
- package/dist/builtin-events.d.ts.map +1 -0
- package/dist/bun-platform/fs.d.ts +9 -0
- package/dist/bun-platform/fs.d.ts.map +1 -0
- package/dist/bun-platform/index.d.ts +12 -0
- package/dist/bun-platform/index.d.ts.map +1 -0
- package/dist/bun-platform/process.d.ts +6 -0
- package/dist/bun-platform/process.d.ts.map +1 -0
- package/dist/config.d.ts +38 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/core/agent-loop.integration.test.d.ts +2 -0
- package/dist/core/agent-loop.integration.test.d.ts.map +1 -0
- package/dist/core/agents/agent-config.test.d.ts +2 -0
- package/dist/core/agents/agent-config.test.d.ts.map +1 -0
- package/dist/core/agents/agent-roles.d.ts +33 -0
- package/dist/core/agents/agent-roles.d.ts.map +1 -0
- package/dist/core/agents/agent-shutdown.test.d.ts +6 -0
- package/dist/core/agents/agent-shutdown.test.d.ts.map +1 -0
- package/dist/core/agents/agent.d.ts +234 -0
- package/dist/core/agents/agent.d.ts.map +1 -0
- package/dist/core/agents/agent.test.d.ts +2 -0
- package/dist/core/agents/agent.test.d.ts.map +1 -0
- package/dist/core/agents/communicator.d.ts +3 -0
- package/dist/core/agents/communicator.d.ts.map +1 -0
- package/dist/core/agents/config.d.ts +84 -0
- package/dist/core/agents/config.d.ts.map +1 -0
- package/dist/core/agents/context.d.ts +16 -0
- package/dist/core/agents/context.d.ts.map +1 -0
- package/dist/core/agents/debounce.d.ts +52 -0
- package/dist/core/agents/debounce.d.ts.map +1 -0
- package/dist/core/agents/handler-events.test.d.ts +5 -0
- package/dist/core/agents/handler-events.test.d.ts.map +1 -0
- package/dist/core/agents/index.d.ts +2 -0
- package/dist/core/agents/index.d.ts.map +1 -0
- package/dist/core/agents/response-sanitizer.d.ts +25 -0
- package/dist/core/agents/response-sanitizer.d.ts.map +1 -0
- package/dist/core/agents/response-sanitizer.test.d.ts +2 -0
- package/dist/core/agents/response-sanitizer.test.d.ts.map +1 -0
- package/dist/core/agents/retry.d.ts +40 -0
- package/dist/core/agents/retry.d.ts.map +1 -0
- package/dist/core/agents/schema.d.ts +57 -0
- package/dist/core/agents/schema.d.ts.map +1 -0
- package/dist/core/agents/state.d.ts +255 -0
- package/dist/core/agents/state.d.ts.map +1 -0
- package/dist/core/context/state.d.ts +28 -0
- package/dist/core/context/state.d.ts.map +1 -0
- package/dist/core/errors.d.ts +29 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/event-sourcing.integration.test.d.ts +2 -0
- package/dist/core/event-sourcing.integration.test.d.ts.map +1 -0
- package/dist/core/events/base-event-store.d.ts +55 -0
- package/dist/core/events/base-event-store.d.ts.map +1 -0
- package/dist/core/events/event-store.d.ts +108 -0
- package/dist/core/events/event-store.d.ts.map +1 -0
- package/dist/core/events/file.d.ts +50 -0
- package/dist/core/events/file.d.ts.map +1 -0
- package/dist/core/events/file.test.d.ts +2 -0
- package/dist/core/events/file.test.d.ts.map +1 -0
- package/dist/core/events/index.d.ts +4 -0
- package/dist/core/events/index.d.ts.map +1 -0
- package/dist/core/events/memory.d.ts +43 -0
- package/dist/core/events/memory.d.ts.map +1 -0
- package/dist/core/events/memory.test.d.ts +2 -0
- package/dist/core/events/memory.test.d.ts.map +1 -0
- package/dist/core/events/metadata-utils.d.ts +27 -0
- package/dist/core/events/metadata-utils.d.ts.map +1 -0
- package/dist/core/events/test-helpers.d.ts +28 -0
- package/dist/core/events/test-helpers.d.ts.map +1 -0
- package/dist/core/events/types.d.ts +46 -0
- package/dist/core/events/types.d.ts.map +1 -0
- package/dist/core/file-store/file-store.d.ts +56 -0
- package/dist/core/file-store/file-store.d.ts.map +1 -0
- package/dist/core/file-store/types.d.ts +50 -0
- package/dist/core/file-store/types.d.ts.map +1 -0
- package/dist/core/image/image-processor.d.ts +15 -0
- package/dist/core/image/image-processor.d.ts.map +1 -0
- package/dist/core/image/image-processor.test.d.ts +2 -0
- package/dist/core/image/image-processor.test.d.ts.map +1 -0
- package/dist/core/image/index.d.ts +5 -0
- package/dist/core/image/index.d.ts.map +1 -0
- package/dist/core/image/noop-resizer.d.ts +5 -0
- package/dist/core/image/noop-resizer.d.ts.map +1 -0
- package/dist/core/image/types.d.ts +20 -0
- package/dist/core/image/types.d.ts.map +1 -0
- package/dist/core/image/vips-resizer.d.ts +21 -0
- package/dist/core/image/vips-resizer.d.ts.map +1 -0
- package/dist/core/image/vips-resizer.test.d.ts +2 -0
- package/dist/core/image/vips-resizer.test.d.ts.map +1 -0
- package/dist/core/llm/anthropic.d.ts +51 -0
- package/dist/core/llm/anthropic.d.ts.map +1 -0
- package/dist/core/llm/anthropic.test.d.ts +2 -0
- package/dist/core/llm/anthropic.test.d.ts.map +1 -0
- package/dist/core/llm/cache-breakpoints.d.ts +17 -0
- package/dist/core/llm/cache-breakpoints.d.ts.map +1 -0
- package/dist/core/llm/cache-live.test.d.ts +16 -0
- package/dist/core/llm/cache-live.test.d.ts.map +1 -0
- package/dist/core/llm/index.d.ts +16 -0
- package/dist/core/llm/index.d.ts.map +1 -0
- package/dist/core/llm/llm-log-types.d.ts +148 -0
- package/dist/core/llm/llm-log-types.d.ts.map +1 -0
- package/dist/core/llm/logger.d.ts +74 -0
- package/dist/core/llm/logger.d.ts.map +1 -0
- package/dist/core/llm/logger.test.d.ts +7 -0
- package/dist/core/llm/logger.test.d.ts.map +1 -0
- package/dist/core/llm/logging-provider.d.ts +20 -0
- package/dist/core/llm/logging-provider.d.ts.map +1 -0
- package/dist/core/llm/middleware.d.ts +79 -0
- package/dist/core/llm/middleware.d.ts.map +1 -0
- package/dist/core/llm/mock.d.ts +79 -0
- package/dist/core/llm/mock.d.ts.map +1 -0
- package/dist/core/llm/mock.test.d.ts +2 -0
- package/dist/core/llm/mock.test.d.ts.map +1 -0
- package/dist/core/llm/openrouter-mapping.test.d.ts +2 -0
- package/dist/core/llm/openrouter-mapping.test.d.ts.map +1 -0
- package/dist/core/llm/openrouter.d.ts +37 -0
- package/dist/core/llm/openrouter.d.ts.map +1 -0
- package/dist/core/llm/openrouter.test.d.ts +2 -0
- package/dist/core/llm/openrouter.test.d.ts.map +1 -0
- package/dist/core/llm/provider-integration.test.d.ts +12 -0
- package/dist/core/llm/provider-integration.test.d.ts.map +1 -0
- package/dist/core/llm/provider.d.ts +175 -0
- package/dist/core/llm/provider.d.ts.map +1 -0
- package/dist/core/llm/routing-provider.d.ts +31 -0
- package/dist/core/llm/routing-provider.d.ts.map +1 -0
- package/dist/core/llm/routing-provider.test.d.ts +2 -0
- package/dist/core/llm/routing-provider.test.d.ts.map +1 -0
- package/dist/core/llm/schema.d.ts +24 -0
- package/dist/core/llm/schema.d.ts.map +1 -0
- package/dist/core/llm/snapshot-fetch.d.ts +21 -0
- package/dist/core/llm/snapshot-fetch.d.ts.map +1 -0
- package/dist/core/llm/snapshot-middleware.d.ts +71 -0
- package/dist/core/llm/snapshot-middleware.d.ts.map +1 -0
- package/dist/core/llm/snapshot-middleware.test.d.ts +2 -0
- package/dist/core/llm/snapshot-middleware.test.d.ts.map +1 -0
- package/dist/core/llm/state.d.ts +73 -0
- package/dist/core/llm/state.d.ts.map +1 -0
- package/dist/core/llm/tokens.d.ts +36 -0
- package/dist/core/llm/tokens.d.ts.map +1 -0
- package/dist/core/multi-agent.integration.test.d.ts +2 -0
- package/dist/core/multi-agent.integration.test.d.ts.map +1 -0
- package/dist/core/plugin-hooks.integration.test.d.ts +2 -0
- package/dist/core/plugin-hooks.integration.test.d.ts.map +1 -0
- package/dist/core/plugins/hook-types.d.ts +55 -0
- package/dist/core/plugins/hook-types.d.ts.map +1 -0
- package/dist/core/plugins/index.d.ts +23 -0
- package/dist/core/plugins/index.d.ts.map +1 -0
- package/dist/core/plugins/plugin-builder.d.ts +474 -0
- package/dist/core/plugins/plugin-builder.d.ts.map +1 -0
- package/dist/core/preset/config.d.ts +55 -0
- package/dist/core/preset/config.d.ts.map +1 -0
- package/dist/core/preset/index.d.ts +8 -0
- package/dist/core/preset/index.d.ts.map +1 -0
- package/dist/core/preset/preset-builder.d.ts +44 -0
- package/dist/core/preset/preset-builder.d.ts.map +1 -0
- package/dist/core/session-lifecycle.integration.test.d.ts +2 -0
- package/dist/core/session-lifecycle.integration.test.d.ts.map +1 -0
- package/dist/core/sessions/apply-event.d.ts +19 -0
- package/dist/core/sessions/apply-event.d.ts.map +1 -0
- package/dist/core/sessions/context.d.ts +34 -0
- package/dist/core/sessions/context.d.ts.map +1 -0
- package/dist/core/sessions/fork-utils.d.ts +20 -0
- package/dist/core/sessions/fork-utils.d.ts.map +1 -0
- package/dist/core/sessions/fork-utils.test.d.ts +2 -0
- package/dist/core/sessions/fork-utils.test.d.ts.map +1 -0
- package/dist/core/sessions/reducer.d.ts +50 -0
- package/dist/core/sessions/reducer.d.ts.map +1 -0
- package/dist/core/sessions/schema.d.ts +82 -0
- package/dist/core/sessions/schema.d.ts.map +1 -0
- package/dist/core/sessions/session-environment.d.ts +13 -0
- package/dist/core/sessions/session-environment.d.ts.map +1 -0
- package/dist/core/sessions/session-manager.d.ts +183 -0
- package/dist/core/sessions/session-manager.d.ts.map +1 -0
- package/dist/core/sessions/session-store.d.ts +69 -0
- package/dist/core/sessions/session-store.d.ts.map +1 -0
- package/dist/core/sessions/session.d.ts +212 -0
- package/dist/core/sessions/session.d.ts.map +1 -0
- package/dist/core/sessions/session.test.d.ts +2 -0
- package/dist/core/sessions/session.test.d.ts.map +1 -0
- package/dist/core/sessions/state.d.ts +110 -0
- package/dist/core/sessions/state.d.ts.map +1 -0
- package/dist/core/system.d.ts +97 -0
- package/dist/core/system.d.ts.map +1 -0
- package/dist/core/tools/context.d.ts +3 -0
- package/dist/core/tools/context.d.ts.map +1 -0
- package/dist/core/tools/definition.d.ts +10 -0
- package/dist/core/tools/definition.d.ts.map +1 -0
- package/dist/core/tools/executor.d.ts +28 -0
- package/dist/core/tools/executor.d.ts.map +1 -0
- package/dist/core/tools/executor.test.d.ts +2 -0
- package/dist/core/tools/executor.test.d.ts.map +1 -0
- package/dist/core/tools/index.d.ts +4 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/schema.d.ts +61 -0
- package/dist/core/tools/schema.d.ts.map +1 -0
- package/dist/core/tools/state.d.ts +28 -0
- package/dist/core/tools/state.d.ts.map +1 -0
- package/dist/index.d.ts +111 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/lib/json/index.d.ts +17 -0
- package/dist/lib/json/index.d.ts.map +1 -0
- package/dist/lib/logger/console.d.ts +35 -0
- package/dist/lib/logger/console.d.ts.map +1 -0
- package/dist/lib/logger/console.test.d.ts +2 -0
- package/dist/lib/logger/console.test.d.ts.map +1 -0
- package/dist/lib/logger/file.d.ts +20 -0
- package/dist/lib/logger/file.d.ts.map +1 -0
- package/dist/lib/logger/index.d.ts +5 -0
- package/dist/lib/logger/index.d.ts.map +1 -0
- package/dist/lib/logger/logger.d.ts +87 -0
- package/dist/lib/logger/logger.d.ts.map +1 -0
- package/dist/lib/logger/ring-buffer.d.ts +33 -0
- package/dist/lib/logger/ring-buffer.d.ts.map +1 -0
- package/dist/lib/logger/tee.d.ts +15 -0
- package/dist/lib/logger/tee.d.ts.map +1 -0
- package/dist/lib/mime.d.ts +9 -0
- package/dist/lib/mime.d.ts.map +1 -0
- package/dist/lib/never.d.ts +2 -0
- package/dist/lib/never.d.ts.map +1 -0
- package/dist/lib/utils/hash.d.ts +19 -0
- package/dist/lib/utils/hash.d.ts.map +1 -0
- package/dist/lib/utils/result.d.ts +26 -0
- package/dist/lib/utils/result.d.ts.map +1 -0
- package/dist/platform/fs.d.ts +39 -0
- package/dist/platform/fs.d.ts.map +1 -0
- package/dist/platform/index.d.ts +21 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/process.d.ts +24 -0
- package/dist/platform/process.d.ts.map +1 -0
- package/dist/plugins/agent-status/plugin.d.ts +8 -0
- package/dist/plugins/agent-status/plugin.d.ts.map +1 -0
- package/dist/plugins/agents/agents.integration.test.d.ts +2 -0
- package/dist/plugins/agents/agents.integration.test.d.ts.map +1 -0
- package/dist/plugins/agents/index.d.ts +3 -0
- package/dist/plugins/agents/index.d.ts.map +1 -0
- package/dist/plugins/agents/plugin.d.ts +57 -0
- package/dist/plugins/agents/plugin.d.ts.map +1 -0
- package/dist/plugins/context-compact/context-compact.integration.test.d.ts +2 -0
- package/dist/plugins/context-compact/context-compact.integration.test.d.ts.map +1 -0
- package/dist/plugins/context-compact/context-compactor.d.ts +88 -0
- package/dist/plugins/context-compact/context-compactor.d.ts.map +1 -0
- package/dist/plugins/context-compact/context-compactor.test.d.ts +2 -0
- package/dist/plugins/context-compact/context-compactor.test.d.ts.map +1 -0
- package/dist/plugins/context-compact/history-offloader.d.ts +17 -0
- package/dist/plugins/context-compact/history-offloader.d.ts.map +1 -0
- package/dist/plugins/context-compact/history-offloader.test.d.ts +2 -0
- package/dist/plugins/context-compact/history-offloader.test.d.ts.map +1 -0
- package/dist/plugins/context-compact/index.d.ts +4 -0
- package/dist/plugins/context-compact/index.d.ts.map +1 -0
- package/dist/plugins/context-compact/plugin.d.ts +15 -0
- package/dist/plugins/context-compact/plugin.d.ts.map +1 -0
- package/dist/plugins/filesystem/filesystem.integration.test.d.ts +2 -0
- package/dist/plugins/filesystem/filesystem.integration.test.d.ts.map +1 -0
- package/dist/plugins/filesystem/helpers.d.ts +34 -0
- package/dist/plugins/filesystem/helpers.d.ts.map +1 -0
- package/dist/plugins/filesystem/index.d.ts +5 -0
- package/dist/plugins/filesystem/index.d.ts.map +1 -0
- package/dist/plugins/filesystem/listing.d.ts +38 -0
- package/dist/plugins/filesystem/listing.d.ts.map +1 -0
- package/dist/plugins/filesystem/plugin.d.ts +53 -0
- package/dist/plugins/filesystem/plugin.d.ts.map +1 -0
- package/dist/plugins/filesystem/schema.d.ts +7 -0
- package/dist/plugins/filesystem/schema.d.ts.map +1 -0
- package/dist/plugins/git-status/index.d.ts +2 -0
- package/dist/plugins/git-status/index.d.ts.map +1 -0
- package/dist/plugins/git-status/plugin.d.ts +12 -0
- package/dist/plugins/git-status/plugin.d.ts.map +1 -0
- package/dist/plugins/limits-guard/config.d.ts +23 -0
- package/dist/plugins/limits-guard/config.d.ts.map +1 -0
- package/dist/plugins/limits-guard/index.d.ts +5 -0
- package/dist/plugins/limits-guard/index.d.ts.map +1 -0
- package/dist/plugins/limits-guard/limit-guard.d.ts +40 -0
- package/dist/plugins/limits-guard/limit-guard.d.ts.map +1 -0
- package/dist/plugins/limits-guard/limit-guard.test.d.ts +2 -0
- package/dist/plugins/limits-guard/limit-guard.test.d.ts.map +1 -0
- package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts +2 -0
- package/dist/plugins/limits-guard/limits-guard.integration.test.d.ts.map +1 -0
- package/dist/plugins/limits-guard/plugin.d.ts +39 -0
- package/dist/plugins/limits-guard/plugin.d.ts.map +1 -0
- package/dist/plugins/llm-debug/index.d.ts +2 -0
- package/dist/plugins/llm-debug/index.d.ts.map +1 -0
- package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts +2 -0
- package/dist/plugins/llm-debug/llm-debug.integration.test.d.ts.map +1 -0
- package/dist/plugins/llm-debug/plugin.d.ts +31 -0
- package/dist/plugins/llm-debug/plugin.d.ts.map +1 -0
- package/dist/plugins/logs/index.d.ts +2 -0
- package/dist/plugins/logs/index.d.ts.map +1 -0
- package/dist/plugins/logs/plugin.d.ts +10 -0
- package/dist/plugins/logs/plugin.d.ts.map +1 -0
- package/dist/plugins/mailbox/helpers.d.ts +20 -0
- package/dist/plugins/mailbox/helpers.d.ts.map +1 -0
- package/dist/plugins/mailbox/index.d.ts +9 -0
- package/dist/plugins/mailbox/index.d.ts.map +1 -0
- package/dist/plugins/mailbox/mailbox.integration.test.d.ts +2 -0
- package/dist/plugins/mailbox/mailbox.integration.test.d.ts.map +1 -0
- package/dist/plugins/mailbox/plugin.d.ts +31 -0
- package/dist/plugins/mailbox/plugin.d.ts.map +1 -0
- package/dist/plugins/mailbox/prompts.d.ts +21 -0
- package/dist/plugins/mailbox/prompts.d.ts.map +1 -0
- package/dist/plugins/mailbox/query.d.ts +33 -0
- package/dist/plugins/mailbox/query.d.ts.map +1 -0
- package/dist/plugins/mailbox/schema.d.ts +54 -0
- package/dist/plugins/mailbox/schema.d.ts.map +1 -0
- package/dist/plugins/mailbox/state.d.ts +40 -0
- package/dist/plugins/mailbox/state.d.ts.map +1 -0
- package/dist/plugins/resources/index.d.ts +7 -0
- package/dist/plugins/resources/index.d.ts.map +1 -0
- package/dist/plugins/resources/manifest.d.ts +23 -0
- package/dist/plugins/resources/manifest.d.ts.map +1 -0
- package/dist/plugins/resources/plugin.d.ts +28 -0
- package/dist/plugins/resources/plugin.d.ts.map +1 -0
- package/dist/plugins/resources/post-inject.d.ts +39 -0
- package/dist/plugins/resources/post-inject.d.ts.map +1 -0
- package/dist/plugins/resources/state.d.ts +25 -0
- package/dist/plugins/resources/state.d.ts.map +1 -0
- package/dist/plugins/result-eviction/index.d.ts +3 -0
- package/dist/plugins/result-eviction/index.d.ts.map +1 -0
- package/dist/plugins/result-eviction/plugin.d.ts +19 -0
- package/dist/plugins/result-eviction/plugin.d.ts.map +1 -0
- package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts +2 -0
- package/dist/plugins/result-eviction/result-eviction.integration.test.d.ts.map +1 -0
- package/dist/plugins/services/plugin.d.ts +85 -0
- package/dist/plugins/services/plugin.d.ts.map +1 -0
- package/dist/plugins/services/port-pool.d.ts +32 -0
- package/dist/plugins/services/port-pool.d.ts.map +1 -0
- package/dist/plugins/services/prompt.d.ts +13 -0
- package/dist/plugins/services/prompt.d.ts.map +1 -0
- package/dist/plugins/services/schema.d.ts +70 -0
- package/dist/plugins/services/schema.d.ts.map +1 -0
- package/dist/plugins/services/service.d.ts +86 -0
- package/dist/plugins/services/service.d.ts.map +1 -0
- package/dist/plugins/services/services.integration.test.d.ts +2 -0
- package/dist/plugins/services/services.integration.test.d.ts.map +1 -0
- package/dist/plugins/session-lifecycle/index.d.ts +2 -0
- package/dist/plugins/session-lifecycle/index.d.ts.map +1 -0
- package/dist/plugins/session-lifecycle/plugin.d.ts +97 -0
- package/dist/plugins/session-lifecycle/plugin.d.ts.map +1 -0
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts +2 -0
- package/dist/plugins/session-lifecycle/session-lifecycle.integration.test.d.ts.map +1 -0
- package/dist/plugins/session-state/plugin.d.ts +48 -0
- package/dist/plugins/session-state/plugin.d.ts.map +1 -0
- package/dist/plugins/session-stats/index.d.ts +4 -0
- package/dist/plugins/session-stats/index.d.ts.map +1 -0
- package/dist/plugins/session-stats/plugin.d.ts +29 -0
- package/dist/plugins/session-stats/plugin.d.ts.map +1 -0
- package/dist/plugins/shell/executor.d.ts +78 -0
- package/dist/plugins/shell/executor.d.ts.map +1 -0
- package/dist/plugins/shell/index.d.ts +6 -0
- package/dist/plugins/shell/index.d.ts.map +1 -0
- package/dist/plugins/shell/plugin.d.ts +51 -0
- package/dist/plugins/shell/plugin.d.ts.map +1 -0
- package/dist/plugins/shell/shell.integration.test.d.ts +2 -0
- package/dist/plugins/shell/shell.integration.test.d.ts.map +1 -0
- package/dist/plugins/shell/shell.test.d.ts +2 -0
- package/dist/plugins/shell/shell.test.d.ts.map +1 -0
- package/dist/plugins/skills/discovery.d.ts +69 -0
- package/dist/plugins/skills/discovery.d.ts.map +1 -0
- package/dist/plugins/skills/discovery.test.d.ts +2 -0
- package/dist/plugins/skills/discovery.test.d.ts.map +1 -0
- package/dist/plugins/skills/index.d.ts +11 -0
- package/dist/plugins/skills/index.d.ts.map +1 -0
- package/dist/plugins/skills/plugin.d.ts +94 -0
- package/dist/plugins/skills/plugin.d.ts.map +1 -0
- package/dist/plugins/skills/prompts.d.ts +29 -0
- package/dist/plugins/skills/prompts.d.ts.map +1 -0
- package/dist/plugins/skills/schema.d.ts +64 -0
- package/dist/plugins/skills/schema.d.ts.map +1 -0
- package/dist/plugins/skills/skills.integration.test.d.ts +2 -0
- package/dist/plugins/skills/skills.integration.test.d.ts.map +1 -0
- package/dist/plugins/snapshotting/index.d.ts +4 -0
- package/dist/plugins/snapshotting/index.d.ts.map +1 -0
- package/dist/plugins/snapshotting/jj-snapshotter.d.ts +27 -0
- package/dist/plugins/snapshotting/jj-snapshotter.d.ts.map +1 -0
- package/dist/plugins/snapshotting/plugin.d.ts +15 -0
- package/dist/plugins/snapshotting/plugin.d.ts.map +1 -0
- package/dist/plugins/snapshotting/snapshotter.d.ts +19 -0
- package/dist/plugins/snapshotting/snapshotter.d.ts.map +1 -0
- package/dist/plugins/todo/index.d.ts +7 -0
- package/dist/plugins/todo/index.d.ts.map +1 -0
- package/dist/plugins/todo/plugin.d.ts +95 -0
- package/dist/plugins/todo/plugin.d.ts.map +1 -0
- package/dist/plugins/todo/prompts.d.ts +13 -0
- package/dist/plugins/todo/prompts.d.ts.map +1 -0
- package/dist/plugins/todo/schema.d.ts +44 -0
- package/dist/plugins/todo/schema.d.ts.map +1 -0
- package/dist/plugins/todo/todo.integration.test.d.ts +2 -0
- package/dist/plugins/todo/todo.integration.test.d.ts.map +1 -0
- package/dist/plugins/uploads/index.d.ts +9 -0
- package/dist/plugins/uploads/index.d.ts.map +1 -0
- package/dist/plugins/uploads/plugin.d.ts +56 -0
- package/dist/plugins/uploads/plugin.d.ts.map +1 -0
- package/dist/plugins/uploads/preprocessor.d.ts +70 -0
- package/dist/plugins/uploads/preprocessor.d.ts.map +1 -0
- package/dist/plugins/uploads/preprocessors/image-classifier.d.ts +49 -0
- package/dist/plugins/uploads/preprocessors/image-classifier.d.ts.map +1 -0
- package/dist/plugins/uploads/preprocessors/index.d.ts +7 -0
- package/dist/plugins/uploads/preprocessors/index.d.ts.map +1 -0
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts +43 -0
- package/dist/plugins/uploads/preprocessors/markitdown-preprocessor.d.ts.map +1 -0
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts +30 -0
- package/dist/plugins/uploads/preprocessors/zip-preprocessor.d.ts.map +1 -0
- package/dist/plugins/uploads/schema.d.ts +72 -0
- package/dist/plugins/uploads/schema.d.ts.map +1 -0
- package/dist/plugins/uploads/state.d.ts +38 -0
- package/dist/plugins/uploads/state.d.ts.map +1 -0
- package/dist/plugins/uploads/uploads.integration.test.d.ts +2 -0
- package/dist/plugins/uploads/uploads.integration.test.d.ts.map +1 -0
- package/dist/plugins/user-chat/index.d.ts +7 -0
- package/dist/plugins/user-chat/index.d.ts.map +1 -0
- package/dist/plugins/user-chat/plugin.d.ts +221 -0
- package/dist/plugins/user-chat/plugin.d.ts.map +1 -0
- package/dist/plugins/user-chat/prompts.d.ts +13 -0
- package/dist/plugins/user-chat/prompts.d.ts.map +1 -0
- package/dist/plugins/user-chat/schema.d.ts +82 -0
- package/dist/plugins/user-chat/schema.d.ts.map +1 -0
- package/dist/plugins/user-chat/user-chat.integration.test.d.ts +2 -0
- package/dist/plugins/user-chat/user-chat.integration.test.d.ts.map +1 -0
- package/dist/plugins/workers/context.d.ts +159 -0
- package/dist/plugins/workers/context.d.ts.map +1 -0
- package/dist/plugins/workers/definition.d.ts +118 -0
- package/dist/plugins/workers/definition.d.ts.map +1 -0
- package/dist/plugins/workers/index.d.ts +11 -0
- package/dist/plugins/workers/index.d.ts.map +1 -0
- package/dist/plugins/workers/plugin.d.ts +125 -0
- package/dist/plugins/workers/plugin.d.ts.map +1 -0
- package/dist/plugins/workers/worker.d.ts +76 -0
- package/dist/plugins/workers/worker.d.ts.map +1 -0
- package/dist/plugins/workers/workers.integration.test.d.ts +2 -0
- package/dist/plugins/workers/workers.integration.test.d.ts.map +1 -0
- package/dist/prompts/base.d.ts +75 -0
- package/dist/prompts/base.d.ts.map +1 -0
- package/dist/prompts/builder.d.ts +73 -0
- package/dist/prompts/builder.d.ts.map +1 -0
- package/dist/prompts/index.d.ts +10 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/macros.d.ts +15 -0
- package/dist/prompts/macros.d.ts.map +1 -0
- package/dist/prompts/macros.test.d.ts +2 -0
- package/dist/prompts/macros.test.d.ts.map +1 -0
- package/dist/testing/bootstrap-for-testing.d.ts +12 -0
- package/dist/testing/bootstrap-for-testing.d.ts.map +1 -0
- package/dist/testing/index.d.ts +8 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/node-platform.d.ts +12 -0
- package/dist/testing/node-platform.d.ts.map +1 -0
- package/dist/testing/notification-collector.d.ts +46 -0
- package/dist/testing/notification-collector.d.ts.map +1 -0
- package/dist/testing/preset-helpers.d.ts +28 -0
- package/dist/testing/preset-helpers.d.ts.map +1 -0
- package/dist/testing/test-harness.d.ts +117 -0
- package/dist/testing/test-harness.d.ts.map +1 -0
- package/dist/testing/test-harness.test.d.ts +2 -0
- package/dist/testing/test-harness.test.d.ts.map +1 -0
- package/dist/testing/wait-helpers.d.ts +17 -0
- package/dist/testing/wait-helpers.d.ts.map +1 -0
- package/dist/transport/adapter/client-adapter.d.ts +32 -0
- package/dist/transport/adapter/client-adapter.d.ts.map +1 -0
- package/dist/transport/adapter/index.d.ts +23 -0
- package/dist/transport/adapter/index.d.ts.map +1 -0
- package/dist/transport/adapter/server-adapter.d.ts +29 -0
- package/dist/transport/adapter/server-adapter.d.ts.map +1 -0
- package/dist/transport/adapter/types.d.ts +14 -0
- package/dist/transport/adapter/types.d.ts.map +1 -0
- package/dist/transport/http/app.d.ts +41 -0
- package/dist/transport/http/app.d.ts.map +1 -0
- package/dist/transport/http/index.d.ts +7 -0
- package/dist/transport/http/index.d.ts.map +1 -0
- package/dist/transport/http/middleware/bearer-auth.d.ts +16 -0
- package/dist/transport/http/middleware/bearer-auth.d.ts.map +1 -0
- package/dist/transport/http/middleware/error-handler.d.ts +21 -0
- package/dist/transport/http/middleware/error-handler.d.ts.map +1 -0
- package/dist/transport/http/routes/files.d.ts +16 -0
- package/dist/transport/http/routes/files.d.ts.map +1 -0
- package/dist/transport/http/routes/resources.d.ts +12 -0
- package/dist/transport/http/routes/resources.d.ts.map +1 -0
- package/dist/transport/http/routes/rpc.d.ts +22 -0
- package/dist/transport/http/routes/rpc.d.ts.map +1 -0
- package/dist/transport/http/routes/rpc.integration.test.d.ts +2 -0
- package/dist/transport/http/routes/rpc.integration.test.d.ts.map +1 -0
- package/dist/transport/http/routes/rpc.test.d.ts +2 -0
- package/dist/transport/http/routes/rpc.test.d.ts.map +1 -0
- package/dist/transport/http/routes/upload.d.ts +14 -0
- package/dist/transport/http/routes/upload.d.ts.map +1 -0
- package/dist/transport/rpc/index.d.ts +8 -0
- package/dist/transport/rpc/index.d.ts.map +1 -0
- package/dist/transport/rpc/methods.d.ts +25 -0
- package/dist/transport/rpc/methods.d.ts.map +1 -0
- package/dist/user-config.d.ts +29 -0
- package/dist/user-config.d.ts.map +1 -0
- package/package.json +154 -0
- package/src/bootstrap.ts +268 -0
- package/src/builtin-events.ts +25 -0
- package/src/bun-platform/fs.ts +50 -0
- package/src/bun-platform/index.ts +21 -0
- package/src/bun-platform/process.ts +25 -0
- package/src/config.test.ts +174 -0
- package/src/config.ts +103 -0
- package/src/core/agent-loop.integration.test.ts +503 -0
- package/src/core/agents/agent-config.test.ts +240 -0
- package/src/core/agents/agent-roles.ts +41 -0
- package/src/core/agents/agent-shutdown.test.ts +236 -0
- package/src/core/agents/agent.test.ts +387 -0
- package/src/core/agents/agent.ts +1472 -0
- package/src/core/agents/communicator.ts +16 -0
- package/src/core/agents/config.ts +98 -0
- package/src/core/agents/context.ts +19 -0
- package/src/core/agents/debounce.ts +116 -0
- package/src/core/agents/handler-events.test.ts +167 -0
- package/src/core/agents/index.ts +1 -0
- package/src/core/agents/response-sanitizer.test.ts +137 -0
- package/src/core/agents/response-sanitizer.ts +67 -0
- package/src/core/agents/retry.ts +164 -0
- package/src/core/agents/schema.ts +75 -0
- package/src/core/agents/state.ts +272 -0
- package/src/core/context/state.ts +38 -0
- package/src/core/errors.ts +55 -0
- package/src/core/event-sourcing.integration.test.ts +191 -0
- package/src/core/events/base-event-store.ts +264 -0
- package/src/core/events/event-store.ts +143 -0
- package/src/core/events/file.test.ts +436 -0
- package/src/core/events/file.ts +372 -0
- package/src/core/events/index.ts +3 -0
- package/src/core/events/memory.test.ts +741 -0
- package/src/core/events/memory.ts +131 -0
- package/src/core/events/metadata-utils.ts +133 -0
- package/src/core/events/test-helpers.ts +31 -0
- package/src/core/events/types.ts +64 -0
- package/src/core/file-store/file-store.ts +275 -0
- package/src/core/file-store/types.ts +52 -0
- package/src/core/image/image-processor.test.ts +218 -0
- package/src/core/image/image-processor.ts +127 -0
- package/src/core/image/index.ts +4 -0
- package/src/core/image/noop-resizer.ts +7 -0
- package/src/core/image/types.ts +24 -0
- package/src/core/image/vips-resizer.test.ts +377 -0
- package/src/core/image/vips-resizer.ts +124 -0
- package/src/core/llm/__snapshots__/anthropic-assistant-text-with-tool-calls.json +156 -0
- package/src/core/llm/__snapshots__/anthropic-consecutive-tool-results.json +152 -0
- package/src/core/llm/__snapshots__/anthropic-image-data-url.json +105 -0
- package/src/core/llm/__snapshots__/anthropic-image-http-url.json +104 -0
- package/src/core/llm/__snapshots__/anthropic-multiple-images.json +113 -0
- package/src/core/llm/__snapshots__/anthropic-multiple-tool-calls-requested.json +151 -0
- package/src/core/llm/__snapshots__/anthropic-simple-user-message.json +97 -0
- package/src/core/llm/__snapshots__/anthropic-system-message-in-conversation.json +119 -0
- package/src/core/llm/__snapshots__/anthropic-tool-call.json +123 -0
- package/src/core/llm/__snapshots__/anthropic-tool-error-result.json +139 -0
- package/src/core/llm/__snapshots__/anthropic-tool-result-with-image.json +152 -0
- package/src/core/llm/__snapshots__/anthropic-tool-roundtrip.json +139 -0
- package/src/core/llm/__snapshots__/openrouter-assistant-text-with-tool-calls.json +150 -0
- package/src/core/llm/__snapshots__/openrouter-consecutive-tool-results.json +150 -0
- package/src/core/llm/__snapshots__/openrouter-image-data-url.json +107 -0
- package/src/core/llm/__snapshots__/openrouter-image-http-url.json +107 -0
- package/src/core/llm/__snapshots__/openrouter-multiple-images.json +113 -0
- package/src/core/llm/__snapshots__/openrouter-multiple-tool-calls-requested.json +158 -0
- package/src/core/llm/__snapshots__/openrouter-simple-user-message.json +96 -0
- package/src/core/llm/__snapshots__/openrouter-system-message-in-conversation.json +108 -0
- package/src/core/llm/__snapshots__/openrouter-tool-call.json +129 -0
- package/src/core/llm/__snapshots__/openrouter-tool-error-result.json +137 -0
- package/src/core/llm/__snapshots__/openrouter-tool-result-with-image.json +148 -0
- package/src/core/llm/__snapshots__/openrouter-tool-roundtrip.json +137 -0
- package/src/core/llm/anthropic.test.ts +509 -0
- package/src/core/llm/anthropic.ts +578 -0
- package/src/core/llm/cache-breakpoints.ts +38 -0
- package/src/core/llm/cache-live.test.ts +155 -0
- package/src/core/llm/index.ts +30 -0
- package/src/core/llm/llm-log-types.ts +167 -0
- package/src/core/llm/logger.test.ts +270 -0
- package/src/core/llm/logger.ts +306 -0
- package/src/core/llm/logging-provider.ts +73 -0
- package/src/core/llm/middleware.ts +172 -0
- package/src/core/llm/mock.test.ts +402 -0
- package/src/core/llm/mock.ts +234 -0
- package/src/core/llm/openrouter-mapping.test.ts +153 -0
- package/src/core/llm/openrouter.test.ts +499 -0
- package/src/core/llm/openrouter.ts +458 -0
- package/src/core/llm/provider-integration.test.ts +408 -0
- package/src/core/llm/provider.ts +238 -0
- package/src/core/llm/routing-provider.test.ts +113 -0
- package/src/core/llm/routing-provider.ts +86 -0
- package/src/core/llm/schema.ts +47 -0
- package/src/core/llm/snapshot-fetch.ts +158 -0
- package/src/core/llm/snapshot-middleware.test.ts +168 -0
- package/src/core/llm/snapshot-middleware.ts +185 -0
- package/src/core/llm/state.ts +92 -0
- package/src/core/llm/tokens.ts +61 -0
- package/src/core/multi-agent.integration.test.ts +340 -0
- package/src/core/plugin-hooks.integration.test.ts +428 -0
- package/src/core/plugins/hook-types.ts +49 -0
- package/src/core/plugins/index.ts +52 -0
- package/src/core/plugins/plugin-builder.ts +967 -0
- package/src/core/preset/config.ts +110 -0
- package/src/core/preset/index.ts +11 -0
- package/src/core/preset/preset-builder.ts +111 -0
- package/src/core/session-lifecycle.integration.test.ts +202 -0
- package/src/core/sessions/apply-event.ts +46 -0
- package/src/core/sessions/context.ts +36 -0
- package/src/core/sessions/fork-utils.test.ts +158 -0
- package/src/core/sessions/fork-utils.ts +71 -0
- package/src/core/sessions/reducer.ts +95 -0
- package/src/core/sessions/schema.ts +91 -0
- package/src/core/sessions/session-environment.ts +12 -0
- package/src/core/sessions/session-manager.ts +883 -0
- package/src/core/sessions/session-store.ts +141 -0
- package/src/core/sessions/session.test.ts +1730 -0
- package/src/core/sessions/session.ts +833 -0
- package/src/core/sessions/state.ts +520 -0
- package/src/core/system.ts +206 -0
- package/src/core/tools/context.ts +3 -0
- package/src/core/tools/definition.ts +15 -0
- package/src/core/tools/executor.test.ts +160 -0
- package/src/core/tools/executor.ts +117 -0
- package/src/core/tools/index.ts +3 -0
- package/src/core/tools/schema.ts +80 -0
- package/src/core/tools/state.ts +34 -0
- package/src/index.ts +165 -0
- package/src/lib/json/index.ts +20 -0
- package/src/lib/logger/console.test.ts +348 -0
- package/src/lib/logger/console.ts +185 -0
- package/src/lib/logger/file.ts +65 -0
- package/src/lib/logger/index.ts +4 -0
- package/src/lib/logger/logger.ts +114 -0
- package/src/lib/logger/ring-buffer.ts +65 -0
- package/src/lib/logger/tee.ts +51 -0
- package/src/lib/mime.ts +23 -0
- package/src/lib/never.ts +3 -0
- package/src/lib/utils/hash.ts +38 -0
- package/src/lib/utils/result.ts +35 -0
- package/src/platform/fs.ts +38 -0
- package/src/platform/index.ts +23 -0
- package/src/platform/process.ts +28 -0
- package/src/plugins/agent-status/plugin.ts +77 -0
- package/src/plugins/agents/agents.integration.test.ts +808 -0
- package/src/plugins/agents/index.ts +2 -0
- package/src/plugins/agents/plugin.ts +242 -0
- package/src/plugins/context-compact/context-compact.integration.test.ts +207 -0
- package/src/plugins/context-compact/context-compactor.test.ts +923 -0
- package/src/plugins/context-compact/context-compactor.ts +343 -0
- package/src/plugins/context-compact/history-offloader.test.ts +100 -0
- package/src/plugins/context-compact/history-offloader.ts +47 -0
- package/src/plugins/context-compact/index.ts +3 -0
- package/src/plugins/context-compact/plugin.ts +62 -0
- package/src/plugins/filesystem/filesystem.integration.test.ts +485 -0
- package/src/plugins/filesystem/helpers.ts +216 -0
- package/src/plugins/filesystem/index.ts +4 -0
- package/src/plugins/filesystem/listing.ts +276 -0
- package/src/plugins/filesystem/plugin.ts +468 -0
- package/src/plugins/filesystem/schema.ts +6 -0
- package/src/plugins/git-status/index.ts +1 -0
- package/src/plugins/git-status/plugin.ts +166 -0
- package/src/plugins/limits-guard/config.ts +26 -0
- package/src/plugins/limits-guard/index.ts +4 -0
- package/src/plugins/limits-guard/limit-guard.test.ts +161 -0
- package/src/plugins/limits-guard/limit-guard.ts +164 -0
- package/src/plugins/limits-guard/limits-guard.integration.test.ts +437 -0
- package/src/plugins/limits-guard/plugin.ts +306 -0
- package/src/plugins/llm-debug/index.ts +1 -0
- package/src/plugins/llm-debug/llm-debug.integration.test.ts +192 -0
- package/src/plugins/llm-debug/plugin.ts +172 -0
- package/src/plugins/logs/index.ts +1 -0
- package/src/plugins/logs/plugin.ts +39 -0
- package/src/plugins/mailbox/helpers.ts +83 -0
- package/src/plugins/mailbox/index.ts +13 -0
- package/src/plugins/mailbox/mailbox.integration.test.ts +705 -0
- package/src/plugins/mailbox/plugin.ts +270 -0
- package/src/plugins/mailbox/prompts.ts +104 -0
- package/src/plugins/mailbox/query.ts +53 -0
- package/src/plugins/mailbox/schema.ts +81 -0
- package/src/plugins/mailbox/state.ts +52 -0
- package/src/plugins/resources/index.ts +11 -0
- package/src/plugins/resources/manifest.ts +25 -0
- package/src/plugins/resources/plugin.ts +201 -0
- package/src/plugins/resources/post-inject.ts +74 -0
- package/src/plugins/resources/state.ts +30 -0
- package/src/plugins/result-eviction/index.ts +2 -0
- package/src/plugins/result-eviction/plugin.ts +65 -0
- package/src/plugins/result-eviction/result-eviction.integration.test.ts +244 -0
- package/src/plugins/services/plugin.ts +485 -0
- package/src/plugins/services/port-pool.ts +73 -0
- package/src/plugins/services/prompt.ts +53 -0
- package/src/plugins/services/schema.ts +83 -0
- package/src/plugins/services/service.ts +578 -0
- package/src/plugins/services/services.integration.test.ts +595 -0
- package/src/plugins/session-lifecycle/index.ts +1 -0
- package/src/plugins/session-lifecycle/plugin.ts +302 -0
- package/src/plugins/session-lifecycle/session-lifecycle.integration.test.ts +639 -0
- package/src/plugins/session-state/plugin.ts +179 -0
- package/src/plugins/session-stats/index.ts +3 -0
- package/src/plugins/session-stats/plugin.ts +120 -0
- package/src/plugins/shell/executor.ts +462 -0
- package/src/plugins/shell/index.ts +23 -0
- package/src/plugins/shell/plugin.ts +118 -0
- package/src/plugins/shell/shell.integration.test.ts +273 -0
- package/src/plugins/shell/shell.test.ts +314 -0
- package/src/plugins/skills/discovery.test.ts +395 -0
- package/src/plugins/skills/discovery.ts +276 -0
- package/src/plugins/skills/index.ts +32 -0
- package/src/plugins/skills/plugin.ts +381 -0
- package/src/plugins/skills/prompts.ts +84 -0
- package/src/plugins/skills/schema.ts +88 -0
- package/src/plugins/skills/skills.integration.test.ts +580 -0
- package/src/plugins/snapshotting/index.ts +3 -0
- package/src/plugins/snapshotting/jj-snapshotter.ts +122 -0
- package/src/plugins/snapshotting/plugin.ts +36 -0
- package/src/plugins/snapshotting/snapshotter.ts +20 -0
- package/src/plugins/todo/index.ts +11 -0
- package/src/plugins/todo/plugin.ts +363 -0
- package/src/plugins/todo/prompts.ts +63 -0
- package/src/plugins/todo/schema.ts +71 -0
- package/src/plugins/todo/todo.integration.test.ts +687 -0
- package/src/plugins/uploads/index.ts +13 -0
- package/src/plugins/uploads/plugin.ts +406 -0
- package/src/plugins/uploads/preprocessor.ts +111 -0
- package/src/plugins/uploads/preprocessors/image-classifier.ts +176 -0
- package/src/plugins/uploads/preprocessors/index.ts +7 -0
- package/src/plugins/uploads/preprocessors/markitdown-preprocessor.ts +262 -0
- package/src/plugins/uploads/preprocessors/zip-preprocessor.ts +210 -0
- package/src/plugins/uploads/schema.ts +92 -0
- package/src/plugins/uploads/state.ts +42 -0
- package/src/plugins/uploads/uploads.integration.test.ts +654 -0
- package/src/plugins/user-chat/index.ts +17 -0
- package/src/plugins/user-chat/plugin.ts +728 -0
- package/src/plugins/user-chat/prompts.ts +30 -0
- package/src/plugins/user-chat/schema.ts +80 -0
- package/src/plugins/user-chat/user-chat.integration.test.ts +794 -0
- package/src/plugins/workers/context.ts +251 -0
- package/src/plugins/workers/definition.ts +169 -0
- package/src/plugins/workers/index.ts +21 -0
- package/src/plugins/workers/plugin.ts +722 -0
- package/src/plugins/workers/worker.ts +115 -0
- package/src/plugins/workers/workers.integration.test.ts +778 -0
- package/src/prompts/base.ts +266 -0
- package/src/prompts/builder.ts +194 -0
- package/src/prompts/index.ts +36 -0
- package/src/prompts/macros.test.ts +107 -0
- package/src/prompts/macros.ts +27 -0
- package/src/testing/bootstrap-for-testing.ts +39 -0
- package/src/testing/index.ts +7 -0
- package/src/testing/node-platform.ts +80 -0
- package/src/testing/notification-collector.ts +100 -0
- package/src/testing/preset-helpers.ts +57 -0
- package/src/testing/test-harness.test.ts +63 -0
- package/src/testing/test-harness.ts +279 -0
- package/src/testing/wait-helpers.ts +84 -0
- package/src/transport/adapter/client-adapter.ts +81 -0
- package/src/transport/adapter/index.ts +42 -0
- package/src/transport/adapter/server-adapter.ts +93 -0
- package/src/transport/adapter/types.ts +20 -0
- package/src/transport/http/app.ts +129 -0
- package/src/transport/http/index.ts +7 -0
- package/src/transport/http/middleware/bearer-auth.ts +40 -0
- package/src/transport/http/middleware/error-handler.ts +76 -0
- package/src/transport/http/routes/files.ts +274 -0
- package/src/transport/http/routes/resources.ts +115 -0
- package/src/transport/http/routes/rpc.integration.test.ts +243 -0
- package/src/transport/http/routes/rpc.test.ts +372 -0
- package/src/transport/http/routes/rpc.ts +156 -0
- package/src/transport/http/routes/upload.ts +286 -0
- package/src/transport/rpc/index.ts +11 -0
- package/src/transport/rpc/methods.ts +38 -0
- package/src/user-config.ts +33 -0
|
@@ -0,0 +1,1472 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent - OOP wrapper for agent orchestration.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Process mailbox (inference + tool execution loop)
|
|
6
|
+
* - Embedded scheduling with debounce
|
|
7
|
+
* - Spawn child agents
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import z from 'zod/v4'
|
|
11
|
+
import { DebounceCallback } from '~/core/agents/debounce.js'
|
|
12
|
+
import type { AgentId } from '~/core/agents/schema.js'
|
|
13
|
+
import type { AgentState, HandlerResult } from '~/core/agents/state.js'
|
|
14
|
+
import { agentEvents } from '~/core/agents/state.js'
|
|
15
|
+
import { withSessionId } from '~/core/events/test-helpers.js'
|
|
16
|
+
import type { FileStore } from '~/core/file-store/types.js'
|
|
17
|
+
import { applyCacheBreakpoint } from '~/core/llm/cache-breakpoints.js'
|
|
18
|
+
import type { ToolResultContent } from '~/core/llm/llm-log-types.js'
|
|
19
|
+
import type { InferenceRequest, LLMMessage, LLMProvider } from '~/core/llm/provider.js'
|
|
20
|
+
import { LLMCallId, ModelId } from '~/core/llm/schema.js'
|
|
21
|
+
import type { LLMResponse } from '~/core/llm/state.js'
|
|
22
|
+
import { llmEvents } from '~/core/llm/state.js'
|
|
23
|
+
import type {
|
|
24
|
+
AfterInferenceResult,
|
|
25
|
+
AfterToolCallResult,
|
|
26
|
+
BeforeInferenceResult,
|
|
27
|
+
BeforeToolCallResult,
|
|
28
|
+
HandlerName,
|
|
29
|
+
OnCompleteResult,
|
|
30
|
+
OnErrorResult,
|
|
31
|
+
OnStartResult,
|
|
32
|
+
} from '~/core/plugins/hook-types.js'
|
|
33
|
+
import type {
|
|
34
|
+
AgentPluginConfig,
|
|
35
|
+
BasePluginHookContext,
|
|
36
|
+
ConfiguredPlugin,
|
|
37
|
+
PluginMethodCaller,
|
|
38
|
+
PluginNotification,
|
|
39
|
+
} from '~/core/plugins/plugin-builder.js'
|
|
40
|
+
import { buildPluginDeps } from '~/core/plugins/plugin-builder.js'
|
|
41
|
+
import type { ToolContext } from '~/core/tools/context.js'
|
|
42
|
+
import type { ToolDefinition } from '~/core/tools/definition.js'
|
|
43
|
+
import type { ToolCall } from '~/core/tools/schema.js'
|
|
44
|
+
import { ToolCallId } from '~/core/tools/schema.js'
|
|
45
|
+
import { toolEvents } from '~/core/tools/state.js'
|
|
46
|
+
import { getAgentUnconsumedMailbox, selectMailboxState } from '~/plugins/mailbox/query.js'
|
|
47
|
+
import { AGENT_BASE_BRIEFING } from '~/prompts/base.js'
|
|
48
|
+
import { buildEnvironmentSection } from '~/prompts/builder.js'
|
|
49
|
+
import type { Logger } from '../../lib/logger/logger.js'
|
|
50
|
+
import type { SessionContext } from '../sessions/context.js'
|
|
51
|
+
import type { SessionStore } from '../sessions/session-store.js'
|
|
52
|
+
import type { SessionState } from '../sessions/state.js'
|
|
53
|
+
import type { SessionEnvironment, ToolExecutor } from '../tools'
|
|
54
|
+
import type { AgentContext } from './context.js'
|
|
55
|
+
import { sanitizeLLMResponse } from './response-sanitizer.js'
|
|
56
|
+
import { withLLMRetry } from './retry.js'
|
|
57
|
+
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Types
|
|
60
|
+
// ============================================================================
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Agent configuration - includes both behavior and debounce settings.
|
|
64
|
+
*/
|
|
65
|
+
export interface AgentConfig<TInput = unknown> {
|
|
66
|
+
systemPrompt: string
|
|
67
|
+
model: ModelId
|
|
68
|
+
spawnableAgents: string[]
|
|
69
|
+
// ToolDefinition<any> required: ToolDefinition is contravariant in TInput,
|
|
70
|
+
// so ToolDefinition<SpecificInput> is not assignable to ToolDefinition<unknown>
|
|
71
|
+
/** Preset-level static tools (merged with plugin tools at runtime) */
|
|
72
|
+
tools?: ToolDefinition<any>[]
|
|
73
|
+
/** Debounce time in ms before processing agent mailbox. Default: 500ms */
|
|
74
|
+
debounceMs?: number
|
|
75
|
+
/** Optional callback to determine when to process */
|
|
76
|
+
debounceCallback?: DebounceCallback
|
|
77
|
+
/** Interval in ms for checking debounce callback (default: 100) */
|
|
78
|
+
checkIntervalMs?: number
|
|
79
|
+
/** Optional Zod schema for typed agent input validation */
|
|
80
|
+
input?: z.ZodType<TInput>
|
|
81
|
+
/** Per-plugin agent-level configs */
|
|
82
|
+
plugins?: AgentPluginConfig[]
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Dependencies for creating an Agent.
|
|
87
|
+
*/
|
|
88
|
+
export interface AgentDependencies {
|
|
89
|
+
id: AgentId
|
|
90
|
+
sessionContext: SessionContext
|
|
91
|
+
store: SessionStore
|
|
92
|
+
llmProvider: LLMProvider
|
|
93
|
+
/** Named provider instances, passed to InferenceContext for middleware routing */
|
|
94
|
+
llmProviders?: ReadonlyMap<string, LLMProvider>
|
|
95
|
+
toolExecutor: ToolExecutor
|
|
96
|
+
logger: Logger
|
|
97
|
+
config: AgentConfig
|
|
98
|
+
plugins: ConfiguredPlugin[]
|
|
99
|
+
/** Session environment directories for tool context */
|
|
100
|
+
environment: SessionEnvironment
|
|
101
|
+
/** FileStore for resolving agent-visible file:// paths (used by LLM provider) */
|
|
102
|
+
fileStore: FileStore
|
|
103
|
+
/** Plugin contexts created by session-level initPluginContexts(), keyed by plugin name */
|
|
104
|
+
pluginContexts?: ReadonlyMap<string, unknown>
|
|
105
|
+
/** Callback for sending plugin notifications directly to transport */
|
|
106
|
+
sendNotification?: (notification: PluginNotification) => void
|
|
107
|
+
/** Callback for resolving cross-plugin method calls (delegates to session) */
|
|
108
|
+
pluginMethodCaller?: PluginMethodCaller
|
|
109
|
+
/** Callback for scheduling this agent for processing */
|
|
110
|
+
schedule?: () => void
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ============================================================================
|
|
114
|
+
// Agent
|
|
115
|
+
// ============================================================================
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Agent handles mailbox processing, inference, and tool execution.
|
|
119
|
+
*
|
|
120
|
+
* Features:
|
|
121
|
+
* - Debounced processing (timer or callback-based)
|
|
122
|
+
* - LLM inference with retry
|
|
123
|
+
* - Context compaction
|
|
124
|
+
* - Tool execution
|
|
125
|
+
*/
|
|
126
|
+
export class Agent {
|
|
127
|
+
readonly id: AgentId
|
|
128
|
+
private readonly config: AgentConfig
|
|
129
|
+
private readonly sessionContext: SessionContext
|
|
130
|
+
private readonly store: SessionStore
|
|
131
|
+
private readonly logger: Logger
|
|
132
|
+
private readonly llmProvider: LLMProvider
|
|
133
|
+
private readonly llmProviders: ReadonlyMap<string, LLMProvider>
|
|
134
|
+
private readonly toolExecutor: ToolExecutor
|
|
135
|
+
private readonly plugins: ConfiguredPlugin[]
|
|
136
|
+
private readonly environment: SessionEnvironment
|
|
137
|
+
private readonly fileStore: FileStore
|
|
138
|
+
private readonly pluginContexts: ReadonlyMap<string, unknown>
|
|
139
|
+
private readonly sendNotification?: (notification: PluginNotification) => void
|
|
140
|
+
private readonly pluginMethodCaller?: PluginMethodCaller
|
|
141
|
+
private readonly scheduleCallback?: () => void
|
|
142
|
+
|
|
143
|
+
/** Merged tools map: config tools + plugin tools (plugins override). Rebuilt each processing cycle. */
|
|
144
|
+
private tools: Map<string, ToolDefinition>
|
|
145
|
+
|
|
146
|
+
// Scheduler state (embedded)
|
|
147
|
+
private debounceTimer?: ReturnType<typeof setTimeout>
|
|
148
|
+
private processing = false
|
|
149
|
+
private scheduled = false
|
|
150
|
+
private pendingReschedule = false
|
|
151
|
+
private readonly abortController = new AbortController()
|
|
152
|
+
|
|
153
|
+
/** Track conversation turn number for handler context */
|
|
154
|
+
private turnNumber = 0
|
|
155
|
+
|
|
156
|
+
constructor(deps: AgentDependencies) {
|
|
157
|
+
this.id = deps.id
|
|
158
|
+
this.config = deps.config
|
|
159
|
+
this.sessionContext = deps.sessionContext
|
|
160
|
+
this.store = deps.store
|
|
161
|
+
this.logger = deps.logger
|
|
162
|
+
this.llmProvider = deps.llmProvider
|
|
163
|
+
this.llmProviders = deps.llmProviders ?? new Map()
|
|
164
|
+
this.toolExecutor = deps.toolExecutor
|
|
165
|
+
this.plugins = deps.plugins
|
|
166
|
+
this.environment = deps.environment
|
|
167
|
+
this.fileStore = deps.fileStore
|
|
168
|
+
this.pluginContexts = deps.pluginContexts ?? new Map()
|
|
169
|
+
this.sendNotification = deps.sendNotification
|
|
170
|
+
this.pluginMethodCaller = deps.pluginMethodCaller
|
|
171
|
+
this.scheduleCallback = deps.schedule
|
|
172
|
+
this.tools = this.buildToolsMap()
|
|
173
|
+
|
|
174
|
+
// Initialize turn number from conversation history
|
|
175
|
+
const state = this.state
|
|
176
|
+
if (state) {
|
|
177
|
+
this.turnNumber = state.conversationHistory.filter((m) => m.role === 'assistant').length
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get the current agent state from store.
|
|
183
|
+
*/
|
|
184
|
+
get state(): AgentState | null {
|
|
185
|
+
return this.store.getAgentState(this.id)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================================================
|
|
189
|
+
// Public API
|
|
190
|
+
// ============================================================================
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Unified processing entry point - decides what to do next.
|
|
194
|
+
* Safe to call multiple times; skips if already processing.
|
|
195
|
+
*/
|
|
196
|
+
async continue(): Promise<void> {
|
|
197
|
+
if (this.processing) return
|
|
198
|
+
if (this.store.isClosed()) return
|
|
199
|
+
this.processing = true
|
|
200
|
+
this.scheduled = false
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
while (true) {
|
|
204
|
+
const agentState = this.state
|
|
205
|
+
if (!agentState) break
|
|
206
|
+
|
|
207
|
+
// Rebuild tools map each cycle so plugin-dynamic tools reflect current state
|
|
208
|
+
this.tools = this.buildToolsMap()
|
|
209
|
+
|
|
210
|
+
const decision = this.decide(agentState)
|
|
211
|
+
|
|
212
|
+
switch (decision) {
|
|
213
|
+
case 'idle':
|
|
214
|
+
this.logger.debug('Agent has nothing to do', {
|
|
215
|
+
agentId: this.id,
|
|
216
|
+
status: agentState.status,
|
|
217
|
+
})
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
case 'paused':
|
|
221
|
+
this.logger.debug('Agent is paused, skipping processing', { agentId: this.id })
|
|
222
|
+
return
|
|
223
|
+
|
|
224
|
+
case 'on_start':
|
|
225
|
+
await this.executeOnStart(agentState)
|
|
226
|
+
continue
|
|
227
|
+
|
|
228
|
+
case 'tool_exec':
|
|
229
|
+
this.logger.info('Executing pending tool calls', {
|
|
230
|
+
agentId: this.id,
|
|
231
|
+
count: agentState.pendingToolCalls.length,
|
|
232
|
+
})
|
|
233
|
+
for (const toolCall of agentState.pendingToolCalls) {
|
|
234
|
+
await this.executeToolCall(toolCall)
|
|
235
|
+
}
|
|
236
|
+
// Schedule re-entry via debounce after tool execution
|
|
237
|
+
// (allows debounce callback to wait for child responses, etc.)
|
|
238
|
+
this.scheduleProcessing()
|
|
239
|
+
return
|
|
240
|
+
|
|
241
|
+
case 'resume_from_error':
|
|
242
|
+
await this.store.emit(withSessionId(
|
|
243
|
+
this.store.sessionId,
|
|
244
|
+
agentEvents.create('agent_resumed', { agentId: this.id }),
|
|
245
|
+
))
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
case 'infer':
|
|
249
|
+
await this.runInference(agentState)
|
|
250
|
+
continue
|
|
251
|
+
|
|
252
|
+
case 'complete':
|
|
253
|
+
await this.executeOnComplete(agentState)
|
|
254
|
+
return
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
} catch (err) {
|
|
258
|
+
if (this.abortController.signal.aborted) {
|
|
259
|
+
this.logger.debug('Agent processing aborted', { agentId: this.id })
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
this.logger.error('Unexpected error in agent processing', err instanceof Error ? err : new Error(String(err)), {
|
|
263
|
+
agentId: this.id,
|
|
264
|
+
sessionId: this.store.sessionId,
|
|
265
|
+
})
|
|
266
|
+
} finally {
|
|
267
|
+
this.processing = false
|
|
268
|
+
if (this.pendingReschedule) {
|
|
269
|
+
this.pendingReschedule = false
|
|
270
|
+
this.scheduleProcessing()
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Schedule processing with debounce.
|
|
277
|
+
* Use this when receiving new messages or after tool execution.
|
|
278
|
+
*/
|
|
279
|
+
scheduleProcessing(): void {
|
|
280
|
+
if (this.scheduled) return
|
|
281
|
+
if (this.store.isClosed()) return
|
|
282
|
+
if (this.processing) {
|
|
283
|
+
this.pendingReschedule = true
|
|
284
|
+
return
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
this.cancelSchedule()
|
|
288
|
+
this.scheduled = true
|
|
289
|
+
|
|
290
|
+
const agentState = this.state
|
|
291
|
+
if (!agentState) return
|
|
292
|
+
|
|
293
|
+
if (this.config.debounceCallback) {
|
|
294
|
+
// Callback-based debounce using recursive setTimeout
|
|
295
|
+
const checkInterval = this.config.checkIntervalMs ?? 100
|
|
296
|
+
|
|
297
|
+
const scheduleCheck = () => {
|
|
298
|
+
this.debounceTimer = setTimeout(async () => {
|
|
299
|
+
// Re-read state fresh each check — no stale data
|
|
300
|
+
const currentState = this.state
|
|
301
|
+
if (!currentState) {
|
|
302
|
+
this.cancelSchedule()
|
|
303
|
+
return
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Guard: schedule could be cancelled between timer fire and here
|
|
307
|
+
if (!this.scheduled) return
|
|
308
|
+
|
|
309
|
+
const sessionState = this.store.getState()
|
|
310
|
+
const unconsumed = getUnconsumedMessages(sessionState, this.id)
|
|
311
|
+
const pendingToolResults = currentState.pendingToolResults
|
|
312
|
+
|
|
313
|
+
// If no messages, no pending tool results, and no plugin pending, nothing to do
|
|
314
|
+
if (unconsumed.length === 0 && pendingToolResults.length === 0 && !this.hasPluginPendingMessages()) {
|
|
315
|
+
this.cancelSchedule()
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const oldestTimestamp = unconsumed.length > 0
|
|
320
|
+
? Math.min(...unconsumed.map((m) => m.timestamp))
|
|
321
|
+
: Date.now()
|
|
322
|
+
const oldestWaitingMs = Date.now() - oldestTimestamp
|
|
323
|
+
|
|
324
|
+
const decision = await this.config.debounceCallback!({
|
|
325
|
+
messages: unconsumed,
|
|
326
|
+
oldestWaitingMs,
|
|
327
|
+
totalPending: unconsumed.length,
|
|
328
|
+
pendingToolResults,
|
|
329
|
+
})
|
|
330
|
+
|
|
331
|
+
// Re-check after async callback — schedule could be cancelled during await
|
|
332
|
+
if (!this.scheduled) return
|
|
333
|
+
|
|
334
|
+
if (decision === 'process_now') {
|
|
335
|
+
this.cancelSchedule()
|
|
336
|
+
this.continue().catch((err) => {
|
|
337
|
+
this.logger.error('Unhandled error in continue()', err instanceof Error ? err : undefined, { agentId: this.id })
|
|
338
|
+
})
|
|
339
|
+
} else {
|
|
340
|
+
// Callback said "wait" — schedule next check.
|
|
341
|
+
// Fresh state will be read on next iteration.
|
|
342
|
+
scheduleCheck()
|
|
343
|
+
}
|
|
344
|
+
}, checkInterval)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
scheduleCheck()
|
|
348
|
+
} else {
|
|
349
|
+
// Timer-based debounce (default: 500ms)
|
|
350
|
+
const debounceMs = this.config.debounceMs ?? 500
|
|
351
|
+
this.debounceTimer = setTimeout(() => {
|
|
352
|
+
this.scheduled = false
|
|
353
|
+
this.debounceTimer = undefined
|
|
354
|
+
this.continue().catch((err) => {
|
|
355
|
+
this.logger.error('Unhandled error in continue()', err instanceof Error ? err : undefined, { agentId: this.id })
|
|
356
|
+
})
|
|
357
|
+
}, debounceMs)
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Shutdown the agent - cancel any scheduled processing.
|
|
363
|
+
*/
|
|
364
|
+
shutdown(): void {
|
|
365
|
+
try {
|
|
366
|
+
this.abortController.abort()
|
|
367
|
+
} catch {
|
|
368
|
+
// AbortError may be thrown synchronously by abort signal listeners
|
|
369
|
+
}
|
|
370
|
+
this.cancelSchedule()
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Check if processing is scheduled.
|
|
375
|
+
*/
|
|
376
|
+
isScheduled(): boolean {
|
|
377
|
+
return this.scheduled
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// ============================================================================
|
|
381
|
+
// Private methods - Processing
|
|
382
|
+
// ============================================================================
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Determine the next action based on current agent state.
|
|
386
|
+
*/
|
|
387
|
+
private decide(state: AgentState): 'idle' | 'paused' | 'on_start' | 'tool_exec' | 'infer' | 'resume_from_error' | 'complete' {
|
|
388
|
+
if (state.status === 'paused') return 'paused'
|
|
389
|
+
if (!state.onStartCalled) return 'on_start'
|
|
390
|
+
if (state.status === 'tool_exec' && state.pendingToolCalls.length > 0) return 'tool_exec'
|
|
391
|
+
if (state.status === 'pending') {
|
|
392
|
+
if (hasWork(state) || this.hasPluginPendingMessages()) return 'infer'
|
|
393
|
+
return 'complete'
|
|
394
|
+
}
|
|
395
|
+
if (state.status === 'errored') {
|
|
396
|
+
// Errored with new messages (e.g. user sent a message): emit resume event, then retry
|
|
397
|
+
// Only check for new messages, not stale pendingToolResults — those were present when inference failed
|
|
398
|
+
if (this.hasPluginPendingMessages()) return 'resume_from_error'
|
|
399
|
+
return 'complete'
|
|
400
|
+
}
|
|
401
|
+
return 'idle'
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
private static readonly MAX_INFERENCE_RETRIES = 3
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Run inference on agent's mailbox.
|
|
408
|
+
* Runs when there are unconsumed messages OR pending tool results.
|
|
409
|
+
*/
|
|
410
|
+
private async runInference(initialAgentState: AgentState, retryCount = 0): Promise<void> {
|
|
411
|
+
let agentState = initialAgentState
|
|
412
|
+
const hasToolResults = agentState.pendingToolResults.length > 0
|
|
413
|
+
|
|
414
|
+
// Collect plugin dequeue messages (includes mailbox messages)
|
|
415
|
+
const pluginDequeued = this.collectPluginMessages()
|
|
416
|
+
|
|
417
|
+
// Need either tool results or plugin messages to process
|
|
418
|
+
if (!hasToolResults && pluginDequeued.length === 0) return
|
|
419
|
+
|
|
420
|
+
this.turnNumber++
|
|
421
|
+
|
|
422
|
+
// 0. beforeInference handler - can skip LLM entirely or pause
|
|
423
|
+
const beforeResult = await this.executeBeforeInference(agentState)
|
|
424
|
+
if (beforeResult !== null) {
|
|
425
|
+
if (beforeResult.action === 'skip') {
|
|
426
|
+
// Skip LLM, use provided response directly
|
|
427
|
+
await this.emitInferenceCompleted(beforeResult.response, undefined)
|
|
428
|
+
return
|
|
429
|
+
}
|
|
430
|
+
if (beforeResult.action === 'pause') {
|
|
431
|
+
return
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 1. Context compaction is now handled by the context-compact plugin's beforeInference hook
|
|
436
|
+
// (which runs above). If compaction occurred, agent state was updated via context_compacted event.
|
|
437
|
+
// Re-read agent state to pick up any compacted history.
|
|
438
|
+
const postHookState = this.state
|
|
439
|
+
if (postHookState) {
|
|
440
|
+
agentState = postHookState
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 2. Build pending messages (tool results only)
|
|
444
|
+
const pendingMessages = this.buildPendingMessages(agentState)
|
|
445
|
+
|
|
446
|
+
// 2b. Append plugin dequeued messages (includes mailbox messages)
|
|
447
|
+
for (const dequeued of pluginDequeued) {
|
|
448
|
+
pendingMessages.push(...dequeued.messages)
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// 3. Inference start - emit with pending messages
|
|
452
|
+
await this.store.emit(withSessionId(
|
|
453
|
+
this.store.sessionId,
|
|
454
|
+
llmEvents.create('inference_started', {
|
|
455
|
+
agentId: this.id,
|
|
456
|
+
messages: pendingMessages,
|
|
457
|
+
consumedMessageIds: [],
|
|
458
|
+
}),
|
|
459
|
+
))
|
|
460
|
+
|
|
461
|
+
// 4. Build LLM messages — re-read state to include inference_started changes
|
|
462
|
+
const preInferenceState = this.state
|
|
463
|
+
if (preInferenceState) {
|
|
464
|
+
agentState = preInferenceState
|
|
465
|
+
}
|
|
466
|
+
const messages = this.buildLLMMessages(agentState, pendingMessages)
|
|
467
|
+
|
|
468
|
+
// 4b. Append ephemeral context (not stored in history, recreated each inference)
|
|
469
|
+
const ephemeralParts: string[] = []
|
|
470
|
+
|
|
471
|
+
// Collect status messages from all plugins
|
|
472
|
+
const pluginStatus = this.getPluginStatus()
|
|
473
|
+
if (pluginStatus) ephemeralParts.push(pluginStatus)
|
|
474
|
+
|
|
475
|
+
if (ephemeralParts.length > 0) {
|
|
476
|
+
messages.push({
|
|
477
|
+
role: 'user',
|
|
478
|
+
content: `<session-context>\n${ephemeralParts.join('\n\n')}\n</session-context>`,
|
|
479
|
+
})
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Mark cache breakpoint — ephemeral session-context suffix is excluded
|
|
483
|
+
// so it doesn't invalidate the cache on every inference.
|
|
484
|
+
const cachedMessages = applyCacheBreakpoint(messages, ephemeralParts.length > 0 ? 1 : 0)
|
|
485
|
+
|
|
486
|
+
// 5. LLM inference (with retry)
|
|
487
|
+
const request: InferenceRequest = {
|
|
488
|
+
model: this.config.model,
|
|
489
|
+
systemPrompt: this.buildSystemPrompt(),
|
|
490
|
+
messages: cachedMessages,
|
|
491
|
+
tools: this.tools.size > 0 ? [...this.tools.values()] : undefined,
|
|
492
|
+
// Stop sequences to prevent hallucination of message tags
|
|
493
|
+
stopSequences: ['<message'],
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
this.logger.debug('Running inference', {
|
|
497
|
+
sessionId: this.store.sessionId,
|
|
498
|
+
agentId: this.id,
|
|
499
|
+
messageCount: messages.length,
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
// Capture llmCallId from the logging provider
|
|
503
|
+
let llmCallId: LLMCallId | undefined
|
|
504
|
+
|
|
505
|
+
const llmResponse = await withLLMRetry(
|
|
506
|
+
() =>
|
|
507
|
+
this.llmProvider.inference(request, {
|
|
508
|
+
sessionId: this.store.sessionId,
|
|
509
|
+
agentId: this.id,
|
|
510
|
+
onLLMCallCreated: (callId) => {
|
|
511
|
+
llmCallId = LLMCallId(callId)
|
|
512
|
+
},
|
|
513
|
+
signal: this.abortController.signal,
|
|
514
|
+
fileStore: this.fileStore,
|
|
515
|
+
providers: this.llmProviders,
|
|
516
|
+
}),
|
|
517
|
+
{ logger: this.logger, signal: this.abortController.signal },
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
// Mark plugin messages as consumed (regardless of inference outcome —
|
|
521
|
+
// messages are already appended to conversationHistory via inference_started)
|
|
522
|
+
{
|
|
523
|
+
const currentAgentState = this.state
|
|
524
|
+
if (currentAgentState) {
|
|
525
|
+
const ctx = this.buildAgentContext(currentAgentState)
|
|
526
|
+
for (const dequeued of pluginDequeued) {
|
|
527
|
+
if (!dequeued.plugin.dequeue) continue
|
|
528
|
+
const pluginCtx = this.buildPluginHookContext(dequeued.plugin, ctx)
|
|
529
|
+
await dequeued.plugin.dequeue.markConsumed(pluginCtx, dequeued.token)
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if (!llmResponse.ok) {
|
|
535
|
+
// 4a. Inference failed
|
|
536
|
+
await this.store.emit(withSessionId(
|
|
537
|
+
this.store.sessionId,
|
|
538
|
+
llmEvents.create('inference_failed', {
|
|
539
|
+
agentId: this.id,
|
|
540
|
+
error: llmResponse.error.message,
|
|
541
|
+
llmCallId,
|
|
542
|
+
}),
|
|
543
|
+
))
|
|
544
|
+
// Notify plugins (e.g. mailbox sends error message to parent)
|
|
545
|
+
const errorState = this.state
|
|
546
|
+
if (errorState) {
|
|
547
|
+
await this.executeOnError(errorState, llmResponse.error.message)
|
|
548
|
+
}
|
|
549
|
+
return
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// 4c. Sanitize response to prevent hallucination
|
|
553
|
+
const sanitized = sanitizeLLMResponse(llmResponse.value.content)
|
|
554
|
+
|
|
555
|
+
if (sanitized.wasTruncated) {
|
|
556
|
+
this.logger.warn('LLM response was truncated (potential hallucination)', {
|
|
557
|
+
agentId: this.id,
|
|
558
|
+
sessionId: this.store.sessionId,
|
|
559
|
+
})
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Build response object
|
|
563
|
+
let response: LLMResponse = {
|
|
564
|
+
content: sanitized.content,
|
|
565
|
+
toolCalls: llmResponse.value.toolCalls.map((tc) => ({
|
|
566
|
+
id: tc.id,
|
|
567
|
+
name: tc.name,
|
|
568
|
+
input: tc.input,
|
|
569
|
+
})),
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// 4c. afterInference handler - can modify response, request retry, or pause
|
|
573
|
+
// Re-read state: inference events have been processed since last read
|
|
574
|
+
const postInferenceState = this.state
|
|
575
|
+
if (postInferenceState) {
|
|
576
|
+
agentState = postInferenceState
|
|
577
|
+
}
|
|
578
|
+
const afterResult = await this.executeAfterInference(agentState, response)
|
|
579
|
+
if (afterResult !== null) {
|
|
580
|
+
if (afterResult.action === 'pause') {
|
|
581
|
+
// Inference completed and messages were consumed — commit the turn
|
|
582
|
+
// before pausing so pendingMessages move to conversationHistory.
|
|
583
|
+
await this.emitInferenceCompleted(response, llmCallId, llmResponse.value.metrics)
|
|
584
|
+
await this.emitHandlerPause(afterResult.reason)
|
|
585
|
+
return
|
|
586
|
+
}
|
|
587
|
+
if (afterResult.action === 'retry') {
|
|
588
|
+
if (retryCount >= Agent.MAX_INFERENCE_RETRIES) {
|
|
589
|
+
this.logger.warn('afterInference retry limit reached, continuing with current response', {
|
|
590
|
+
agentId: this.id,
|
|
591
|
+
retryCount,
|
|
592
|
+
})
|
|
593
|
+
} else {
|
|
594
|
+
// Retry inference - decrement turn number and recursively call with fresh state
|
|
595
|
+
this.turnNumber--
|
|
596
|
+
const freshState = this.state
|
|
597
|
+
if (!freshState) return
|
|
598
|
+
await this.runInference(freshState, retryCount + 1)
|
|
599
|
+
return
|
|
600
|
+
}
|
|
601
|
+
} else if (afterResult.action === 'modify') {
|
|
602
|
+
response = afterResult.response
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// 4d. Inference completed
|
|
607
|
+
// Tool calls will be executed in the next continue() cycle
|
|
608
|
+
await this.emitInferenceCompleted(response, llmCallId, llmResponse.value.metrics)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/**
|
|
612
|
+
* Emit inference_completed event.
|
|
613
|
+
*/
|
|
614
|
+
private async emitInferenceCompleted(
|
|
615
|
+
response: LLMResponse,
|
|
616
|
+
llmCallId: LLMCallId | undefined,
|
|
617
|
+
metrics?: {
|
|
618
|
+
promptTokens: number
|
|
619
|
+
completionTokens: number
|
|
620
|
+
totalTokens: number
|
|
621
|
+
latencyMs: number
|
|
622
|
+
model: string
|
|
623
|
+
provider?: string
|
|
624
|
+
cost?: number
|
|
625
|
+
cachedTokens?: number
|
|
626
|
+
cacheWriteTokens?: number
|
|
627
|
+
},
|
|
628
|
+
): Promise<void> {
|
|
629
|
+
await this.store.emit(withSessionId(
|
|
630
|
+
this.store.sessionId,
|
|
631
|
+
llmEvents.create('inference_completed', {
|
|
632
|
+
agentId: this.id,
|
|
633
|
+
consumedMessageIds: [],
|
|
634
|
+
response: {
|
|
635
|
+
content: response.content,
|
|
636
|
+
toolCalls: response.toolCalls.map((tc) => ({
|
|
637
|
+
id: ToolCallId(tc.id),
|
|
638
|
+
name: tc.name,
|
|
639
|
+
input: tc.input,
|
|
640
|
+
})),
|
|
641
|
+
},
|
|
642
|
+
metrics: metrics ?? {
|
|
643
|
+
promptTokens: 0,
|
|
644
|
+
completionTokens: 0,
|
|
645
|
+
totalTokens: 0,
|
|
646
|
+
latencyMs: 0,
|
|
647
|
+
model: 'handler-skip',
|
|
648
|
+
},
|
|
649
|
+
llmCallId,
|
|
650
|
+
}),
|
|
651
|
+
))
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// ============================================================================
|
|
655
|
+
// Private methods - Scheduling
|
|
656
|
+
// ============================================================================
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Cancel any scheduled processing.
|
|
660
|
+
*/
|
|
661
|
+
private cancelSchedule(): void {
|
|
662
|
+
if (this.debounceTimer) {
|
|
663
|
+
clearTimeout(this.debounceTimer)
|
|
664
|
+
this.debounceTimer = undefined
|
|
665
|
+
}
|
|
666
|
+
this.scheduled = false
|
|
667
|
+
this.pendingReschedule = false
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Execute a single tool call.
|
|
672
|
+
*/
|
|
673
|
+
private async executeToolCall(toolCall: ToolCall): Promise<void> {
|
|
674
|
+
const agentState = this.state
|
|
675
|
+
if (!agentState) return
|
|
676
|
+
|
|
677
|
+
// beforeToolCall handler - can block, replace, or pause the tool call
|
|
678
|
+
let effectiveToolCall = toolCall
|
|
679
|
+
const beforeResult = await this.executeBeforeToolCall(agentState, toolCall)
|
|
680
|
+
if (beforeResult !== null) {
|
|
681
|
+
if (beforeResult.action === 'pause') {
|
|
682
|
+
return
|
|
683
|
+
}
|
|
684
|
+
if (beforeResult.action === 'block') {
|
|
685
|
+
// Emit tool_failed with the block reason
|
|
686
|
+
await this.store.emit(withSessionId(
|
|
687
|
+
this.store.sessionId,
|
|
688
|
+
toolEvents.create('tool_started', {
|
|
689
|
+
agentId: this.id,
|
|
690
|
+
toolCallId: toolCall.id,
|
|
691
|
+
toolName: toolCall.name,
|
|
692
|
+
input: toInputRecord(toolCall.input),
|
|
693
|
+
}),
|
|
694
|
+
))
|
|
695
|
+
await this.store.emit(withSessionId(
|
|
696
|
+
this.store.sessionId,
|
|
697
|
+
toolEvents.create('tool_failed', {
|
|
698
|
+
agentId: this.id,
|
|
699
|
+
toolCallId: toolCall.id,
|
|
700
|
+
error: `Tool blocked by handler: ${beforeResult.reason}`,
|
|
701
|
+
}),
|
|
702
|
+
))
|
|
703
|
+
return
|
|
704
|
+
} else if (beforeResult.action === 'replace') {
|
|
705
|
+
effectiveToolCall = {
|
|
706
|
+
id: ToolCallId(beforeResult.toolCall.id),
|
|
707
|
+
name: beforeResult.toolCall.name,
|
|
708
|
+
input: beforeResult.toolCall.input,
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Start event
|
|
714
|
+
await this.store.emit(withSessionId(
|
|
715
|
+
this.store.sessionId,
|
|
716
|
+
toolEvents.create('tool_started', {
|
|
717
|
+
agentId: this.id,
|
|
718
|
+
toolCallId: effectiveToolCall.id,
|
|
719
|
+
toolName: effectiveToolCall.name,
|
|
720
|
+
input: toInputRecord(effectiveToolCall.input),
|
|
721
|
+
}),
|
|
722
|
+
))
|
|
723
|
+
|
|
724
|
+
const tool = this.tools.get(effectiveToolCall.name)
|
|
725
|
+
if (!tool) {
|
|
726
|
+
await this.store.emit(withSessionId(
|
|
727
|
+
this.store.sessionId,
|
|
728
|
+
toolEvents.create('tool_failed', {
|
|
729
|
+
agentId: this.id,
|
|
730
|
+
toolCallId: effectiveToolCall.id,
|
|
731
|
+
error: `Unknown tool: ${effectiveToolCall.name}`,
|
|
732
|
+
}),
|
|
733
|
+
))
|
|
734
|
+
return
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
const context: ToolContext = {
|
|
738
|
+
...this.buildAgentContext(agentState),
|
|
739
|
+
logger: this.logger.child({ toolName: toolCall.name }),
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
const result = await this.toolExecutor.execute(tool, effectiveToolCall.input, context)
|
|
743
|
+
|
|
744
|
+
// Build initial tool result with ToolResultContent
|
|
745
|
+
let toolResult: { isError: boolean; content: ToolResultContent } = result.ok
|
|
746
|
+
? { isError: false, content: result.value }
|
|
747
|
+
: { isError: true, content: result.error.message }
|
|
748
|
+
|
|
749
|
+
// afterToolCall handler - can modify result or pause
|
|
750
|
+
const currentAgentState = this.state
|
|
751
|
+
if (currentAgentState) {
|
|
752
|
+
const afterResult = await this.executeAfterToolCall(currentAgentState, effectiveToolCall, toolResult)
|
|
753
|
+
if (afterResult !== null) {
|
|
754
|
+
if (afterResult.action === 'pause') {
|
|
755
|
+
return
|
|
756
|
+
}
|
|
757
|
+
if (afterResult.action === 'modify') {
|
|
758
|
+
toolResult = afterResult.result
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Result event
|
|
764
|
+
if (!toolResult.isError) {
|
|
765
|
+
await this.store.emit(withSessionId(
|
|
766
|
+
this.store.sessionId,
|
|
767
|
+
toolEvents.create('tool_completed', {
|
|
768
|
+
agentId: this.id,
|
|
769
|
+
toolCallId: effectiveToolCall.id,
|
|
770
|
+
result: toolResult.content,
|
|
771
|
+
}),
|
|
772
|
+
))
|
|
773
|
+
} else {
|
|
774
|
+
// Convert content to string for tool_failed error field
|
|
775
|
+
const errorMessage = typeof toolResult.content === 'string'
|
|
776
|
+
? toolResult.content
|
|
777
|
+
: JSON.stringify(toolResult.content)
|
|
778
|
+
await this.store.emit(withSessionId(
|
|
779
|
+
this.store.sessionId,
|
|
780
|
+
toolEvents.create('tool_failed', {
|
|
781
|
+
agentId: this.id,
|
|
782
|
+
toolCallId: effectiveToolCall.id,
|
|
783
|
+
error: errorMessage,
|
|
784
|
+
}),
|
|
785
|
+
))
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
// ============================================================================
|
|
790
|
+
// Handler execution methods
|
|
791
|
+
// ============================================================================
|
|
792
|
+
|
|
793
|
+
/**
|
|
794
|
+
* Emit agent_paused event with reason 'handler'.
|
|
795
|
+
*/
|
|
796
|
+
private async emitHandlerPause(message?: string): Promise<void> {
|
|
797
|
+
await this.store.emit(withSessionId(
|
|
798
|
+
this.store.sessionId,
|
|
799
|
+
agentEvents.create('agent_paused', {
|
|
800
|
+
agentId: this.id,
|
|
801
|
+
reason: 'handler',
|
|
802
|
+
message,
|
|
803
|
+
}),
|
|
804
|
+
))
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Build base AgentContext for handler/hook calls.
|
|
809
|
+
*/
|
|
810
|
+
private buildAgentContext(agentState: AgentState): AgentContext {
|
|
811
|
+
return {
|
|
812
|
+
// SessionContext fields (refreshed from store for up-to-date state)
|
|
813
|
+
sessionId: this.sessionContext.sessionId,
|
|
814
|
+
sessionState: this.store.getState(),
|
|
815
|
+
sessionInput: this.sessionContext.sessionInput,
|
|
816
|
+
environment: this.sessionContext.environment,
|
|
817
|
+
llm: this.sessionContext.llm,
|
|
818
|
+
files: this.sessionContext.files,
|
|
819
|
+
eventStore: this.sessionContext.eventStore,
|
|
820
|
+
llmLogger: this.sessionContext.llmLogger,
|
|
821
|
+
platform: this.sessionContext.platform,
|
|
822
|
+
logger: this.logger,
|
|
823
|
+
emitEvent: this.sessionContext.emitEvent,
|
|
824
|
+
notify: this.sessionContext.notify,
|
|
825
|
+
// AgentContext fields
|
|
826
|
+
agentId: this.id,
|
|
827
|
+
agentState,
|
|
828
|
+
agentConfig: this.config,
|
|
829
|
+
input: agentState.typedInput,
|
|
830
|
+
parentId: agentState.parentId,
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
/**
|
|
835
|
+
* Build PluginHookContext for a specific plugin.
|
|
836
|
+
* Adds pluginConfig, pluginAgentConfig, pluginContext, pluginState, self.
|
|
837
|
+
*/
|
|
838
|
+
private buildPluginHookContext(plugin: ConfiguredPlugin, agentContext: AgentContext): BasePluginHookContext {
|
|
839
|
+
const pluginState = plugin.slice
|
|
840
|
+
? plugin.slice.select(this.store.getState())
|
|
841
|
+
: undefined
|
|
842
|
+
|
|
843
|
+
const self: Record<string, (input: unknown) => Promise<unknown>> = {}
|
|
844
|
+
for (const [methodName] of Object.entries(plugin.methods)) {
|
|
845
|
+
self[methodName] = async (input: unknown) => {
|
|
846
|
+
if (!this.pluginMethodCaller) {
|
|
847
|
+
throw new Error('pluginMethodCaller not available')
|
|
848
|
+
}
|
|
849
|
+
return this.pluginMethodCaller(plugin.name, methodName, input)
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const sendNotification = this.sendNotification
|
|
854
|
+
const pluginName = plugin.name
|
|
855
|
+
|
|
856
|
+
const deps = this.pluginMethodCaller
|
|
857
|
+
? buildPluginDeps(plugin.dependencyNames, this.plugins, this.pluginMethodCaller)
|
|
858
|
+
: {}
|
|
859
|
+
|
|
860
|
+
const schedule = this.scheduleCallback ?? (() => {})
|
|
861
|
+
|
|
862
|
+
return {
|
|
863
|
+
...agentContext,
|
|
864
|
+
pluginConfig: undefined, // injected by plugin builder wrapper
|
|
865
|
+
pluginAgentConfig: this.config.plugins?.find(c => c.pluginName === plugin.name)?.config,
|
|
866
|
+
pluginContext: this.pluginContexts.get(plugin.name),
|
|
867
|
+
pluginState,
|
|
868
|
+
self,
|
|
869
|
+
schedule,
|
|
870
|
+
notify: (type: string, payload: unknown) => {
|
|
871
|
+
sendNotification?.({ pluginName, type, payload })
|
|
872
|
+
},
|
|
873
|
+
deps,
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
/**
|
|
878
|
+
* Emit handler_completed event.
|
|
879
|
+
*
|
|
880
|
+
* Skipped when the handler produced no action (null result) — those events are
|
|
881
|
+
* pure noise (64%+ of a typical session log). onStart is the one exception: the
|
|
882
|
+
* reducer uses its completion event to flip `onStartCalled`, so we always emit
|
|
883
|
+
* it even with a null result.
|
|
884
|
+
*/
|
|
885
|
+
private async emitHandlerCompleted(handlerName: HandlerName, result: HandlerResult): Promise<void> {
|
|
886
|
+
if (result === null && handlerName !== 'onStart') return
|
|
887
|
+
|
|
888
|
+
await this.store.emit(withSessionId(
|
|
889
|
+
this.store.sessionId,
|
|
890
|
+
agentEvents.create('handler_completed', {
|
|
891
|
+
agentId: this.id,
|
|
892
|
+
handlerName,
|
|
893
|
+
result,
|
|
894
|
+
}),
|
|
895
|
+
))
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Execute onStart handler - called once on first inference.
|
|
900
|
+
*/
|
|
901
|
+
private async executeOnStart(agentState: AgentState): Promise<OnStartResult> {
|
|
902
|
+
this.logger.debug('Executing onStart handlers', { agentId: this.id })
|
|
903
|
+
|
|
904
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
905
|
+
|
|
906
|
+
// Run all plugin handlers with per-plugin isolation
|
|
907
|
+
// Note: Handlers emit preamble_added events directly via ctx.emitEvent()
|
|
908
|
+
let pauseResult: OnStartResult = null
|
|
909
|
+
|
|
910
|
+
for (const plugin of this.plugins) {
|
|
911
|
+
if (!plugin.agentHooks?.onStart) continue
|
|
912
|
+
try {
|
|
913
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
914
|
+
const result = await plugin.agentHooks.onStart(ctx)
|
|
915
|
+
|
|
916
|
+
if (result !== null && result.action === 'pause') {
|
|
917
|
+
// Record first pause, but continue running other handlers
|
|
918
|
+
if (pauseResult === null) {
|
|
919
|
+
pauseResult = result
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
} catch (error) {
|
|
923
|
+
this.logger.error(`Plugin '${plugin.name}' onStart hook failed`, error instanceof Error ? error : undefined, {
|
|
924
|
+
agentId: this.id,
|
|
925
|
+
plugin: plugin.name,
|
|
926
|
+
})
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
await this.emitHandlerCompleted('onStart', pauseResult)
|
|
931
|
+
|
|
932
|
+
if (pauseResult !== null) {
|
|
933
|
+
await this.emitHandlerPause(pauseResult.reason)
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
return pauseResult
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Execute beforeInference handler.
|
|
941
|
+
*/
|
|
942
|
+
private async executeBeforeInference(
|
|
943
|
+
agentState: AgentState,
|
|
944
|
+
): Promise<BeforeInferenceResult> {
|
|
945
|
+
this.logger.debug('Executing beforeInference handlers', {
|
|
946
|
+
agentId: this.id,
|
|
947
|
+
turnNumber: this.turnNumber,
|
|
948
|
+
})
|
|
949
|
+
|
|
950
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
951
|
+
|
|
952
|
+
// Run plugin handlers with per-plugin isolation - first skip/pause wins
|
|
953
|
+
for (const plugin of this.plugins) {
|
|
954
|
+
if (!plugin.agentHooks?.beforeInference) continue
|
|
955
|
+
try {
|
|
956
|
+
const ctx = {
|
|
957
|
+
...this.buildPluginHookContext(plugin, agentContext),
|
|
958
|
+
pendingMessages: getUnconsumedMessages(this.store.getState(), this.id),
|
|
959
|
+
turnNumber: this.turnNumber,
|
|
960
|
+
}
|
|
961
|
+
const result = await plugin.agentHooks.beforeInference(ctx)
|
|
962
|
+
if (result === null) {
|
|
963
|
+
continue
|
|
964
|
+
}
|
|
965
|
+
switch (result.action) {
|
|
966
|
+
case 'skip':
|
|
967
|
+
await this.emitHandlerCompleted('beforeInference', result)
|
|
968
|
+
return result
|
|
969
|
+
case 'pause':
|
|
970
|
+
await this.emitHandlerCompleted('beforeInference', result)
|
|
971
|
+
await this.emitHandlerPause(result.reason)
|
|
972
|
+
return result
|
|
973
|
+
default:
|
|
974
|
+
throw new Error(`Unhandled beforeInference action: ${(result as { action: string }).action}`)
|
|
975
|
+
}
|
|
976
|
+
} catch (error) {
|
|
977
|
+
this.logger.error(`Plugin '${plugin.name}' beforeInference hook failed`, error instanceof Error ? error : undefined, {
|
|
978
|
+
agentId: this.id,
|
|
979
|
+
plugin: plugin.name,
|
|
980
|
+
})
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
await this.emitHandlerCompleted('beforeInference', null)
|
|
985
|
+
return null
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
/**
|
|
989
|
+
* Execute afterInference handler.
|
|
990
|
+
*/
|
|
991
|
+
private async executeAfterInference(
|
|
992
|
+
agentState: AgentState,
|
|
993
|
+
response: LLMResponse,
|
|
994
|
+
): Promise<AfterInferenceResult> {
|
|
995
|
+
this.logger.debug('Executing afterInference handlers', {
|
|
996
|
+
agentId: this.id,
|
|
997
|
+
turnNumber: this.turnNumber,
|
|
998
|
+
})
|
|
999
|
+
|
|
1000
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1001
|
+
|
|
1002
|
+
// Run plugin handlers with per-plugin isolation - first retry/modify/pause wins
|
|
1003
|
+
for (const plugin of this.plugins) {
|
|
1004
|
+
if (!plugin.agentHooks?.afterInference) continue
|
|
1005
|
+
try {
|
|
1006
|
+
const ctx = {
|
|
1007
|
+
...this.buildPluginHookContext(plugin, agentContext),
|
|
1008
|
+
response,
|
|
1009
|
+
turnNumber: this.turnNumber,
|
|
1010
|
+
}
|
|
1011
|
+
const result = await plugin.agentHooks.afterInference(ctx)
|
|
1012
|
+
if (result === null) {
|
|
1013
|
+
continue
|
|
1014
|
+
}
|
|
1015
|
+
switch (result.action) {
|
|
1016
|
+
case 'retry':
|
|
1017
|
+
await this.emitHandlerCompleted('afterInference', result)
|
|
1018
|
+
return result
|
|
1019
|
+
case 'modify':
|
|
1020
|
+
await this.emitHandlerCompleted('afterInference', result)
|
|
1021
|
+
return result
|
|
1022
|
+
case 'pause':
|
|
1023
|
+
await this.emitHandlerCompleted('afterInference', result)
|
|
1024
|
+
// Don't emit agent_paused here — caller commits inference first,
|
|
1025
|
+
// then pauses (so conversationHistory includes the completed turn).
|
|
1026
|
+
return result
|
|
1027
|
+
default:
|
|
1028
|
+
throw new Error(`Unhandled afterInference action: ${(result as { action: string }).action}`)
|
|
1029
|
+
}
|
|
1030
|
+
} catch (error) {
|
|
1031
|
+
this.logger.error(`Plugin '${plugin.name}' afterInference hook failed`, error instanceof Error ? error : undefined, {
|
|
1032
|
+
agentId: this.id,
|
|
1033
|
+
plugin: plugin.name,
|
|
1034
|
+
})
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
await this.emitHandlerCompleted('afterInference', null)
|
|
1039
|
+
return null
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Execute beforeToolCall handler.
|
|
1044
|
+
*/
|
|
1045
|
+
private async executeBeforeToolCall(
|
|
1046
|
+
agentState: AgentState,
|
|
1047
|
+
toolCall: ToolCall,
|
|
1048
|
+
): Promise<BeforeToolCallResult | { action: 'replace'; toolCall: ToolCall }> {
|
|
1049
|
+
this.logger.debug('Executing beforeToolCall handlers', {
|
|
1050
|
+
agentId: this.id,
|
|
1051
|
+
toolName: toolCall.name,
|
|
1052
|
+
})
|
|
1053
|
+
|
|
1054
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1055
|
+
|
|
1056
|
+
// Run plugin handlers with per-plugin isolation - first block/replace/pause wins
|
|
1057
|
+
for (const plugin of this.plugins) {
|
|
1058
|
+
if (!plugin.agentHooks?.beforeToolCall) continue
|
|
1059
|
+
try {
|
|
1060
|
+
const ctx = {
|
|
1061
|
+
...this.buildPluginHookContext(plugin, agentContext),
|
|
1062
|
+
toolCall: {
|
|
1063
|
+
id: toolCall.id,
|
|
1064
|
+
name: toolCall.name,
|
|
1065
|
+
input: toolCall.input,
|
|
1066
|
+
},
|
|
1067
|
+
}
|
|
1068
|
+
const result = await plugin.agentHooks.beforeToolCall(ctx)
|
|
1069
|
+
if (result === null) {
|
|
1070
|
+
continue
|
|
1071
|
+
}
|
|
1072
|
+
switch (result.action) {
|
|
1073
|
+
case 'block':
|
|
1074
|
+
await this.emitHandlerCompleted('beforeToolCall', result)
|
|
1075
|
+
return result
|
|
1076
|
+
case 'replace':
|
|
1077
|
+
await this.emitHandlerCompleted('beforeToolCall', result)
|
|
1078
|
+
return {
|
|
1079
|
+
action: 'replace',
|
|
1080
|
+
toolCall: {
|
|
1081
|
+
id: result.toolCall.id,
|
|
1082
|
+
name: result.toolCall.name,
|
|
1083
|
+
input: result.toolCall.input,
|
|
1084
|
+
},
|
|
1085
|
+
}
|
|
1086
|
+
case 'pause':
|
|
1087
|
+
await this.emitHandlerCompleted('beforeToolCall', result)
|
|
1088
|
+
await this.emitHandlerPause(result.reason)
|
|
1089
|
+
return result
|
|
1090
|
+
default:
|
|
1091
|
+
throw new Error(`Unhandled beforeToolCall action: ${(result as { action: string }).action}`)
|
|
1092
|
+
}
|
|
1093
|
+
} catch (error) {
|
|
1094
|
+
this.logger.error(`Plugin '${plugin.name}' beforeToolCall hook failed`, error instanceof Error ? error : undefined, {
|
|
1095
|
+
agentId: this.id,
|
|
1096
|
+
plugin: plugin.name,
|
|
1097
|
+
toolName: toolCall.name,
|
|
1098
|
+
})
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
await this.emitHandlerCompleted('beforeToolCall', null)
|
|
1103
|
+
return null
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* Execute afterToolCall handler.
|
|
1108
|
+
*/
|
|
1109
|
+
private async executeAfterToolCall(
|
|
1110
|
+
agentState: AgentState,
|
|
1111
|
+
toolCall: ToolCall,
|
|
1112
|
+
toolResult: { isError: boolean; content: ToolResultContent },
|
|
1113
|
+
): Promise<AfterToolCallResult> {
|
|
1114
|
+
this.logger.debug('Executing afterToolCall handlers', {
|
|
1115
|
+
agentId: this.id,
|
|
1116
|
+
toolName: toolCall.name,
|
|
1117
|
+
})
|
|
1118
|
+
|
|
1119
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1120
|
+
|
|
1121
|
+
// Run plugin handlers with per-plugin isolation - first modify/pause wins
|
|
1122
|
+
for (const plugin of this.plugins) {
|
|
1123
|
+
if (!plugin.agentHooks?.afterToolCall) continue
|
|
1124
|
+
try {
|
|
1125
|
+
const ctx = {
|
|
1126
|
+
...this.buildPluginHookContext(plugin, agentContext),
|
|
1127
|
+
toolCall: {
|
|
1128
|
+
id: toolCall.id,
|
|
1129
|
+
name: toolCall.name,
|
|
1130
|
+
input: toolCall.input,
|
|
1131
|
+
},
|
|
1132
|
+
result: toolResult,
|
|
1133
|
+
}
|
|
1134
|
+
const result = await plugin.agentHooks.afterToolCall(ctx)
|
|
1135
|
+
if (result === null) {
|
|
1136
|
+
continue
|
|
1137
|
+
}
|
|
1138
|
+
switch (result.action) {
|
|
1139
|
+
case 'modify':
|
|
1140
|
+
await this.emitHandlerCompleted('afterToolCall', result)
|
|
1141
|
+
return result
|
|
1142
|
+
case 'pause':
|
|
1143
|
+
await this.emitHandlerCompleted('afterToolCall', result)
|
|
1144
|
+
await this.emitHandlerPause(result.reason)
|
|
1145
|
+
return result
|
|
1146
|
+
default:
|
|
1147
|
+
throw new Error(`Unhandled afterToolCall action: ${(result as { action: string }).action}`)
|
|
1148
|
+
}
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
this.logger.error(`Plugin '${plugin.name}' afterToolCall hook failed`, error instanceof Error ? error : undefined, {
|
|
1151
|
+
agentId: this.id,
|
|
1152
|
+
plugin: plugin.name,
|
|
1153
|
+
toolName: toolCall.name,
|
|
1154
|
+
})
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
await this.emitHandlerCompleted('afterToolCall', null)
|
|
1159
|
+
return null
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/**
|
|
1163
|
+
* Execute onComplete handler.
|
|
1164
|
+
*/
|
|
1165
|
+
private async executeOnComplete(agentState: AgentState): Promise<void> {
|
|
1166
|
+
this.logger.debug('Executing onComplete handlers', { agentId: this.id })
|
|
1167
|
+
|
|
1168
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1169
|
+
|
|
1170
|
+
// Run all plugin handlers with per-plugin isolation - first pause wins
|
|
1171
|
+
for (const plugin of this.plugins) {
|
|
1172
|
+
if (!plugin.agentHooks?.onComplete) continue
|
|
1173
|
+
try {
|
|
1174
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1175
|
+
const pluginResult = await plugin.agentHooks.onComplete(ctx)
|
|
1176
|
+
if (pluginResult === null) {
|
|
1177
|
+
continue
|
|
1178
|
+
}
|
|
1179
|
+
switch (pluginResult.action) {
|
|
1180
|
+
case 'pause':
|
|
1181
|
+
await this.emitHandlerCompleted('onComplete', pluginResult)
|
|
1182
|
+
await this.emitHandlerPause(pluginResult.reason)
|
|
1183
|
+
return
|
|
1184
|
+
default:
|
|
1185
|
+
throw new Error(`Unhandled onComplete action: ${(pluginResult as { action: string }).action}`)
|
|
1186
|
+
}
|
|
1187
|
+
} catch (error) {
|
|
1188
|
+
this.logger.error(`Plugin '${plugin.name}' onComplete hook failed`, error instanceof Error ? error : undefined, {
|
|
1189
|
+
agentId: this.id,
|
|
1190
|
+
plugin: plugin.name,
|
|
1191
|
+
})
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
await this.emitHandlerCompleted('onComplete', null)
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
/**
|
|
1199
|
+
* Execute onError handler.
|
|
1200
|
+
*/
|
|
1201
|
+
private async executeOnError(agentState: AgentState, error: string): Promise<void> {
|
|
1202
|
+
this.logger.debug('Executing onError handlers', { agentId: this.id })
|
|
1203
|
+
|
|
1204
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1205
|
+
|
|
1206
|
+
// Run all plugin handlers with per-plugin isolation - first pause wins
|
|
1207
|
+
for (const plugin of this.plugins) {
|
|
1208
|
+
if (!plugin.agentHooks?.onError) continue
|
|
1209
|
+
try {
|
|
1210
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1211
|
+
const pluginResult = await plugin.agentHooks.onError({ ...ctx, error })
|
|
1212
|
+
if (pluginResult === null) {
|
|
1213
|
+
continue
|
|
1214
|
+
}
|
|
1215
|
+
switch (pluginResult.action) {
|
|
1216
|
+
case 'pause':
|
|
1217
|
+
await this.emitHandlerCompleted('onError', pluginResult)
|
|
1218
|
+
await this.emitHandlerPause(pluginResult.reason)
|
|
1219
|
+
return
|
|
1220
|
+
default:
|
|
1221
|
+
throw new Error(`Unhandled onError action: ${(pluginResult as { action: string }).action}`)
|
|
1222
|
+
}
|
|
1223
|
+
} catch (error) {
|
|
1224
|
+
this.logger.error(`Plugin '${plugin.name}' onError hook failed`, error instanceof Error ? error : undefined, {
|
|
1225
|
+
agentId: this.id,
|
|
1226
|
+
plugin: plugin.name,
|
|
1227
|
+
})
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
await this.emitHandlerCompleted('onError', null)
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
// ============================================================================
|
|
1235
|
+
// Message building
|
|
1236
|
+
// ============================================================================
|
|
1237
|
+
|
|
1238
|
+
/**
|
|
1239
|
+
* Build pending messages from tool results.
|
|
1240
|
+
* Mailbox messages are handled by the mailbox plugin's dequeue mechanism.
|
|
1241
|
+
*/
|
|
1242
|
+
private buildPendingMessages(agentState: AgentState): LLMMessage[] {
|
|
1243
|
+
const pending: LLMMessage[] = []
|
|
1244
|
+
|
|
1245
|
+
for (const ptr of agentState.pendingToolResults) {
|
|
1246
|
+
pending.push({
|
|
1247
|
+
role: 'tool',
|
|
1248
|
+
toolCallId: ptr.toolCallId,
|
|
1249
|
+
toolName: ptr.toolName,
|
|
1250
|
+
content: ptr.content,
|
|
1251
|
+
isError: ptr.isError,
|
|
1252
|
+
timestamp: ptr.timestamp,
|
|
1253
|
+
})
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
return pending
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Build LLM messages from agent state and pending messages.
|
|
1261
|
+
* Order: [preamble, conversation history, pending messages]
|
|
1262
|
+
* - Preamble is never compacted (includes skills injected by plugin)
|
|
1263
|
+
* - Conversation history may be compacted
|
|
1264
|
+
* - Pending messages are ephemeral (for current turn)
|
|
1265
|
+
*/
|
|
1266
|
+
private buildLLMMessages(
|
|
1267
|
+
agentState: AgentState,
|
|
1268
|
+
pendingMessages: LLMMessage[],
|
|
1269
|
+
): LLMMessage[] {
|
|
1270
|
+
const messages: LLMMessage[] = []
|
|
1271
|
+
|
|
1272
|
+
// 1. Preamble (ALWAYS prepended, NEVER compacted — includes skills from plugin)
|
|
1273
|
+
messages.push(...agentState.preamble)
|
|
1274
|
+
|
|
1275
|
+
// 2. Conversation history (may be compacted)
|
|
1276
|
+
messages.push(...agentState.conversationHistory)
|
|
1277
|
+
|
|
1278
|
+
// 3. Pending messages
|
|
1279
|
+
messages.push(...pendingMessages)
|
|
1280
|
+
|
|
1281
|
+
return messages
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
// ============================================================================
|
|
1285
|
+
// Plugin system helpers
|
|
1286
|
+
// ============================================================================
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* Build merged tools map from config (preset-level) and plugin tools.
|
|
1290
|
+
* Plugin tools override config tools with the same name.
|
|
1291
|
+
*/
|
|
1292
|
+
private buildToolsMap(): Map<string, ToolDefinition> {
|
|
1293
|
+
const tools = new Map<string, ToolDefinition>()
|
|
1294
|
+
/** Track which source registered each tool name for collision detection */
|
|
1295
|
+
const toolSources = new Map<string, string>()
|
|
1296
|
+
|
|
1297
|
+
// 1. Static tools from config (preset-level)
|
|
1298
|
+
for (const tool of this.config.tools ?? []) {
|
|
1299
|
+
tools.set(tool.name, tool)
|
|
1300
|
+
toolSources.set(tool.name, 'config')
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
// 2. Plugin tools (override static)
|
|
1304
|
+
const agentState = this.state
|
|
1305
|
+
if (agentState) {
|
|
1306
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1307
|
+
for (const plugin of this.plugins) {
|
|
1308
|
+
if (!plugin.getTools) continue
|
|
1309
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1310
|
+
for (const tool of plugin.getTools(ctx)) {
|
|
1311
|
+
const existing = toolSources.get(tool.name)
|
|
1312
|
+
if (existing) {
|
|
1313
|
+
this.logger.warn(`Tool name collision: '${tool.name}' from plugin '${plugin.name}' overrides '${existing}'`, {
|
|
1314
|
+
agentId: this.id,
|
|
1315
|
+
toolName: tool.name,
|
|
1316
|
+
})
|
|
1317
|
+
}
|
|
1318
|
+
tools.set(tool.name, tool)
|
|
1319
|
+
toolSources.set(tool.name, `plugin:${plugin.name}`)
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
return tools
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
/**
|
|
1328
|
+
* Build composed system prompt from base briefing, plugin sections, environment, and preset prompt.
|
|
1329
|
+
*/
|
|
1330
|
+
private buildSystemPrompt(): string {
|
|
1331
|
+
const sections: string[] = []
|
|
1332
|
+
|
|
1333
|
+
// 1. Framework base briefing (always first)
|
|
1334
|
+
sections.push(AGENT_BASE_BRIEFING)
|
|
1335
|
+
|
|
1336
|
+
// 2. Plugin system prompt sections
|
|
1337
|
+
const agentState = this.state
|
|
1338
|
+
if (agentState) {
|
|
1339
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1340
|
+
for (const plugin of this.plugins) {
|
|
1341
|
+
if (!plugin.getSystemPrompt) continue
|
|
1342
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1343
|
+
const section = plugin.getSystemPrompt(ctx)
|
|
1344
|
+
if (section) sections.push(section)
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// 3. Environment section
|
|
1349
|
+
const roots = this.fileStore.getRoots()
|
|
1350
|
+
sections.push(buildEnvironmentSection({
|
|
1351
|
+
sessionPath: roots.session,
|
|
1352
|
+
workspacePath: roots.workspace,
|
|
1353
|
+
}))
|
|
1354
|
+
|
|
1355
|
+
// 4. Custom prompt from preset (last)
|
|
1356
|
+
if (this.config.systemPrompt) {
|
|
1357
|
+
let customPrompt = this.config.systemPrompt
|
|
1358
|
+
customPrompt = customPrompt.replaceAll('{{sessionDir}}', roots.session)
|
|
1359
|
+
if (roots.workspace) {
|
|
1360
|
+
customPrompt = customPrompt.replaceAll('{{workspaceDir}}', roots.workspace)
|
|
1361
|
+
}
|
|
1362
|
+
sections.push(customPrompt)
|
|
1363
|
+
}
|
|
1364
|
+
|
|
1365
|
+
return sections.filter(Boolean).join('\n\n').trim()
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
/**
|
|
1369
|
+
* Get combined status from all plugins.
|
|
1370
|
+
*/
|
|
1371
|
+
private getPluginStatus(): string | null {
|
|
1372
|
+
const agentState = this.state
|
|
1373
|
+
if (!agentState) return null
|
|
1374
|
+
|
|
1375
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1376
|
+
const parts: string[] = []
|
|
1377
|
+
|
|
1378
|
+
for (const plugin of this.plugins) {
|
|
1379
|
+
if (!plugin.getStatus) continue
|
|
1380
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1381
|
+
const status = plugin.getStatus(ctx)
|
|
1382
|
+
if (status) parts.push(status)
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
return parts.length > 0 ? parts.join('\n\n') : null
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
// ============================================================================
|
|
1389
|
+
// Plugin dequeue helpers
|
|
1390
|
+
// ============================================================================
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Check if any plugin has pending messages for this agent.
|
|
1394
|
+
*/
|
|
1395
|
+
private hasPluginPendingMessages(): boolean {
|
|
1396
|
+
const agentState = this.state
|
|
1397
|
+
if (!agentState) return false
|
|
1398
|
+
|
|
1399
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1400
|
+
for (const plugin of this.plugins) {
|
|
1401
|
+
if (!plugin.dequeue) continue
|
|
1402
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1403
|
+
if (plugin.dequeue.hasPendingMessages(ctx)) return true
|
|
1404
|
+
}
|
|
1405
|
+
return false
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
/**
|
|
1409
|
+
* Collect pending messages from all plugins that have dequeue hooks.
|
|
1410
|
+
* Returns array of { plugin, messages, token } for each plugin with pending messages.
|
|
1411
|
+
*/
|
|
1412
|
+
private collectPluginMessages(): Array<{
|
|
1413
|
+
plugin: ConfiguredPlugin
|
|
1414
|
+
messages: LLMMessage[]
|
|
1415
|
+
token: unknown
|
|
1416
|
+
}> {
|
|
1417
|
+
const agentState = this.state
|
|
1418
|
+
if (!agentState) return []
|
|
1419
|
+
|
|
1420
|
+
const agentContext = this.buildAgentContext(agentState)
|
|
1421
|
+
const collected: Array<{
|
|
1422
|
+
plugin: ConfiguredPlugin
|
|
1423
|
+
messages: LLMMessage[]
|
|
1424
|
+
token: unknown
|
|
1425
|
+
}> = []
|
|
1426
|
+
|
|
1427
|
+
for (const plugin of this.plugins) {
|
|
1428
|
+
if (!plugin.dequeue) continue
|
|
1429
|
+
const ctx = this.buildPluginHookContext(plugin, agentContext)
|
|
1430
|
+
const result = plugin.dequeue.getPendingMessages(ctx)
|
|
1431
|
+
if (result) {
|
|
1432
|
+
collected.push({
|
|
1433
|
+
plugin,
|
|
1434
|
+
messages: result.messages,
|
|
1435
|
+
token: result.token,
|
|
1436
|
+
})
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
return collected
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
// ============================================================================
|
|
1445
|
+
// Local helpers (inlined from @roj-ai/core)
|
|
1446
|
+
// ============================================================================
|
|
1447
|
+
|
|
1448
|
+
function getUnconsumedMessages(sessionState: SessionState, agentId: AgentId) {
|
|
1449
|
+
return getAgentUnconsumedMailbox(selectMailboxState(sessionState), agentId)
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
function hasWork(agent: AgentState): boolean {
|
|
1453
|
+
// Has pending tool results - needs LLM to process
|
|
1454
|
+
if (agent.pendingToolResults.length > 0) return true
|
|
1455
|
+
|
|
1456
|
+
return false
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
/**
|
|
1460
|
+
* Narrow tool call input from `unknown` to `Record<string, unknown>`.
|
|
1461
|
+
* Tool inputs are always validated objects from Zod schemas.
|
|
1462
|
+
*/
|
|
1463
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
1464
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
function toInputRecord(input: unknown): Record<string, unknown> {
|
|
1468
|
+
if (isRecord(input)) {
|
|
1469
|
+
return input
|
|
1470
|
+
}
|
|
1471
|
+
return {}
|
|
1472
|
+
}
|