@theokit/sdk 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +187 -0
- package/dist/a2a/agent-mailbox.d.cts +27 -0
- package/dist/a2a/agent-mailbox.d.ts +27 -0
- package/dist/a2a/index.cjs +16850 -0
- package/dist/a2a/index.cjs.map +1 -0
- package/dist/a2a/index.d.cts +9 -0
- package/dist/a2a/index.d.ts +9 -0
- package/dist/a2a/index.js +16844 -0
- package/dist/a2a/index.js.map +1 -0
- package/dist/a2a/message-bus.d.cts +27 -0
- package/dist/a2a/message-bus.d.ts +27 -0
- package/dist/a2a/subagent.d.cts +25 -0
- package/dist/a2a/subagent.d.ts +25 -0
- package/dist/a2a/types.d.cts +12 -0
- package/dist/a2a/types.d.ts +12 -0
- package/dist/agent.d.ts +1 -1
- package/dist/client/index.cjs +73 -0
- package/dist/client/index.cjs.map +1 -0
- package/dist/client/index.d.cts +7 -0
- package/dist/client/index.d.ts +7 -0
- package/dist/client/index.js +71 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/theokit-client.d.cts +18 -0
- package/dist/client/theokit-client.d.ts +18 -0
- package/dist/client/types.d.cts +19 -0
- package/dist/client/types.d.ts +19 -0
- package/dist/{run-DkCD5DeO.d.cts → cron-BnywDYLq.d.cts} +496 -910
- package/dist/{run-DkCD5DeO.d.ts → cron-CtZvJD9J.d.ts} +496 -910
- package/dist/cron.cjs +4285 -2893
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +2 -3
- package/dist/cron.d.ts +2 -71
- package/dist/cron.js +4289 -2897
- package/dist/cron.js.map +1 -1
- package/dist/{errors-CvAeEWgE.d.ts → errors-ChqOmFH1.d.cts} +52 -6
- package/dist/{errors-CK8brCJ1.d.cts → errors-DV9e0rcp.d.ts} +52 -6
- package/dist/errors.cjs +218 -3
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +2 -3
- package/dist/errors.d.ts +50 -4
- package/dist/errors.js +217 -4
- package/dist/errors.js.map +1 -1
- package/dist/eval.cjs +4285 -2893
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.d.cts +35 -0
- package/dist/eval.js +4289 -2897
- package/dist/eval.js.map +1 -1
- package/dist/event-bus.d.ts +23 -0
- package/dist/index.cjs +5132 -4200
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +298 -278
- package/dist/index.d.ts +1898 -24
- package/dist/index.js +6441 -5509
- package/dist/index.js.map +1 -1
- package/dist/internal/agent-loop/loop-context-init.d.ts +2 -0
- package/dist/internal/agent-loop/tool-dispatch.d.ts +22 -1
- package/dist/internal/auth/api-key-validator.d.ts +46 -0
- package/dist/internal/llm/anthropic-shared.d.ts +8 -1
- package/dist/internal/llm/retry.d.ts +22 -0
- package/dist/internal/llm/types.d.ts +47 -1
- package/dist/internal/memory/active-memory-cache.d.ts +3 -3
- package/dist/internal/memory/active-memory-types.d.ts +8 -0
- package/dist/internal/memory/active-memory.d.ts +24 -20
- package/dist/internal/memory/adapters/azure-openai-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/cohere-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/gemini-embedding.d.ts +2 -0
- package/dist/internal/memory/adapters/jina-embedding.d.ts +2 -0
- package/dist/internal/memory/index-manager-contract.d.ts +26 -0
- package/dist/internal/memory/index-manager-dispatch.d.ts +1 -1
- package/dist/internal/memory/index-manager.d.ts +8 -26
- package/dist/internal/memory/{chunk-markdown.d.ts → storage/chunk-markdown.d.ts} +1 -1
- package/dist/internal/memory/{markdown-store.d.ts → storage/markdown-store.d.ts} +1 -1
- package/dist/internal/memory/{reader.d.ts → storage/reader.d.ts} +1 -1
- package/dist/internal/observability/context.d.cts +23 -0
- package/dist/internal/observability/context.d.ts +23 -0
- package/dist/internal/observability/index.cjs +38 -0
- package/dist/internal/observability/index.cjs.map +1 -0
- package/dist/internal/observability/index.d.cts +8 -0
- package/dist/internal/observability/index.d.ts +8 -0
- package/dist/internal/observability/index.js +33 -0
- package/dist/internal/observability/index.js.map +1 -0
- package/dist/internal/observability/tracer-loader.d.cts +20 -0
- package/dist/internal/persistence/conversation-storage-fs.d.cts +37 -0
- package/dist/internal/persistence/conversation-storage-memory.d.cts +24 -0
- package/dist/internal/persistence/credential-pool-store.d.cts +32 -0
- package/dist/internal/persistence/credential-pool-store.d.ts +32 -0
- package/dist/internal/persistence/cwd-mutex.d.cts +1 -0
- package/dist/internal/persistence/exclusive-create.d.cts +22 -0
- package/dist/internal/persistence/exclusive-create.d.ts +22 -0
- package/dist/internal/persistence/file-lock.d.cts +14 -0
- package/dist/internal/persistence/fts5-sanitize.d.cts +16 -0
- package/dist/internal/persistence/index.cjs +359 -0
- package/dist/internal/persistence/index.cjs.map +1 -0
- package/dist/internal/persistence/index.d.cts +20 -0
- package/dist/internal/persistence/index.d.ts +20 -0
- package/dist/internal/persistence/index.js +341 -0
- package/dist/internal/persistence/index.js.map +1 -0
- package/dist/internal/persistence/markdown-config-loader.d.cts +35 -0
- package/dist/internal/persistence/paths.d.cts +19 -0
- package/dist/internal/persistence/persistence-schema.d.cts +21 -0
- package/dist/internal/persistence/persistence-schema.d.ts +4 -0
- package/dist/internal/persistence/schema-version.d.cts +13 -0
- package/dist/internal/persistence/sqlite-cas.d.cts +25 -0
- package/dist/internal/persistence/sqlite-cas.d.ts +25 -0
- package/dist/internal/persistence/sqlite-wal.d.cts +10 -0
- package/dist/internal/plugins/context.d.cts +31 -0
- package/dist/internal/plugins/index.cjs +228 -0
- package/dist/internal/plugins/index.cjs.map +1 -0
- package/dist/internal/plugins/index.d.cts +8 -0
- package/dist/internal/plugins/index.d.ts +8 -0
- package/dist/internal/plugins/index.js +222 -0
- package/dist/internal/plugins/index.js.map +1 -0
- package/dist/internal/plugins/lifecycle.d.cts +14 -0
- package/dist/internal/plugins/lifecycle.d.ts +14 -0
- package/dist/internal/plugins/manager.d.cts +37 -0
- package/dist/internal/plugins/types.d.cts +102 -0
- package/dist/internal/providers/catalog-loader.d.ts +39 -0
- package/dist/internal/runtime/agent-session-store.d.ts +1 -1
- package/dist/internal/runtime/agent-session.d.ts +1 -0
- package/dist/internal/runtime/budget-tracker.d.ts +73 -0
- package/dist/internal/runtime/{context-manager.d.ts → context/context-manager.d.ts} +1 -1
- package/dist/internal/runtime/{fixture-events.d.ts → fixtures/fixture-events.d.ts} +1 -1
- package/dist/internal/runtime/{fixture-run-base.d.ts → fixtures/fixture-run-base.d.ts} +4 -4
- package/dist/internal/runtime/{fixture-scripts.d.ts → fixtures/fixture-scripts.d.ts} +1 -1
- package/dist/internal/runtime/local-agent-bootstrap.d.ts +2 -2
- package/dist/internal/runtime/local-agent-memory-provider.d.ts +57 -0
- package/dist/internal/runtime/memory-path-selector.d.ts +73 -0
- package/dist/internal/runtime/memory-provider.d.ts +165 -0
- package/dist/internal/runtime/{agent-registry.d.ts → registry/agent-registry-contract.d.ts} +15 -9
- package/dist/internal/runtime/registry/agent-registry.d.ts +7 -0
- package/dist/internal/runtime/{live-agent-registry.d.ts → registry/live-agent-registry.d.ts} +1 -1
- package/dist/internal/runtime/{run-registry.d.ts → registry/run-registry.d.ts} +1 -1
- package/dist/internal/runtime/session-types.d.ts +35 -0
- package/dist/internal/runtime/system-prompt/sources/skills-provider.d.ts +1 -0
- package/dist/internal/runtime/validate-response.d.ts +18 -0
- package/dist/internal/security/index.cjs +361 -0
- package/dist/internal/security/index.cjs.map +1 -0
- package/dist/internal/security/index.d.cts +11 -0
- package/dist/internal/security/index.js +350 -0
- package/dist/internal/security/index.js.map +1 -0
- package/dist/internal/security/path-guard.d.cts +59 -0
- package/dist/internal/security/path-guard.d.ts +3 -0
- package/dist/internal/security/redact.d.cts +21 -0
- package/dist/internal/security/secret-redactor.d.cts +1 -0
- package/dist/internal/security/secret-redactor.d.ts +1 -0
- package/dist/internal/security/test-reset.d.cts +10 -0
- package/dist/internal/security/test-reset.d.ts +10 -0
- package/dist/internal/telemetry/adapters/arize.d.ts +2 -0
- package/dist/internal/telemetry/adapters/braintrust.d.ts +2 -0
- package/dist/internal/telemetry/adapters/datadog.d.ts +2 -0
- package/dist/internal/telemetry/adapters/langsmith.d.ts +2 -0
- package/dist/internal/telemetry/span-names.d.ts +6 -0
- package/dist/internal/telemetry/tracer.d.ts +1 -0
- package/dist/internal/workflow/evented-executor.d.ts +42 -0
- package/dist/internal/workflow/scheduler.d.ts +23 -0
- package/dist/internal/zod/to-json-schema.d.ts +5 -15
- package/dist/job-queue.d.ts +28 -0
- package/dist/path-safety.cjs +67 -6
- package/dist/path-safety.cjs.map +1 -1
- package/dist/path-safety.d.cts +15 -0
- package/dist/path-safety.d.ts +1 -1
- package/dist/path-safety.js +67 -7
- package/dist/path-safety.js.map +1 -1
- package/dist/permission-engine.d.ts +21 -0
- package/dist/provider-catalog.json +702 -0
- package/dist/rag/index.cjs +136 -0
- package/dist/rag/index.cjs.map +1 -0
- package/dist/rag/index.d.cts +11 -0
- package/dist/rag/index.d.ts +11 -0
- package/dist/rag/index.js +129 -0
- package/dist/rag/index.js.map +1 -0
- package/dist/rag/reranker.d.cts +26 -0
- package/dist/rag/reranker.d.ts +26 -0
- package/dist/rag/retriever.d.cts +25 -0
- package/dist/rag/retriever.d.ts +25 -0
- package/dist/rag/text-splitter.d.cts +12 -0
- package/dist/rag/text-splitter.d.ts +12 -0
- package/dist/rag/types.d.cts +37 -0
- package/dist/rag/types.d.ts +37 -0
- package/dist/run-DrwUpFxZ.d.cts +823 -0
- package/dist/run-DrwUpFxZ.d.ts +823 -0
- package/dist/sandbox/index.cjs +133 -0
- package/dist/sandbox/index.cjs.map +1 -0
- package/dist/sandbox/index.d.cts +2 -0
- package/dist/sandbox/index.d.ts +2 -0
- package/dist/sandbox/index.js +128 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/local-sandbox.d.cts +17 -0
- package/dist/sandbox/local-sandbox.d.ts +17 -0
- package/dist/sandbox/types.d.cts +44 -0
- package/dist/sandbox/types.d.ts +44 -0
- package/dist/server/adapter/express.d.cts +9 -0
- package/dist/server/adapter/express.d.ts +9 -0
- package/dist/server/adapter/fastify.d.cts +9 -0
- package/dist/server/adapter/fastify.d.ts +9 -0
- package/dist/server/adapter/hono.d.cts +9 -0
- package/dist/server/adapter/hono.d.ts +9 -0
- package/dist/server/adapter/index.d.cts +8 -0
- package/dist/server/adapter/index.d.ts +8 -0
- package/dist/server/adapter/shared-handler.d.cts +9 -0
- package/dist/server/adapter/shared-handler.d.ts +9 -0
- package/dist/server/adapter/types.d.cts +33 -0
- package/dist/server/adapter/types.d.ts +33 -0
- package/dist/server/auth/errors.d.cts +53 -0
- package/dist/server/auth/errors.d.ts +53 -0
- package/dist/server/auth/index.cjs +48 -42
- package/dist/server/auth/index.cjs.map +1 -1
- package/dist/server/auth/index.d.cts +11 -172
- package/dist/server/auth/index.d.ts +11 -172
- package/dist/server/auth/index.js +49 -43
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/auth/oauth-transaction-store.d.cts +39 -0
- package/dist/server/auth/oauth-transaction-store.d.ts +39 -0
- package/dist/server/auth/orchestrator.d.cts +8 -0
- package/dist/server/auth/orchestrator.d.ts +8 -0
- package/dist/server/auth/types.d.cts +91 -0
- package/dist/server/auth/types.d.ts +91 -0
- package/dist/server/auth/validate-return-to.d.cts +17 -0
- package/dist/server/auth/validate-return-to.d.ts +17 -0
- package/dist/server/errors-envelope.cjs +409 -0
- package/dist/server/errors-envelope.cjs.map +1 -0
- package/dist/server/errors-envelope.d.cts +61 -0
- package/dist/server/errors-envelope.d.ts +61 -0
- package/dist/server/errors-envelope.js +405 -0
- package/dist/server/errors-envelope.js.map +1 -0
- package/dist/subscription/define-subscription.d.cts +63 -0
- package/dist/subscription/define-subscription.d.ts +63 -0
- package/dist/subscription/index.cjs +402 -0
- package/dist/subscription/index.cjs.map +1 -0
- package/dist/subscription/index.d.cts +18 -0
- package/dist/subscription/index.d.ts +18 -0
- package/dist/subscription/index.js +394 -0
- package/dist/subscription/index.js.map +1 -0
- package/dist/subscription/internal/adapter-types.d.cts +11 -0
- package/dist/subscription/internal/adapter-types.d.ts +11 -0
- package/dist/subscription/internal/backpressure.d.cts +24 -0
- package/dist/subscription/internal/backpressure.d.ts +24 -0
- package/dist/subscription/internal/server-integration.d.cts +17 -0
- package/dist/subscription/internal/server-integration.d.ts +17 -0
- package/dist/subscription/internal/sse-encoder.d.cts +13 -0
- package/dist/subscription/internal/sse-encoder.d.ts +13 -0
- package/dist/subscription/internal/sse-parser.d.cts +15 -0
- package/dist/subscription/internal/sse-parser.d.ts +15 -0
- package/dist/subscription/internal/subscription-runtime.d.cts +9 -0
- package/dist/subscription/internal/subscription-runtime.d.ts +9 -0
- package/dist/subscription/internal/ws-adapter-node.d.cts +10 -0
- package/dist/subscription/internal/ws-adapter-node.d.ts +10 -0
- package/dist/subscription/theokit-subscribe.d.cts +41 -0
- package/dist/subscription/theokit-subscribe.d.ts +41 -0
- package/dist/subscription/types.d.cts +140 -0
- package/dist/subscription/types.d.ts +140 -0
- package/dist/task-store.cjs +30 -2
- package/dist/task-store.cjs.map +1 -1
- package/dist/task-store.d.cts +8 -0
- package/dist/task-store.js +31 -3
- package/dist/task-store.js.map +1 -1
- package/dist/types/agent-prims.d.ts +61 -0
- package/dist/types/agent.d.ts +48 -53
- package/dist/types/conversation.d.ts +20 -8
- package/dist/types/index.d.ts +0 -2
- package/dist/types/messages-base.d.ts +20 -0
- package/dist/types/messages.d.ts +1 -1
- package/dist/types/run.d.ts +1 -1
- package/dist/types/updates.d.ts +1 -1
- package/dist/voice/index.d.ts +7 -0
- package/dist/voice/openai-realtime.d.ts +21 -0
- package/dist/voice/types.d.ts +35 -0
- package/dist/workflow.cjs +179 -88
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +97 -0
- package/dist/workflow.js +180 -89
- package/dist/workflow.js.map +1 -1
- package/package.json +126 -25
- package/dist/budget.d.ts +0 -48
- package/dist/cache.d.ts +0 -74
- package/dist/cron-1yxL3K2S.d.cts +0 -221
- package/dist/cron-BYVdYzob.d.ts +0 -221
- package/dist/handoff.d.ts +0 -55
- package/dist/internal/budget/calendar-window.d.ts +0 -19
- package/dist/internal/budget/enforcement.d.ts +0 -32
- package/dist/internal/budget/ledger.d.ts +0 -25
- package/dist/internal/budget/normalize-usage.d.ts +0 -27
- package/dist/internal/budget/registry.d.ts +0 -16
- package/dist/internal/cache/cosine.d.ts +0 -14
- package/dist/internal/cache/embed-helper.d.ts +0 -15
- package/dist/internal/cache/key.d.ts +0 -15
- package/dist/internal/cache/lookup.d.ts +0 -28
- package/dist/internal/cache/store-handler.d.ts +0 -24
- package/dist/internal/cache/store-json.d.ts +0 -48
- package/dist/internal/cache/store.d.ts +0 -54
- package/dist/internal/cache/telemetry.d.ts +0 -20
- package/dist/internal/cache/ttl.d.ts +0 -11
- package/dist/internal/catalog/fixtures.d.ts +0 -16
- package/dist/internal/catalog/local-models.d.ts +0 -24
- package/dist/internal/handoff/dispatcher.d.ts +0 -29
- package/dist/internal/handoff/registry.d.ts +0 -23
- package/dist/internal/handoff/telemetry.d.ts +0 -18
- package/dist/internal/handoff/tool-injector.d.ts +0 -34
- package/dist/internal/memory/atomic-write.d.ts +0 -7
- package/dist/internal/memory/dreaming/diary.d.ts +0 -4
- package/dist/internal/memory/dreaming/phases.d.ts +0 -15
- package/dist/internal/memory/dreaming/run.d.ts +0 -10
- package/dist/internal/memory/migrate-sqlite-to-lance.d.ts +0 -15
- package/dist/memory-adapter-helpers.d.ts +0 -28
- package/dist/memory.d.ts +0 -123
- package/dist/migrate.d.ts +0 -33
- package/dist/security.d.ts +0 -67
- package/dist/task.d.ts +0 -87
- package/dist/theokit.d.ts +0 -84
- package/dist/tools/_path-scope.d.ts +0 -8
- package/dist/tools/_subprocess.d.ts +0 -28
- package/dist/tools/git-diff.d.ts +0 -22
- package/dist/tools/index.d.ts +0 -29
- package/dist/tools/list-dir.d.ts +0 -26
- package/dist/tools/read-file.d.ts +0 -31
- package/dist/tools/run-vitest.d.ts +0 -46
- package/dist/tools/search-text.d.ts +0 -32
- package/dist/tools.cjs +0 -690
- package/dist/tools.cjs.map +0 -1
- package/dist/tools.js +0 -683
- package/dist/tools.js.map +0 -1
- package/dist/trajectory-helpers.d.ts +0 -31
- package/dist/types/cache.d.ts +0 -76
- package/dist/types/handoff.d.ts +0 -135
- /package/dist/{internal/cron/run-job.d.ts → agent-helpers.d.ts} +0 -0
- /package/dist/internal/{cron/scheduler.d.ts → agent-loop/loop-llm-stream.d.ts} +0 -0
- /package/dist/internal/{cron/store.d.ts → agent-loop/tool-executors.d.ts} +0 -0
- /package/dist/internal/{cron/validate.d.ts → memory/index-manager-helpers.d.ts} +0 -0
- /package/dist/internal/memory/{session-loader.d.ts → storage/session-loader.d.ts} +0 -0
- /package/dist/internal/memory/{session-summary-writer.d.ts → storage/session-summary-writer.d.ts} +0 -0
- /package/dist/internal/memory/{transcript-store.d.ts → storage/transcript-store.d.ts} +0 -0
- /package/dist/internal/memory/{wiki-loader.d.ts → storage/wiki-loader.d.ts} +0 -0
- /package/dist/internal/{memory/cwd-mutex.d.ts → persistence/atomic-write.d.cts} +0 -0
- /package/dist/internal/runtime/{context-aggregator.d.ts → context/context-aggregator.d.ts} +0 -0
- /package/dist/internal/runtime/{context-discovery-runner.d.ts → context/context-discovery-runner.d.ts} +0 -0
- /package/dist/internal/runtime/{context-discovery.d.ts → context/context-discovery.d.ts} +0 -0
- /package/dist/internal/runtime/{context-frontmatter.d.ts → context/context-frontmatter.d.ts} +0 -0
- /package/dist/internal/runtime/{context-import-resolver.d.ts → context/context-import-resolver.d.ts} +0 -0
- /package/dist/internal/runtime/{context-loaders.d.ts → context/context-loaders.d.ts} +0 -0
- /package/dist/internal/runtime/{context-mdc-parser.d.ts → context/context-mdc-parser.d.ts} +0 -0
- /package/dist/internal/runtime/{fixture-responder.d.ts → fixtures/fixture-responder.d.ts} +0 -0
- /package/dist/internal/runtime/{fixture-types.d.ts → fixtures/fixture-types.d.ts} +0 -0
- /package/dist/internal/runtime/{plugins-manager.d.ts → local-agent-send.d.ts} +0 -0
- /package/dist/internal/runtime/{plugin-frontmatter.d.ts → plugins/plugin-frontmatter.d.ts} +0 -0
- /package/dist/internal/runtime/{system-prompt/providers/active-memory-provider.d.ts → plugins/plugins-manager.d.ts} +0 -0
- /package/dist/internal/runtime/{agent-factory-registry.d.ts → registry/agent-factory-registry.d.ts} +0 -0
- /package/dist/internal/runtime/{agent-registry-store.d.ts → registry/agent-registry-store.d.ts} +0 -0
- /package/dist/internal/runtime/system-prompt/{providers/base-provider.d.ts → sources/active-memory-provider.d.ts} +0 -0
- /package/dist/internal/runtime/system-prompt/{providers/context-provider.d.ts → sources/base-provider.d.ts} +0 -0
- /package/dist/internal/runtime/system-prompt/{providers/memory-provider.d.ts → sources/context-provider.d.ts} +0 -0
- /package/dist/internal/runtime/system-prompt/{providers/skills-provider.d.ts → sources/memory-provider.d.ts} +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/internal/plugins/context.ts
|
|
4
|
+
function createPluginContext() {
|
|
5
|
+
const registrations = {
|
|
6
|
+
tools: [],
|
|
7
|
+
commands: [],
|
|
8
|
+
hooks: /* @__PURE__ */ new Map(),
|
|
9
|
+
injected: []
|
|
10
|
+
};
|
|
11
|
+
const impl = {
|
|
12
|
+
registerTool(tool) {
|
|
13
|
+
registrations.tools.push(tool);
|
|
14
|
+
},
|
|
15
|
+
registerCommand(name, handler, opts = {}) {
|
|
16
|
+
const entry = { name, handler };
|
|
17
|
+
if (opts.description !== void 0) entry.description = opts.description;
|
|
18
|
+
registrations.commands.push(entry);
|
|
19
|
+
},
|
|
20
|
+
on(hook, handler) {
|
|
21
|
+
if (typeof handler !== "function") {
|
|
22
|
+
process.stderr.write(`[theokit-sdk] ignoring non-function handler for hook "${hook}"
|
|
23
|
+
`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const existing = registrations.hooks.get(hook) ?? [];
|
|
27
|
+
existing.push(handler);
|
|
28
|
+
registrations.hooks.set(hook, existing);
|
|
29
|
+
},
|
|
30
|
+
injectMessage(content, role = "user") {
|
|
31
|
+
registrations.injected.push({ content, role });
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const ctx = shouldSeal() ? sealContext(impl) : impl;
|
|
35
|
+
return { ctx, registrations };
|
|
36
|
+
}
|
|
37
|
+
function shouldSeal() {
|
|
38
|
+
return process.env.NODE_ENV !== "production";
|
|
39
|
+
}
|
|
40
|
+
function sealContext(impl) {
|
|
41
|
+
return new Proxy(impl, {
|
|
42
|
+
set(_target, prop) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`[theokit-sdk] PluginContext is sealed \u2014 cannot set ${String(prop)}. Plugins must use registerTool, registerCommand, on, or injectMessage.`
|
|
45
|
+
);
|
|
46
|
+
},
|
|
47
|
+
deleteProperty(_target, prop) {
|
|
48
|
+
throw new Error(`[theokit-sdk] PluginContext is sealed \u2014 cannot delete ${String(prop)}.`);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/internal/plugins/lifecycle.ts
|
|
54
|
+
async function runFireAndForgetHooks(handlers, ctx) {
|
|
55
|
+
for (const h of handlers) {
|
|
56
|
+
try {
|
|
57
|
+
await h(ctx);
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
process.stderr.write(`[theokit-sdk] plugin hook threw (continuing): ${msg}
|
|
61
|
+
`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function runTransformHooks(handlers, initial) {
|
|
66
|
+
let current = initial;
|
|
67
|
+
for (const h of handlers) {
|
|
68
|
+
try {
|
|
69
|
+
const next = await h(current);
|
|
70
|
+
if (next !== void 0) current = next;
|
|
71
|
+
} catch (err) {
|
|
72
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
73
|
+
process.stderr.write(`[theokit-sdk] plugin transform hook threw (continuing): ${msg}
|
|
74
|
+
`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return current;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/internal/plugins/manager.ts
|
|
81
|
+
var PluginManager = class {
|
|
82
|
+
#aggregated = {
|
|
83
|
+
tools: [],
|
|
84
|
+
commands: [],
|
|
85
|
+
hooks: /* @__PURE__ */ new Map(),
|
|
86
|
+
injected: [],
|
|
87
|
+
providerProfiles: [],
|
|
88
|
+
memoryProviders: []
|
|
89
|
+
};
|
|
90
|
+
#initialized = false;
|
|
91
|
+
async initialize(plugins) {
|
|
92
|
+
if (this.#initialized) {
|
|
93
|
+
throw new Error("PluginManager.initialize called twice \u2014 register only once per process");
|
|
94
|
+
}
|
|
95
|
+
this.#initialized = true;
|
|
96
|
+
const seen = /* @__PURE__ */ new Set();
|
|
97
|
+
for (const plugin of plugins) {
|
|
98
|
+
if (seen.has(plugin.name)) {
|
|
99
|
+
process.stderr.write(
|
|
100
|
+
`[theokit-sdk] duplicate plugin name "${plugin.name}" \u2014 both will register independently
|
|
101
|
+
`
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
seen.add(plugin.name);
|
|
105
|
+
await this.#dispatchPlugin(plugin);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
get aggregated() {
|
|
109
|
+
return this.#aggregated;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Run all `pre_tool_call` hooks; first decision with `block: true` wins.
|
|
113
|
+
* D101: veto pattern — return `{ block: true, message }` makes the loop
|
|
114
|
+
* surface a tool_result with `isError: false, content: message` so the
|
|
115
|
+
* LLM can self-correct.
|
|
116
|
+
*/
|
|
117
|
+
async runPreToolCallHooks(ctx) {
|
|
118
|
+
const handlers = this.#aggregated.hooks.get("pre_tool_call") ?? [];
|
|
119
|
+
for (const h of handlers) {
|
|
120
|
+
const decision = await h(ctx);
|
|
121
|
+
if (decision !== void 0 && decision.block === true) {
|
|
122
|
+
return decision;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return void 0;
|
|
126
|
+
}
|
|
127
|
+
/** Aggregated handlers for a given hook (read-only view). @internal */
|
|
128
|
+
hooksFor(name) {
|
|
129
|
+
return this.#aggregated.hooks.get(name) ?? [];
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Run all `pre_user_send` hooks; concatenate non-empty `recalledContext`
|
|
133
|
+
* outputs with `\n\n` and cap total length at `maxRecallContextBytes`
|
|
134
|
+
* (EC-A). Per-handler failures are caught + logged to stderr (EC-8) so a
|
|
135
|
+
* single broken adapter never blocks the LLM call (graceful degrade).
|
|
136
|
+
*
|
|
137
|
+
* Returns the assembled context (or undefined if empty after cap).
|
|
138
|
+
*
|
|
139
|
+
* @internal
|
|
140
|
+
*/
|
|
141
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-handler try/catch + EC-A cap + EC-8 isolation are 3 concerns that share state (parts buffer); splitting fragments the single-pass aggregation.
|
|
142
|
+
async runPreUserSendHooks(ctx, maxRecallContextBytes) {
|
|
143
|
+
const handlers = this.#aggregated.hooks.get("pre_user_send") ?? [];
|
|
144
|
+
if (handlers.length === 0) return void 0;
|
|
145
|
+
const parts = [];
|
|
146
|
+
for (const h of handlers) {
|
|
147
|
+
try {
|
|
148
|
+
const result = await h(ctx);
|
|
149
|
+
if (result?.recalledContext && result.recalledContext.length > 0) {
|
|
150
|
+
parts.push(result.recalledContext);
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
process.stderr.write(
|
|
154
|
+
`[theokit-sdk] pre_user_send hook failed: ${err instanceof Error ? err.message : String(err)}
|
|
155
|
+
`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
if (parts.length === 0) return void 0;
|
|
160
|
+
let combined = parts.join("\n\n");
|
|
161
|
+
if (combined.length > maxRecallContextBytes) {
|
|
162
|
+
combined = `${combined.slice(0, maxRecallContextBytes)}
|
|
163
|
+
\u2026[truncated]`;
|
|
164
|
+
}
|
|
165
|
+
return combined;
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Run all `post_assistant_reply` hooks. Fire-and-forget: errors are
|
|
169
|
+
* surfaced to stderr (EC-O) so a slow/broken sync never blocks the
|
|
170
|
+
* caller's `wait()`. Returns a Promise that callers may optionally
|
|
171
|
+
* await for tests; production code typically `void`s it.
|
|
172
|
+
*
|
|
173
|
+
* @internal
|
|
174
|
+
*/
|
|
175
|
+
async runPostAssistantReplyHooks(ctx) {
|
|
176
|
+
const handlers = this.#aggregated.hooks.get("post_assistant_reply") ?? [];
|
|
177
|
+
for (const h of handlers) {
|
|
178
|
+
try {
|
|
179
|
+
await h(ctx);
|
|
180
|
+
} catch (err) {
|
|
181
|
+
process.stderr.write(
|
|
182
|
+
`[theokit-sdk] post_assistant_reply hook failed: ${err instanceof Error ? err.message : String(err)}
|
|
183
|
+
`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
async #dispatchPlugin(plugin) {
|
|
189
|
+
if (plugin.kind === "general") {
|
|
190
|
+
const { ctx, registrations } = createPluginContext();
|
|
191
|
+
await plugin.register(ctx);
|
|
192
|
+
this.#merge(registrations);
|
|
193
|
+
} else if (plugin.kind === "model-provider") {
|
|
194
|
+
this.#aggregated.providerProfiles.push({
|
|
195
|
+
pluginName: plugin.name,
|
|
196
|
+
profile: plugin.profile
|
|
197
|
+
});
|
|
198
|
+
} else if (plugin.kind === "memory") {
|
|
199
|
+
this.#aggregated.memoryProviders.push({
|
|
200
|
+
pluginName: plugin.name,
|
|
201
|
+
createProvider: plugin.createProvider
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
#merge(r) {
|
|
206
|
+
this.#aggregated.tools.push(...r.tools);
|
|
207
|
+
this.#aggregated.commands.push(...r.commands);
|
|
208
|
+
for (const [hook, handlers] of r.hooks.entries()) {
|
|
209
|
+
const existing = this.#aggregated.hooks.get(hook) ?? [];
|
|
210
|
+
existing.push(...handlers);
|
|
211
|
+
this.#aggregated.hooks.set(hook, existing);
|
|
212
|
+
}
|
|
213
|
+
this.#aggregated.injected.push(...r.injected);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// src/internal/plugins/types.ts
|
|
218
|
+
function definePlugin(p) {
|
|
219
|
+
return p;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
exports.PluginManager = PluginManager;
|
|
223
|
+
exports.createPluginContext = createPluginContext;
|
|
224
|
+
exports.definePlugin = definePlugin;
|
|
225
|
+
exports.runFireAndForgetHooks = runFireAndForgetHooks;
|
|
226
|
+
exports.runTransformHooks = runTransformHooks;
|
|
227
|
+
//# sourceMappingURL=index.cjs.map
|
|
228
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/internal/plugins/context.ts","../../../src/internal/plugins/lifecycle.ts","../../../src/internal/plugins/manager.ts","../../../src/internal/plugins/types.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * PluginContext implementation + dev-mode seal (T1.2, ADR D99).\n *\n * `createPluginContext()` returns a fresh `{ ctx, registrations }` pair\n * for each plugin. In dev mode (`NODE_ENV !== \"production\"`) the context\n * is wrapped in a Proxy that throws on `set`/`delete` to catch plugin\n * abuse early. In production the raw impl is returned (zero overhead).\n *\n * @internal\n */\n\nimport type { CustomTool } from \"../../types/agent.js\";\nimport type {\n CommandHandler,\n CommandOptions,\n HookHandler,\n HookName,\n PluginContext,\n} from \"./types.js\";\n\ninterface CommandEntry {\n name: string;\n handler: CommandHandler;\n description?: string;\n}\n\ninterface InjectedMessage {\n content: string;\n role: \"user\" | \"system\";\n}\n\nexport interface PluginRegistrations {\n tools: CustomTool[];\n commands: CommandEntry[];\n hooks: Map<HookName, HookHandler[]>;\n injected: InjectedMessage[];\n}\n\nexport function createPluginContext(): {\n ctx: PluginContext;\n registrations: PluginRegistrations;\n} {\n const registrations: PluginRegistrations = {\n tools: [],\n commands: [],\n hooks: new Map(),\n injected: [],\n };\n\n const impl: PluginContext = {\n registerTool(tool) {\n registrations.tools.push(tool);\n },\n registerCommand(name, handler, opts: CommandOptions = {}) {\n const entry: CommandEntry = { name, handler };\n if (opts.description !== undefined) entry.description = opts.description;\n registrations.commands.push(entry);\n },\n on(hook, handler) {\n // EC-2 fix: defense-in-depth. Plugin author can bypass TS via `as any`\n // and pass null/undefined; ignore + warn rather than crash the loop\n // downstream when `runPreToolCallHooks` tries to invoke the handler.\n if (typeof handler !== \"function\") {\n process.stderr.write(`[theokit-sdk] ignoring non-function handler for hook \"${hook}\"\\n`);\n return;\n }\n const existing = registrations.hooks.get(hook) ?? [];\n existing.push(handler);\n registrations.hooks.set(hook, existing);\n },\n injectMessage(content, role = \"user\") {\n registrations.injected.push({ content, role });\n },\n };\n\n const ctx = shouldSeal() ? sealContext(impl) : impl;\n return { ctx, registrations };\n}\n\nfunction shouldSeal(): boolean {\n return process.env.NODE_ENV !== \"production\";\n}\n\nfunction sealContext(impl: PluginContext): PluginContext {\n return new Proxy(impl, {\n set(_target, prop) {\n throw new Error(\n `[theokit-sdk] PluginContext is sealed — cannot set ${String(prop)}. ` +\n `Plugins must use registerTool, registerCommand, on, or injectMessage.`,\n );\n },\n deleteProperty(_target, prop) {\n throw new Error(`[theokit-sdk] PluginContext is sealed — cannot delete ${String(prop)}.`);\n },\n });\n}\n","/**\n * Hook dispatch helpers (T1.4, extracted from manager to keep both modules\n * small).\n *\n * - `runFireAndForgetHooks` — runs all handlers, swallows + logs throws,\n * no return value (post_tool_call, on_session_start/end, etc.).\n * - `runTransformHooks` — chains handlers, each can return a new value\n * that replaces the input for the next handler. `undefined` keeps the\n * current; `null` REPLACES current with null (EC-6 explicit).\n *\n * @internal\n */\n\nimport type { HookHandler } from \"./types.js\";\n\nexport async function runFireAndForgetHooks<C>(\n handlers: ReadonlyArray<HookHandler>,\n ctx: C,\n): Promise<void> {\n for (const h of handlers) {\n try {\n await (h as (c: C) => unknown)(ctx);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[theokit-sdk] plugin hook threw (continuing): ${msg}\\n`);\n }\n }\n}\n\nexport async function runTransformHooks<T>(\n handlers: ReadonlyArray<HookHandler>,\n initial: T,\n): Promise<T> {\n let current = initial;\n for (const h of handlers) {\n try {\n const next = await (h as (c: T) => T | undefined)(current);\n // EC-6 explicit semantics: `undefined` = no-op; any other value\n // (including `null`) REPLACES current.\n if (next !== undefined) current = next;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[theokit-sdk] plugin transform hook threw (continuing): ${msg}\\n`);\n }\n }\n return current;\n}\n","/**\n * PluginManager — constructs PluginContext per plugin, invokes register()\n * once, aggregates registrations + provider profiles + memory factories\n * (T1.3, ADRs D97-D101).\n *\n * @internal\n */\n\nimport type { ProviderProfile } from \"../providers/types.js\";\nimport { createPluginContext, type PluginRegistrations } from \"./context.js\";\nimport type {\n HookHandler,\n MemoryProviderFactory,\n Plugin,\n PostAssistantReplyContext,\n PreToolCallContext,\n PreToolCallDecision,\n PreUserSendContext,\n PreUserSendResult,\n} from \"./types.js\";\n\nexport interface ProviderEntry {\n pluginName: string;\n profile: ProviderProfile;\n}\n\nexport interface MemoryEntry {\n pluginName: string;\n createProvider: MemoryProviderFactory;\n}\n\nexport interface AggregatedPlugins {\n tools: PluginRegistrations[\"tools\"];\n commands: PluginRegistrations[\"commands\"];\n hooks: PluginRegistrations[\"hooks\"];\n injected: PluginRegistrations[\"injected\"];\n providerProfiles: ProviderEntry[];\n memoryProviders: MemoryEntry[];\n}\n\nexport class PluginManager {\n #aggregated: AggregatedPlugins = {\n tools: [],\n commands: [],\n hooks: new Map(),\n injected: [],\n providerProfiles: [],\n memoryProviders: [],\n };\n #initialized = false;\n\n async initialize(plugins: ReadonlyArray<Plugin>): Promise<void> {\n if (this.#initialized) {\n throw new Error(\"PluginManager.initialize called twice — register only once per process\");\n }\n this.#initialized = true;\n // EC-4: surface duplicate plugin names so operators notice. Two plugins\n // with the same name are usually a mistake (npm install with override).\n const seen = new Set<string>();\n for (const plugin of plugins) {\n if (seen.has(plugin.name)) {\n process.stderr.write(\n `[theokit-sdk] duplicate plugin name \"${plugin.name}\" — both will register independently\\n`,\n );\n }\n seen.add(plugin.name);\n await this.#dispatchPlugin(plugin);\n }\n }\n\n get aggregated(): Readonly<AggregatedPlugins> {\n return this.#aggregated;\n }\n\n /**\n * Run all `pre_tool_call` hooks; first decision with `block: true` wins.\n * D101: veto pattern — return `{ block: true, message }` makes the loop\n * surface a tool_result with `isError: false, content: message` so the\n * LLM can self-correct.\n */\n async runPreToolCallHooks(ctx: PreToolCallContext): Promise<PreToolCallDecision | undefined> {\n const handlers = this.#aggregated.hooks.get(\"pre_tool_call\") ?? [];\n for (const h of handlers) {\n const decision = (await (h as (c: PreToolCallContext) => unknown)(ctx)) as\n | PreToolCallDecision\n | undefined;\n if (decision !== undefined && (decision as { block?: boolean }).block === true) {\n return decision as PreToolCallDecision;\n }\n }\n return undefined;\n }\n\n /** Aggregated handlers for a given hook (read-only view). @internal */\n hooksFor(name: Parameters<AggregatedPlugins[\"hooks\"][\"get\"]>[0]): ReadonlyArray<HookHandler> {\n return this.#aggregated.hooks.get(name) ?? [];\n }\n\n /**\n * Run all `pre_user_send` hooks; concatenate non-empty `recalledContext`\n * outputs with `\\n\\n` and cap total length at `maxRecallContextBytes`\n * (EC-A). Per-handler failures are caught + logged to stderr (EC-8) so a\n * single broken adapter never blocks the LLM call (graceful degrade).\n *\n * Returns the assembled context (or undefined if empty after cap).\n *\n * @internal\n */\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-handler try/catch + EC-A cap + EC-8 isolation are 3 concerns that share state (parts buffer); splitting fragments the single-pass aggregation.\n async runPreUserSendHooks(\n ctx: PreUserSendContext,\n maxRecallContextBytes: number,\n ): Promise<string | undefined> {\n const handlers = this.#aggregated.hooks.get(\"pre_user_send\") ?? [];\n if (handlers.length === 0) return undefined;\n const parts: string[] = [];\n for (const h of handlers) {\n try {\n const result = (await (h as (c: PreUserSendContext) => unknown)(ctx)) as\n | PreUserSendResult\n | undefined;\n if (result?.recalledContext && result.recalledContext.length > 0) {\n parts.push(result.recalledContext);\n }\n } catch (err) {\n process.stderr.write(\n `[theokit-sdk] pre_user_send hook failed: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n }\n if (parts.length === 0) return undefined;\n let combined = parts.join(\"\\n\\n\");\n // EC-A: cap to prevent context-window blowout.\n if (combined.length > maxRecallContextBytes) {\n combined = `${combined.slice(0, maxRecallContextBytes)}\\n…[truncated]`;\n }\n return combined;\n }\n\n /**\n * Run all `post_assistant_reply` hooks. Fire-and-forget: errors are\n * surfaced to stderr (EC-O) so a slow/broken sync never blocks the\n * caller's `wait()`. Returns a Promise that callers may optionally\n * await for tests; production code typically `void`s it.\n *\n * @internal\n */\n async runPostAssistantReplyHooks(ctx: PostAssistantReplyContext): Promise<void> {\n const handlers = this.#aggregated.hooks.get(\"post_assistant_reply\") ?? [];\n for (const h of handlers) {\n try {\n await (h as (c: PostAssistantReplyContext) => unknown)(ctx);\n } catch (err) {\n process.stderr.write(\n `[theokit-sdk] post_assistant_reply hook failed: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n }\n }\n\n async #dispatchPlugin(plugin: Plugin): Promise<void> {\n if (plugin.kind === \"general\") {\n const { ctx, registrations } = createPluginContext();\n await plugin.register(ctx);\n this.#merge(registrations);\n } else if (plugin.kind === \"model-provider\") {\n this.#aggregated.providerProfiles.push({\n pluginName: plugin.name,\n profile: plugin.profile,\n });\n } else if (plugin.kind === \"memory\") {\n this.#aggregated.memoryProviders.push({\n pluginName: plugin.name,\n createProvider: plugin.createProvider,\n });\n }\n }\n\n #merge(r: PluginRegistrations): void {\n this.#aggregated.tools.push(...r.tools);\n this.#aggregated.commands.push(...r.commands);\n for (const [hook, handlers] of r.hooks.entries()) {\n const existing = this.#aggregated.hooks.get(hook) ?? [];\n existing.push(...handlers);\n this.#aggregated.hooks.set(hook, existing);\n }\n this.#aggregated.injected.push(...r.injected);\n }\n}\n","/**\n * Plugin contract types (T1.1, ADRs D97-D101).\n *\n * Discriminated union by `kind`:\n * - `\"general\"` — registers tools/hooks/commands via `register(ctx)`.\n * - `\"model-provider\"` — declares a `ProviderProfile` consumed by router.\n * - `\"memory\"` — supplies a memory provider factory.\n *\n * Hooks are a fixed enum (D100) to prevent sprawl; `pre_tool_call` supports\n * veto via `{ block: true, message }` (D101) so plugins can implement safety\n * guards without crashing the agent loop.\n *\n * @public\n */\n\nimport type { CustomTool } from \"../../types/agent.js\";\nimport type { MemoryAdapter } from \"../../types/memory-adapter.js\";\nimport type { ProviderProfile } from \"../providers/types.js\";\n\nexport type HookName =\n | \"pre_tool_call\"\n | \"post_tool_call\"\n | \"pre_llm_call\"\n | \"post_llm_call\"\n | \"on_session_start\"\n | \"on_session_end\"\n | \"transform_tool_result\"\n | \"transform_llm_output\"\n // Memory adapter hooks (ADRs D141 / D145).\n | \"pre_user_send\"\n | \"post_assistant_reply\";\n\nexport interface PreToolCallContext {\n name: string;\n args: Record<string, unknown>;\n agentId: string;\n runId: string;\n}\n\nexport interface PreToolCallDecision {\n block: true;\n message: string;\n}\n\n/**\n * Context passed to `pre_user_send` hook handlers (ADR D145).\n *\n * @public\n */\nexport interface PreUserSendContext {\n prompt: string;\n agentId: string;\n runId: string;\n /** Caller-supplied memory context, flowing through from `AgentOptions.memoryContext`. */\n memoryContext?: import(\"../../types/memory-adapter.js\").MemoryContext;\n /** Forwarded `AbortSignal` so adapter recall HTTP can be cancelled mid-flight (EC-H). */\n signal?: AbortSignal;\n}\n\n/**\n * Optional result returned by `pre_user_send` handlers. The agent loop\n * concatenates `recalledContext` from all handlers and injects it as a\n * `<memory-context>...</memory-context>` block before the user prompt.\n *\n * @public\n */\nexport interface PreUserSendResult {\n recalledContext?: string;\n}\n\n/**\n * Context passed to `post_assistant_reply` hook handlers (ADR D145).\n * Fire-and-forget — exceptions are caught and surfaced to stderr; the\n * caller's `wait()` never blocks on this dispatch.\n *\n * @public\n */\nexport interface PostAssistantReplyContext {\n prompt: string;\n reply: string;\n agentId: string;\n runId: string;\n memoryContext?: import(\"../../types/memory-adapter.js\").MemoryContext;\n}\n\nexport type HookHandler = (ctx: unknown) => unknown | Promise<unknown>;\n\nexport type CommandHandler = (args: Record<string, unknown>) => Promise<string> | string;\n\nexport interface CommandOptions {\n description?: string;\n}\n\nexport interface PluginContext {\n /** Register a custom tool. Equivalent to passing in `AgentOptions.tools`. */\n registerTool(tool: CustomTool): void;\n /** Register a slash-command-style handler. Consumed by CLI/bot wrappers; NOT used by the agent loop. */\n registerCommand(name: string, handler: CommandHandler, opts?: CommandOptions): void;\n /** Attach a hook handler. `pre_tool_call` supports veto via `PreToolCallDecision`. */\n on(hook: HookName, handler: HookHandler): void;\n /** Inject a user/system message into the next agent turn. v1 supports only `on_session_start` context. */\n injectMessage(content: string, role?: \"user\" | \"system\"): void;\n}\n\ninterface BasePlugin {\n name: string;\n version: string;\n}\n\n/**\n * Memory provider factory shape (ADR D141). Returns a `MemoryAdapter`\n * (sync) or a Promise resolving to one (lazy HTTP probe / config load).\n *\n * Adapters live in `@theokit-memory-*` packages; the SDK never imports\n * them. Factory rejection is caught by the plugin manager and surfaced\n * as `ConfigurationError(code: \"plugin_factory_failed\")` (EC-F) — never\n * an unhandled rejection.\n *\n * @internal\n */\nexport type MemoryProviderFactory = (cwd: string) => MemoryAdapter | Promise<MemoryAdapter>;\n\nexport type Plugin =\n | (BasePlugin & {\n kind: \"general\";\n register: (ctx: PluginContext) => void | Promise<void>;\n })\n | (BasePlugin & {\n kind: \"model-provider\";\n profile: ProviderProfile;\n })\n | (BasePlugin & {\n kind: \"memory\";\n createProvider: MemoryProviderFactory;\n });\n\n/**\n * Identity helper for plugin authors. TS-only convenience — preserves\n * inferred type without forcing manual `Plugin` annotation.\n *\n * @public\n */\nexport function definePlugin<P extends Plugin>(p: P): P {\n return p;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the Plugin contract (ADRs D97-D101).
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export { runFireAndForgetHooks, runTransformHooks } from "./lifecycle.js";
|
|
7
|
+
export { type AggregatedPlugins, type MemoryEntry, PluginManager, type ProviderEntry, } from "./manager.js";
|
|
8
|
+
export { type CommandHandler, type CommandOptions, definePlugin, type HookHandler, type HookName, type MemoryProviderFactory, type Plugin, type PluginContext, type PostAssistantReplyContext, type PreToolCallContext, type PreToolCallDecision, type PreUserSendContext, type PreUserSendResult, } from "./types.js";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel for the Plugin contract (ADRs D97-D101).
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export { runFireAndForgetHooks, runTransformHooks } from "./lifecycle.js";
|
|
7
|
+
export { type AggregatedPlugins, type MemoryEntry, PluginManager, type ProviderEntry, } from "./manager.js";
|
|
8
|
+
export { type CommandHandler, type CommandOptions, definePlugin, type HookHandler, type HookName, type MemoryProviderFactory, type Plugin, type PluginContext, type PostAssistantReplyContext, type PreToolCallContext, type PreToolCallDecision, type PreUserSendContext, type PreUserSendResult, } from "./types.js";
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// src/internal/plugins/context.ts
|
|
2
|
+
function createPluginContext() {
|
|
3
|
+
const registrations = {
|
|
4
|
+
tools: [],
|
|
5
|
+
commands: [],
|
|
6
|
+
hooks: /* @__PURE__ */ new Map(),
|
|
7
|
+
injected: []
|
|
8
|
+
};
|
|
9
|
+
const impl = {
|
|
10
|
+
registerTool(tool) {
|
|
11
|
+
registrations.tools.push(tool);
|
|
12
|
+
},
|
|
13
|
+
registerCommand(name, handler, opts = {}) {
|
|
14
|
+
const entry = { name, handler };
|
|
15
|
+
if (opts.description !== void 0) entry.description = opts.description;
|
|
16
|
+
registrations.commands.push(entry);
|
|
17
|
+
},
|
|
18
|
+
on(hook, handler) {
|
|
19
|
+
if (typeof handler !== "function") {
|
|
20
|
+
process.stderr.write(`[theokit-sdk] ignoring non-function handler for hook "${hook}"
|
|
21
|
+
`);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const existing = registrations.hooks.get(hook) ?? [];
|
|
25
|
+
existing.push(handler);
|
|
26
|
+
registrations.hooks.set(hook, existing);
|
|
27
|
+
},
|
|
28
|
+
injectMessage(content, role = "user") {
|
|
29
|
+
registrations.injected.push({ content, role });
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const ctx = shouldSeal() ? sealContext(impl) : impl;
|
|
33
|
+
return { ctx, registrations };
|
|
34
|
+
}
|
|
35
|
+
function shouldSeal() {
|
|
36
|
+
return process.env.NODE_ENV !== "production";
|
|
37
|
+
}
|
|
38
|
+
function sealContext(impl) {
|
|
39
|
+
return new Proxy(impl, {
|
|
40
|
+
set(_target, prop) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
`[theokit-sdk] PluginContext is sealed \u2014 cannot set ${String(prop)}. Plugins must use registerTool, registerCommand, on, or injectMessage.`
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
deleteProperty(_target, prop) {
|
|
46
|
+
throw new Error(`[theokit-sdk] PluginContext is sealed \u2014 cannot delete ${String(prop)}.`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/internal/plugins/lifecycle.ts
|
|
52
|
+
async function runFireAndForgetHooks(handlers, ctx) {
|
|
53
|
+
for (const h of handlers) {
|
|
54
|
+
try {
|
|
55
|
+
await h(ctx);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
process.stderr.write(`[theokit-sdk] plugin hook threw (continuing): ${msg}
|
|
59
|
+
`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function runTransformHooks(handlers, initial) {
|
|
64
|
+
let current = initial;
|
|
65
|
+
for (const h of handlers) {
|
|
66
|
+
try {
|
|
67
|
+
const next = await h(current);
|
|
68
|
+
if (next !== void 0) current = next;
|
|
69
|
+
} catch (err) {
|
|
70
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
71
|
+
process.stderr.write(`[theokit-sdk] plugin transform hook threw (continuing): ${msg}
|
|
72
|
+
`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return current;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/internal/plugins/manager.ts
|
|
79
|
+
var PluginManager = class {
|
|
80
|
+
#aggregated = {
|
|
81
|
+
tools: [],
|
|
82
|
+
commands: [],
|
|
83
|
+
hooks: /* @__PURE__ */ new Map(),
|
|
84
|
+
injected: [],
|
|
85
|
+
providerProfiles: [],
|
|
86
|
+
memoryProviders: []
|
|
87
|
+
};
|
|
88
|
+
#initialized = false;
|
|
89
|
+
async initialize(plugins) {
|
|
90
|
+
if (this.#initialized) {
|
|
91
|
+
throw new Error("PluginManager.initialize called twice \u2014 register only once per process");
|
|
92
|
+
}
|
|
93
|
+
this.#initialized = true;
|
|
94
|
+
const seen = /* @__PURE__ */ new Set();
|
|
95
|
+
for (const plugin of plugins) {
|
|
96
|
+
if (seen.has(plugin.name)) {
|
|
97
|
+
process.stderr.write(
|
|
98
|
+
`[theokit-sdk] duplicate plugin name "${plugin.name}" \u2014 both will register independently
|
|
99
|
+
`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
seen.add(plugin.name);
|
|
103
|
+
await this.#dispatchPlugin(plugin);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
get aggregated() {
|
|
107
|
+
return this.#aggregated;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Run all `pre_tool_call` hooks; first decision with `block: true` wins.
|
|
111
|
+
* D101: veto pattern — return `{ block: true, message }` makes the loop
|
|
112
|
+
* surface a tool_result with `isError: false, content: message` so the
|
|
113
|
+
* LLM can self-correct.
|
|
114
|
+
*/
|
|
115
|
+
async runPreToolCallHooks(ctx) {
|
|
116
|
+
const handlers = this.#aggregated.hooks.get("pre_tool_call") ?? [];
|
|
117
|
+
for (const h of handlers) {
|
|
118
|
+
const decision = await h(ctx);
|
|
119
|
+
if (decision !== void 0 && decision.block === true) {
|
|
120
|
+
return decision;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
/** Aggregated handlers for a given hook (read-only view). @internal */
|
|
126
|
+
hooksFor(name) {
|
|
127
|
+
return this.#aggregated.hooks.get(name) ?? [];
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Run all `pre_user_send` hooks; concatenate non-empty `recalledContext`
|
|
131
|
+
* outputs with `\n\n` and cap total length at `maxRecallContextBytes`
|
|
132
|
+
* (EC-A). Per-handler failures are caught + logged to stderr (EC-8) so a
|
|
133
|
+
* single broken adapter never blocks the LLM call (graceful degrade).
|
|
134
|
+
*
|
|
135
|
+
* Returns the assembled context (or undefined if empty after cap).
|
|
136
|
+
*
|
|
137
|
+
* @internal
|
|
138
|
+
*/
|
|
139
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-handler try/catch + EC-A cap + EC-8 isolation are 3 concerns that share state (parts buffer); splitting fragments the single-pass aggregation.
|
|
140
|
+
async runPreUserSendHooks(ctx, maxRecallContextBytes) {
|
|
141
|
+
const handlers = this.#aggregated.hooks.get("pre_user_send") ?? [];
|
|
142
|
+
if (handlers.length === 0) return void 0;
|
|
143
|
+
const parts = [];
|
|
144
|
+
for (const h of handlers) {
|
|
145
|
+
try {
|
|
146
|
+
const result = await h(ctx);
|
|
147
|
+
if (result?.recalledContext && result.recalledContext.length > 0) {
|
|
148
|
+
parts.push(result.recalledContext);
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
process.stderr.write(
|
|
152
|
+
`[theokit-sdk] pre_user_send hook failed: ${err instanceof Error ? err.message : String(err)}
|
|
153
|
+
`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (parts.length === 0) return void 0;
|
|
158
|
+
let combined = parts.join("\n\n");
|
|
159
|
+
if (combined.length > maxRecallContextBytes) {
|
|
160
|
+
combined = `${combined.slice(0, maxRecallContextBytes)}
|
|
161
|
+
\u2026[truncated]`;
|
|
162
|
+
}
|
|
163
|
+
return combined;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Run all `post_assistant_reply` hooks. Fire-and-forget: errors are
|
|
167
|
+
* surfaced to stderr (EC-O) so a slow/broken sync never blocks the
|
|
168
|
+
* caller's `wait()`. Returns a Promise that callers may optionally
|
|
169
|
+
* await for tests; production code typically `void`s it.
|
|
170
|
+
*
|
|
171
|
+
* @internal
|
|
172
|
+
*/
|
|
173
|
+
async runPostAssistantReplyHooks(ctx) {
|
|
174
|
+
const handlers = this.#aggregated.hooks.get("post_assistant_reply") ?? [];
|
|
175
|
+
for (const h of handlers) {
|
|
176
|
+
try {
|
|
177
|
+
await h(ctx);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
process.stderr.write(
|
|
180
|
+
`[theokit-sdk] post_assistant_reply hook failed: ${err instanceof Error ? err.message : String(err)}
|
|
181
|
+
`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async #dispatchPlugin(plugin) {
|
|
187
|
+
if (plugin.kind === "general") {
|
|
188
|
+
const { ctx, registrations } = createPluginContext();
|
|
189
|
+
await plugin.register(ctx);
|
|
190
|
+
this.#merge(registrations);
|
|
191
|
+
} else if (plugin.kind === "model-provider") {
|
|
192
|
+
this.#aggregated.providerProfiles.push({
|
|
193
|
+
pluginName: plugin.name,
|
|
194
|
+
profile: plugin.profile
|
|
195
|
+
});
|
|
196
|
+
} else if (plugin.kind === "memory") {
|
|
197
|
+
this.#aggregated.memoryProviders.push({
|
|
198
|
+
pluginName: plugin.name,
|
|
199
|
+
createProvider: plugin.createProvider
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
#merge(r) {
|
|
204
|
+
this.#aggregated.tools.push(...r.tools);
|
|
205
|
+
this.#aggregated.commands.push(...r.commands);
|
|
206
|
+
for (const [hook, handlers] of r.hooks.entries()) {
|
|
207
|
+
const existing = this.#aggregated.hooks.get(hook) ?? [];
|
|
208
|
+
existing.push(...handlers);
|
|
209
|
+
this.#aggregated.hooks.set(hook, existing);
|
|
210
|
+
}
|
|
211
|
+
this.#aggregated.injected.push(...r.injected);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// src/internal/plugins/types.ts
|
|
216
|
+
function definePlugin(p) {
|
|
217
|
+
return p;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export { PluginManager, createPluginContext, definePlugin, runFireAndForgetHooks, runTransformHooks };
|
|
221
|
+
//# sourceMappingURL=index.js.map
|
|
222
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/internal/plugins/context.ts","../../../src/internal/plugins/lifecycle.ts","../../../src/internal/plugins/manager.ts","../../../src/internal/plugins/types.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * PluginContext implementation + dev-mode seal (T1.2, ADR D99).\n *\n * `createPluginContext()` returns a fresh `{ ctx, registrations }` pair\n * for each plugin. In dev mode (`NODE_ENV !== \"production\"`) the context\n * is wrapped in a Proxy that throws on `set`/`delete` to catch plugin\n * abuse early. In production the raw impl is returned (zero overhead).\n *\n * @internal\n */\n\nimport type { CustomTool } from \"../../types/agent.js\";\nimport type {\n CommandHandler,\n CommandOptions,\n HookHandler,\n HookName,\n PluginContext,\n} from \"./types.js\";\n\ninterface CommandEntry {\n name: string;\n handler: CommandHandler;\n description?: string;\n}\n\ninterface InjectedMessage {\n content: string;\n role: \"user\" | \"system\";\n}\n\nexport interface PluginRegistrations {\n tools: CustomTool[];\n commands: CommandEntry[];\n hooks: Map<HookName, HookHandler[]>;\n injected: InjectedMessage[];\n}\n\nexport function createPluginContext(): {\n ctx: PluginContext;\n registrations: PluginRegistrations;\n} {\n const registrations: PluginRegistrations = {\n tools: [],\n commands: [],\n hooks: new Map(),\n injected: [],\n };\n\n const impl: PluginContext = {\n registerTool(tool) {\n registrations.tools.push(tool);\n },\n registerCommand(name, handler, opts: CommandOptions = {}) {\n const entry: CommandEntry = { name, handler };\n if (opts.description !== undefined) entry.description = opts.description;\n registrations.commands.push(entry);\n },\n on(hook, handler) {\n // EC-2 fix: defense-in-depth. Plugin author can bypass TS via `as any`\n // and pass null/undefined; ignore + warn rather than crash the loop\n // downstream when `runPreToolCallHooks` tries to invoke the handler.\n if (typeof handler !== \"function\") {\n process.stderr.write(`[theokit-sdk] ignoring non-function handler for hook \"${hook}\"\\n`);\n return;\n }\n const existing = registrations.hooks.get(hook) ?? [];\n existing.push(handler);\n registrations.hooks.set(hook, existing);\n },\n injectMessage(content, role = \"user\") {\n registrations.injected.push({ content, role });\n },\n };\n\n const ctx = shouldSeal() ? sealContext(impl) : impl;\n return { ctx, registrations };\n}\n\nfunction shouldSeal(): boolean {\n return process.env.NODE_ENV !== \"production\";\n}\n\nfunction sealContext(impl: PluginContext): PluginContext {\n return new Proxy(impl, {\n set(_target, prop) {\n throw new Error(\n `[theokit-sdk] PluginContext is sealed — cannot set ${String(prop)}. ` +\n `Plugins must use registerTool, registerCommand, on, or injectMessage.`,\n );\n },\n deleteProperty(_target, prop) {\n throw new Error(`[theokit-sdk] PluginContext is sealed — cannot delete ${String(prop)}.`);\n },\n });\n}\n","/**\n * Hook dispatch helpers (T1.4, extracted from manager to keep both modules\n * small).\n *\n * - `runFireAndForgetHooks` — runs all handlers, swallows + logs throws,\n * no return value (post_tool_call, on_session_start/end, etc.).\n * - `runTransformHooks` — chains handlers, each can return a new value\n * that replaces the input for the next handler. `undefined` keeps the\n * current; `null` REPLACES current with null (EC-6 explicit).\n *\n * @internal\n */\n\nimport type { HookHandler } from \"./types.js\";\n\nexport async function runFireAndForgetHooks<C>(\n handlers: ReadonlyArray<HookHandler>,\n ctx: C,\n): Promise<void> {\n for (const h of handlers) {\n try {\n await (h as (c: C) => unknown)(ctx);\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[theokit-sdk] plugin hook threw (continuing): ${msg}\\n`);\n }\n }\n}\n\nexport async function runTransformHooks<T>(\n handlers: ReadonlyArray<HookHandler>,\n initial: T,\n): Promise<T> {\n let current = initial;\n for (const h of handlers) {\n try {\n const next = await (h as (c: T) => T | undefined)(current);\n // EC-6 explicit semantics: `undefined` = no-op; any other value\n // (including `null`) REPLACES current.\n if (next !== undefined) current = next;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`[theokit-sdk] plugin transform hook threw (continuing): ${msg}\\n`);\n }\n }\n return current;\n}\n","/**\n * PluginManager — constructs PluginContext per plugin, invokes register()\n * once, aggregates registrations + provider profiles + memory factories\n * (T1.3, ADRs D97-D101).\n *\n * @internal\n */\n\nimport type { ProviderProfile } from \"../providers/types.js\";\nimport { createPluginContext, type PluginRegistrations } from \"./context.js\";\nimport type {\n HookHandler,\n MemoryProviderFactory,\n Plugin,\n PostAssistantReplyContext,\n PreToolCallContext,\n PreToolCallDecision,\n PreUserSendContext,\n PreUserSendResult,\n} from \"./types.js\";\n\nexport interface ProviderEntry {\n pluginName: string;\n profile: ProviderProfile;\n}\n\nexport interface MemoryEntry {\n pluginName: string;\n createProvider: MemoryProviderFactory;\n}\n\nexport interface AggregatedPlugins {\n tools: PluginRegistrations[\"tools\"];\n commands: PluginRegistrations[\"commands\"];\n hooks: PluginRegistrations[\"hooks\"];\n injected: PluginRegistrations[\"injected\"];\n providerProfiles: ProviderEntry[];\n memoryProviders: MemoryEntry[];\n}\n\nexport class PluginManager {\n #aggregated: AggregatedPlugins = {\n tools: [],\n commands: [],\n hooks: new Map(),\n injected: [],\n providerProfiles: [],\n memoryProviders: [],\n };\n #initialized = false;\n\n async initialize(plugins: ReadonlyArray<Plugin>): Promise<void> {\n if (this.#initialized) {\n throw new Error(\"PluginManager.initialize called twice — register only once per process\");\n }\n this.#initialized = true;\n // EC-4: surface duplicate plugin names so operators notice. Two plugins\n // with the same name are usually a mistake (npm install with override).\n const seen = new Set<string>();\n for (const plugin of plugins) {\n if (seen.has(plugin.name)) {\n process.stderr.write(\n `[theokit-sdk] duplicate plugin name \"${plugin.name}\" — both will register independently\\n`,\n );\n }\n seen.add(plugin.name);\n await this.#dispatchPlugin(plugin);\n }\n }\n\n get aggregated(): Readonly<AggregatedPlugins> {\n return this.#aggregated;\n }\n\n /**\n * Run all `pre_tool_call` hooks; first decision with `block: true` wins.\n * D101: veto pattern — return `{ block: true, message }` makes the loop\n * surface a tool_result with `isError: false, content: message` so the\n * LLM can self-correct.\n */\n async runPreToolCallHooks(ctx: PreToolCallContext): Promise<PreToolCallDecision | undefined> {\n const handlers = this.#aggregated.hooks.get(\"pre_tool_call\") ?? [];\n for (const h of handlers) {\n const decision = (await (h as (c: PreToolCallContext) => unknown)(ctx)) as\n | PreToolCallDecision\n | undefined;\n if (decision !== undefined && (decision as { block?: boolean }).block === true) {\n return decision as PreToolCallDecision;\n }\n }\n return undefined;\n }\n\n /** Aggregated handlers for a given hook (read-only view). @internal */\n hooksFor(name: Parameters<AggregatedPlugins[\"hooks\"][\"get\"]>[0]): ReadonlyArray<HookHandler> {\n return this.#aggregated.hooks.get(name) ?? [];\n }\n\n /**\n * Run all `pre_user_send` hooks; concatenate non-empty `recalledContext`\n * outputs with `\\n\\n` and cap total length at `maxRecallContextBytes`\n * (EC-A). Per-handler failures are caught + logged to stderr (EC-8) so a\n * single broken adapter never blocks the LLM call (graceful degrade).\n *\n * Returns the assembled context (or undefined if empty after cap).\n *\n * @internal\n */\n // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: per-handler try/catch + EC-A cap + EC-8 isolation are 3 concerns that share state (parts buffer); splitting fragments the single-pass aggregation.\n async runPreUserSendHooks(\n ctx: PreUserSendContext,\n maxRecallContextBytes: number,\n ): Promise<string | undefined> {\n const handlers = this.#aggregated.hooks.get(\"pre_user_send\") ?? [];\n if (handlers.length === 0) return undefined;\n const parts: string[] = [];\n for (const h of handlers) {\n try {\n const result = (await (h as (c: PreUserSendContext) => unknown)(ctx)) as\n | PreUserSendResult\n | undefined;\n if (result?.recalledContext && result.recalledContext.length > 0) {\n parts.push(result.recalledContext);\n }\n } catch (err) {\n process.stderr.write(\n `[theokit-sdk] pre_user_send hook failed: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n }\n if (parts.length === 0) return undefined;\n let combined = parts.join(\"\\n\\n\");\n // EC-A: cap to prevent context-window blowout.\n if (combined.length > maxRecallContextBytes) {\n combined = `${combined.slice(0, maxRecallContextBytes)}\\n…[truncated]`;\n }\n return combined;\n }\n\n /**\n * Run all `post_assistant_reply` hooks. Fire-and-forget: errors are\n * surfaced to stderr (EC-O) so a slow/broken sync never blocks the\n * caller's `wait()`. Returns a Promise that callers may optionally\n * await for tests; production code typically `void`s it.\n *\n * @internal\n */\n async runPostAssistantReplyHooks(ctx: PostAssistantReplyContext): Promise<void> {\n const handlers = this.#aggregated.hooks.get(\"post_assistant_reply\") ?? [];\n for (const h of handlers) {\n try {\n await (h as (c: PostAssistantReplyContext) => unknown)(ctx);\n } catch (err) {\n process.stderr.write(\n `[theokit-sdk] post_assistant_reply hook failed: ${\n err instanceof Error ? err.message : String(err)\n }\\n`,\n );\n }\n }\n }\n\n async #dispatchPlugin(plugin: Plugin): Promise<void> {\n if (plugin.kind === \"general\") {\n const { ctx, registrations } = createPluginContext();\n await plugin.register(ctx);\n this.#merge(registrations);\n } else if (plugin.kind === \"model-provider\") {\n this.#aggregated.providerProfiles.push({\n pluginName: plugin.name,\n profile: plugin.profile,\n });\n } else if (plugin.kind === \"memory\") {\n this.#aggregated.memoryProviders.push({\n pluginName: plugin.name,\n createProvider: plugin.createProvider,\n });\n }\n }\n\n #merge(r: PluginRegistrations): void {\n this.#aggregated.tools.push(...r.tools);\n this.#aggregated.commands.push(...r.commands);\n for (const [hook, handlers] of r.hooks.entries()) {\n const existing = this.#aggregated.hooks.get(hook) ?? [];\n existing.push(...handlers);\n this.#aggregated.hooks.set(hook, existing);\n }\n this.#aggregated.injected.push(...r.injected);\n }\n}\n","/**\n * Plugin contract types (T1.1, ADRs D97-D101).\n *\n * Discriminated union by `kind`:\n * - `\"general\"` — registers tools/hooks/commands via `register(ctx)`.\n * - `\"model-provider\"` — declares a `ProviderProfile` consumed by router.\n * - `\"memory\"` — supplies a memory provider factory.\n *\n * Hooks are a fixed enum (D100) to prevent sprawl; `pre_tool_call` supports\n * veto via `{ block: true, message }` (D101) so plugins can implement safety\n * guards without crashing the agent loop.\n *\n * @public\n */\n\nimport type { CustomTool } from \"../../types/agent.js\";\nimport type { MemoryAdapter } from \"../../types/memory-adapter.js\";\nimport type { ProviderProfile } from \"../providers/types.js\";\n\nexport type HookName =\n | \"pre_tool_call\"\n | \"post_tool_call\"\n | \"pre_llm_call\"\n | \"post_llm_call\"\n | \"on_session_start\"\n | \"on_session_end\"\n | \"transform_tool_result\"\n | \"transform_llm_output\"\n // Memory adapter hooks (ADRs D141 / D145).\n | \"pre_user_send\"\n | \"post_assistant_reply\";\n\nexport interface PreToolCallContext {\n name: string;\n args: Record<string, unknown>;\n agentId: string;\n runId: string;\n}\n\nexport interface PreToolCallDecision {\n block: true;\n message: string;\n}\n\n/**\n * Context passed to `pre_user_send` hook handlers (ADR D145).\n *\n * @public\n */\nexport interface PreUserSendContext {\n prompt: string;\n agentId: string;\n runId: string;\n /** Caller-supplied memory context, flowing through from `AgentOptions.memoryContext`. */\n memoryContext?: import(\"../../types/memory-adapter.js\").MemoryContext;\n /** Forwarded `AbortSignal` so adapter recall HTTP can be cancelled mid-flight (EC-H). */\n signal?: AbortSignal;\n}\n\n/**\n * Optional result returned by `pre_user_send` handlers. The agent loop\n * concatenates `recalledContext` from all handlers and injects it as a\n * `<memory-context>...</memory-context>` block before the user prompt.\n *\n * @public\n */\nexport interface PreUserSendResult {\n recalledContext?: string;\n}\n\n/**\n * Context passed to `post_assistant_reply` hook handlers (ADR D145).\n * Fire-and-forget — exceptions are caught and surfaced to stderr; the\n * caller's `wait()` never blocks on this dispatch.\n *\n * @public\n */\nexport interface PostAssistantReplyContext {\n prompt: string;\n reply: string;\n agentId: string;\n runId: string;\n memoryContext?: import(\"../../types/memory-adapter.js\").MemoryContext;\n}\n\nexport type HookHandler = (ctx: unknown) => unknown | Promise<unknown>;\n\nexport type CommandHandler = (args: Record<string, unknown>) => Promise<string> | string;\n\nexport interface CommandOptions {\n description?: string;\n}\n\nexport interface PluginContext {\n /** Register a custom tool. Equivalent to passing in `AgentOptions.tools`. */\n registerTool(tool: CustomTool): void;\n /** Register a slash-command-style handler. Consumed by CLI/bot wrappers; NOT used by the agent loop. */\n registerCommand(name: string, handler: CommandHandler, opts?: CommandOptions): void;\n /** Attach a hook handler. `pre_tool_call` supports veto via `PreToolCallDecision`. */\n on(hook: HookName, handler: HookHandler): void;\n /** Inject a user/system message into the next agent turn. v1 supports only `on_session_start` context. */\n injectMessage(content: string, role?: \"user\" | \"system\"): void;\n}\n\ninterface BasePlugin {\n name: string;\n version: string;\n}\n\n/**\n * Memory provider factory shape (ADR D141). Returns a `MemoryAdapter`\n * (sync) or a Promise resolving to one (lazy HTTP probe / config load).\n *\n * Adapters live in `@theokit-memory-*` packages; the SDK never imports\n * them. Factory rejection is caught by the plugin manager and surfaced\n * as `ConfigurationError(code: \"plugin_factory_failed\")` (EC-F) — never\n * an unhandled rejection.\n *\n * @internal\n */\nexport type MemoryProviderFactory = (cwd: string) => MemoryAdapter | Promise<MemoryAdapter>;\n\nexport type Plugin =\n | (BasePlugin & {\n kind: \"general\";\n register: (ctx: PluginContext) => void | Promise<void>;\n })\n | (BasePlugin & {\n kind: \"model-provider\";\n profile: ProviderProfile;\n })\n | (BasePlugin & {\n kind: \"memory\";\n createProvider: MemoryProviderFactory;\n });\n\n/**\n * Identity helper for plugin authors. TS-only convenience — preserves\n * inferred type without forcing manual `Plugin` annotation.\n *\n * @public\n */\nexport function definePlugin<P extends Plugin>(p: P): P {\n return p;\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook dispatch helpers (T1.4, extracted from manager to keep both modules
|
|
3
|
+
* small).
|
|
4
|
+
*
|
|
5
|
+
* - `runFireAndForgetHooks` — runs all handlers, swallows + logs throws,
|
|
6
|
+
* no return value (post_tool_call, on_session_start/end, etc.).
|
|
7
|
+
* - `runTransformHooks` — chains handlers, each can return a new value
|
|
8
|
+
* that replaces the input for the next handler. `undefined` keeps the
|
|
9
|
+
* current; `null` REPLACES current with null (EC-6 explicit).
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function runFireAndForgetHooks<C>(handlers: ReadonlyArray<HookHandler>, ctx: C): Promise<void>;
|
|
14
|
+
export declare function runTransformHooks<T>(handlers: ReadonlyArray<HookHandler>, initial: T): Promise<T>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hook dispatch helpers (T1.4, extracted from manager to keep both modules
|
|
3
|
+
* small).
|
|
4
|
+
*
|
|
5
|
+
* - `runFireAndForgetHooks` — runs all handlers, swallows + logs throws,
|
|
6
|
+
* no return value (post_tool_call, on_session_start/end, etc.).
|
|
7
|
+
* - `runTransformHooks` — chains handlers, each can return a new value
|
|
8
|
+
* that replaces the input for the next handler. `undefined` keeps the
|
|
9
|
+
* current; `null` REPLACES current with null (EC-6 explicit).
|
|
10
|
+
*
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
export declare function runFireAndForgetHooks<C>(handlers: ReadonlyArray<HookHandler>, ctx: C): Promise<void>;
|
|
14
|
+
export declare function runTransformHooks<T>(handlers: ReadonlyArray<HookHandler>, initial: T): Promise<T>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PluginManager — constructs PluginContext per plugin, invokes register()
|
|
3
|
+
* once, aggregates registrations + provider profiles + memory factories
|
|
4
|
+
* (T1.3, ADRs D97-D101).
|
|
5
|
+
*
|
|
6
|
+
* @internal
|
|
7
|
+
*/
|
|
8
|
+
import { type PluginRegistrations } from "./context.js";
|
|
9
|
+
import type { MemoryProviderFactory, Plugin, PreToolCallContext, PreToolCallDecision } from "./types.js";
|
|
10
|
+
export interface ProviderEntry {
|
|
11
|
+
pluginName: string;
|
|
12
|
+
profile: ProviderProfile;
|
|
13
|
+
}
|
|
14
|
+
export interface MemoryEntry {
|
|
15
|
+
pluginName: string;
|
|
16
|
+
createProvider: MemoryProviderFactory;
|
|
17
|
+
}
|
|
18
|
+
export interface AggregatedPlugins {
|
|
19
|
+
tools: PluginRegistrations["tools"];
|
|
20
|
+
commands: PluginRegistrations["commands"];
|
|
21
|
+
hooks: PluginRegistrations["hooks"];
|
|
22
|
+
injected: PluginRegistrations["injected"];
|
|
23
|
+
providerProfiles: ProviderEntry[];
|
|
24
|
+
memoryProviders: MemoryEntry[];
|
|
25
|
+
}
|
|
26
|
+
export declare class PluginManager {
|
|
27
|
+
#private;
|
|
28
|
+
initialize(plugins: ReadonlyArray<Plugin>): Promise<void>;
|
|
29
|
+
get aggregated(): Readonly<AggregatedPlugins>;
|
|
30
|
+
/**
|
|
31
|
+
* Run all `pre_tool_call` hooks; first decision with `block: true` wins.
|
|
32
|
+
* D101: veto pattern — return `{ block: true, message }` makes the loop
|
|
33
|
+
* surface a tool_result with `isError: false, content: message` so the
|
|
34
|
+
* LLM can self-correct.
|
|
35
|
+
*/
|
|
36
|
+
runPreToolCallHooks(ctx: PreToolCallContext): Promise<PreToolCallDecision | undefined>;
|
|
37
|
+
}
|