@theokit/sdk 2.19.0 → 2.21.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/dist/a2a/index.cjs +611 -274
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +612 -275
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/a2a/types.d.cts +7 -0
  7. package/dist/a2a/types.d.ts +7 -0
  8. package/dist/agent-builder.d.ts +2 -1
  9. package/dist/agent-generate.d.ts +12 -0
  10. package/dist/client/index.cjs.map +1 -1
  11. package/dist/client/index.d.cts +5 -0
  12. package/dist/client/index.d.ts +5 -0
  13. package/dist/client/index.js.map +1 -1
  14. package/dist/client/theokit-client.d.cts +6 -0
  15. package/dist/client/theokit-client.d.ts +6 -0
  16. package/dist/client/types.d.cts +2 -0
  17. package/dist/client/types.d.ts +2 -0
  18. package/dist/create-skill.d.ts +29 -0
  19. package/dist/{cron-D_wK1S-0.d.cts → cron-YrmsszEN.d.cts} +110 -3
  20. package/dist/{cron-Cep07kTz.d.ts → cron-dpvtRoro.d.ts} +110 -3
  21. package/dist/cron.cjs +660 -370
  22. package/dist/cron.cjs.map +1 -1
  23. package/dist/cron.d.cts +3 -2
  24. package/dist/cron.d.ts +3 -2
  25. package/dist/cron.js +661 -371
  26. package/dist/cron.js.map +1 -1
  27. package/dist/{errors-5lj1EWgs.d.ts → errors-C4vZPqXf.d.ts} +2 -2
  28. package/dist/{errors-CE-lMBi2.d.cts → errors-DrcpYVfZ.d.cts} +2 -2
  29. package/dist/errors.d.cts +3 -2
  30. package/dist/eval.cjs +660 -370
  31. package/dist/eval.cjs.map +1 -1
  32. package/dist/eval.js +660 -370
  33. package/dist/eval.js.map +1 -1
  34. package/dist/generate-object.d.ts +19 -4
  35. package/dist/index.cjs +867 -371
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.d.cts +274 -16
  38. package/dist/index.d.ts +274 -16
  39. package/dist/index.js +863 -373
  40. package/dist/index.js.map +1 -1
  41. package/dist/internal/agent-loop/loop-types.d.ts +2 -0
  42. package/dist/internal/agent-loop/tool-result-guard.d.ts +1 -0
  43. package/dist/internal/llm/tool-result-content.d.ts +40 -0
  44. package/dist/internal/llm/types.d.ts +6 -1
  45. package/dist/internal/persistence/conversation-storage-fs.d.cts +3 -1
  46. package/dist/internal/persistence/conversation-storage-fs.d.ts +3 -1
  47. package/dist/internal/persistence/conversation-storage-memory.d.cts +3 -1
  48. package/dist/internal/persistence/conversation-storage-memory.d.ts +3 -1
  49. package/dist/internal/persistence/session-meta.d.cts +13 -0
  50. package/dist/internal/persistence/session-meta.d.ts +13 -0
  51. package/dist/internal/runtime/model-selection.d.ts +14 -0
  52. package/dist/internal/structured-output-helpers.d.ts +1 -1
  53. package/dist/permission-engine.d.ts +32 -1
  54. package/dist/{run-BgfBWX-z.d.cts → run-BMo8yRwK.d.cts} +262 -19
  55. package/dist/{run-BgfBWX-z.d.ts → run-BMo8yRwK.d.ts} +262 -19
  56. package/dist/stream-object.d.ts +2 -1
  57. package/dist/tool-error.d.ts +30 -0
  58. package/dist/types/agent-prims.d.ts +10 -8
  59. package/dist/types/agent.d.ts +22 -1
  60. package/dist/types/content-blocks.d.ts +47 -0
  61. package/dist/types/conversation-storage.d.ts +38 -0
  62. package/dist/types/index.d.ts +1 -0
  63. package/dist/types/messages.d.ts +2 -9
  64. package/dist/types/run-events.d.ts +84 -0
  65. package/dist/types/run.d.ts +115 -1
  66. package/dist/types/session.d.ts +99 -0
  67. package/dist/types/workflow.d.ts +7 -0
  68. package/dist/workflow.cjs +7 -2
  69. package/dist/workflow.cjs.map +1 -1
  70. package/dist/workflow.d.cts +2 -0
  71. package/dist/workflow.d.ts +2 -0
  72. package/dist/workflow.js +7 -2
  73. package/dist/workflow.js.map +1 -1
  74. package/package.json +3 -23
  75. package/dist/internal/observability/context.d.cts +0 -23
  76. package/dist/internal/observability/context.d.ts +0 -23
  77. package/dist/internal/observability/index.cjs +0 -38
  78. package/dist/internal/observability/index.cjs.map +0 -1
  79. package/dist/internal/observability/index.d.cts +0 -8
  80. package/dist/internal/observability/index.d.ts +0 -8
  81. package/dist/internal/observability/index.js +0 -33
  82. package/dist/internal/observability/index.js.map +0 -1
  83. package/dist/internal/plugins/index.cjs +0 -363
  84. package/dist/internal/plugins/index.cjs.map +0 -1
  85. package/dist/internal/plugins/index.js +0 -357
  86. package/dist/internal/plugins/index.js.map +0 -1
  87. package/dist/internal/workflow/index.d.ts +0 -12
  88. package/dist/server/adapter/index.d.cts +0 -8
  89. package/dist/server/adapter/index.d.ts +0 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theokit/sdk",
3
- "version": "2.19.0",
3
+ "version": "2.21.0",
4
4
  "description": "TypeScript SDK for the Theo agent harness — same surface, local or cloud.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/usetheo/theokit-sdk#readme",
@@ -228,26 +228,6 @@
228
228
  "default": "./dist/internal/persistence/index.cjs"
229
229
  }
230
230
  },
231
- "./internal/plugins": {
232
- "import": {
233
- "types": "./dist/internal/plugins/index.d.ts",
234
- "default": "./dist/internal/plugins/index.js"
235
- },
236
- "require": {
237
- "types": "./dist/internal/plugins/index.d.cts",
238
- "default": "./dist/internal/plugins/index.cjs"
239
- }
240
- },
241
- "./internal/observability": {
242
- "import": {
243
- "types": "./dist/internal/observability/index.d.ts",
244
- "default": "./dist/internal/observability/index.js"
245
- },
246
- "require": {
247
- "types": "./dist/internal/observability/index.d.cts",
248
- "default": "./dist/internal/observability/index.cjs"
249
- }
250
- },
251
231
  "./internal/security": {
252
232
  "import": {
253
233
  "types": "./dist/internal/security/index.d.ts",
@@ -375,8 +355,8 @@
375
355
  "typedoc": "^0.28.19",
376
356
  "ws": "^8.18.0",
377
357
  "zod": "^4.0.0",
378
- "@theokit/sdk-memory": "0.2.0",
379
- "@theokit/sdk-handoff": "0.1.0"
358
+ "@theokit/sdk-handoff": "0.1.0",
359
+ "@theokit/sdk-memory": "0.2.0"
380
360
  },
381
361
  "scripts": {
382
362
  "build": "tsup && cp src/internal/providers/provider-catalog.json dist/provider-catalog.json",
@@ -1,23 +0,0 @@
1
- /**
2
- * ObservabilityContext — public type for structured observability
3
- * across agent runtime, memory, and tool dispatch (T10.2, ADR D449).
4
- *
5
- * Consumers use this type to thread tracing/logging context through
6
- * custom tools and plugins.
7
- *
8
- * @public
9
- */
10
- export interface ObservabilityContext {
11
- /** Current trace ID (W3C Trace Context format). */
12
- traceId: string;
13
- /** Current span ID. */
14
- spanId: string;
15
- /** Parent span ID (undefined for root spans). */
16
- parentSpanId?: string;
17
- /** Structured log emitter. */
18
- log: (level: "debug" | "info" | "warn" | "error", message: string, attrs?: Record<string, unknown>) => void;
19
- /** Record a counter metric. */
20
- counter: (name: string, value?: number, attrs?: Record<string, unknown>) => void;
21
- /** Record a histogram metric. */
22
- histogram: (name: string, value: number, attrs?: Record<string, unknown>) => void;
23
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * ObservabilityContext — public type for structured observability
3
- * across agent runtime, memory, and tool dispatch (T10.2, ADR D449).
4
- *
5
- * Consumers use this type to thread tracing/logging context through
6
- * custom tools and plugins.
7
- *
8
- * @public
9
- */
10
- export interface ObservabilityContext {
11
- /** Current trace ID (W3C Trace Context format). */
12
- traceId: string;
13
- /** Current span ID. */
14
- spanId: string;
15
- /** Parent span ID (undefined for root spans). */
16
- parentSpanId?: string;
17
- /** Structured log emitter. */
18
- log: (level: "debug" | "info" | "warn" | "error", message: string, attrs?: Record<string, unknown>) => void;
19
- /** Record a counter metric. */
20
- counter: (name: string, value?: number, attrs?: Record<string, unknown>) => void;
21
- /** Record a histogram metric. */
22
- histogram: (name: string, value: number, attrs?: Record<string, unknown>) => void;
23
- }
@@ -1,38 +0,0 @@
1
- 'use strict';
2
-
3
- var module$1 = require('module');
4
-
5
- var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
6
- // src/internal/observability/tracer-loader.ts
7
- var noopSpan = {
8
- setAttribute: () => noopSpan,
9
- end: () => void 0
10
- };
11
- var tracerCache = /* @__PURE__ */ new Map();
12
- function getTracer(name, version = "1.0.0") {
13
- const cached = tracerCache.get(name);
14
- if (cached !== void 0) return cached.tracer ?? void 0;
15
- try {
16
- const r = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
17
- const otel = r("@opentelemetry/api");
18
- if (otel.trace?.getTracer === void 0) {
19
- tracerCache.set(name, { tracer: null });
20
- return void 0;
21
- }
22
- const tracer = otel.trace.getTracer(name, version);
23
- tracerCache.set(name, { tracer });
24
- return tracer;
25
- } catch {
26
- tracerCache.set(name, { tracer: null });
27
- return void 0;
28
- }
29
- }
30
- function resetTracerCacheForTests() {
31
- tracerCache.clear();
32
- }
33
-
34
- exports.getTracer = getTracer;
35
- exports.noopSpan = noopSpan;
36
- exports.resetTracerCacheForTests = resetTracerCacheForTests;
37
- //# sourceMappingURL=index.cjs.map
38
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/internal/observability/tracer-loader.ts"],"names":["createRequire"],"mappings":";;;;;;AAgBO,IAAM,QAAA,GAAqB;AAAA,EAChC,cAAc,MAAM,QAAA;AAAA,EACpB,KAAK,MAAM;AACb;AAaA,IAAM,WAAA,uBAAkB,GAAA,EAAwB;AAEzC,SAAS,SAAA,CAAU,IAAA,EAAc,OAAA,GAAU,OAAA,EAAiC;AACjF,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,CAAI,IAAI,CAAA;AACnC,EAAA,IAAI,MAAA,KAAW,MAAA,EAAW,OAAO,MAAA,CAAO,MAAA,IAAU,MAAA;AAClD,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAIA,sBAAA,CAAc,2PAAe,CAAA;AACvC,IAAA,MAAM,IAAA,GAAO,EAAE,oBAAoB,CAAA;AAGnC,IAAA,IAAI,IAAA,CAAK,KAAA,EAAO,SAAA,KAAc,KAAA,CAAA,EAAW;AACvC,MAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAM,CAAA;AACtC,MAAA,OAAO,KAAA,CAAA;AAAA,IACT;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,MAAM,OAAO,CAAA;AACjD,IAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,CAAA;AAChC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAM,CAAA;AACtC,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEO,SAAS,wBAAA,GAAiC;AAC/C,EAAA,WAAA,CAAY,KAAA,EAAM;AACpB","file":"index.cjs","sourcesContent":["/**\n * Shared OTel tracer loader (extracted to eliminate cross-module clones —\n * was previously inlined in cache/, workflow/, eval/, handoff/ telemetry\n * modules). Lazy-loads `@opentelemetry/api` via `createRequire`; users\n * without OTel installed pay zero cost.\n *\n * @internal\n */\n\nimport { createRequire } from \"node:module\";\n\nexport interface SpanLike {\n setAttribute(key: string, value: string | number | boolean): SpanLike;\n end(): void;\n}\n\nexport const noopSpan: SpanLike = {\n setAttribute: () => noopSpan,\n end: () => undefined,\n};\n\nexport interface TracerLike {\n startSpan(\n name: string,\n options?: { attributes?: Record<string, string | number | boolean> },\n ): SpanLike;\n}\n\ninterface CacheEntry {\n tracer: TracerLike | null;\n}\n\nconst tracerCache = new Map<string, CacheEntry>();\n\nexport function getTracer(name: string, version = \"1.0.0\"): TracerLike | undefined {\n const cached = tracerCache.get(name);\n if (cached !== undefined) return cached.tracer ?? undefined;\n try {\n const r = createRequire(import.meta.url);\n const otel = r(\"@opentelemetry/api\") as {\n trace?: { getTracer: (n: string, v?: string) => TracerLike };\n };\n if (otel.trace?.getTracer === undefined) {\n tracerCache.set(name, { tracer: null });\n return undefined;\n }\n const tracer = otel.trace.getTracer(name, version);\n tracerCache.set(name, { tracer });\n return tracer;\n } catch {\n tracerCache.set(name, { tracer: null });\n return undefined;\n }\n}\n\nexport function resetTracerCacheForTests(): void {\n tracerCache.clear();\n}\n"]}
@@ -1,8 +0,0 @@
1
- /**
2
- * Barrel for observability primitives shared across subsystems
3
- * (cache, memory, etc.) — exposed via `@theokit/sdk/internal/observability`
4
- * sub-path (SDK 2.0 Phase 3 prep).
5
- *
6
- * @internal — semver-exempt; surface may change in patch releases.
7
- */
8
- export * from "./tracer-loader.js";
@@ -1,8 +0,0 @@
1
- /**
2
- * Barrel for observability primitives shared across subsystems
3
- * (cache, memory, etc.) — exposed via `@theokit/sdk/internal/observability`
4
- * sub-path (SDK 2.0 Phase 3 prep).
5
- *
6
- * @internal — semver-exempt; surface may change in patch releases.
7
- */
8
- export * from "./tracer-loader.js";
@@ -1,33 +0,0 @@
1
- import { createRequire } from 'module';
2
-
3
- // src/internal/observability/tracer-loader.ts
4
- var noopSpan = {
5
- setAttribute: () => noopSpan,
6
- end: () => void 0
7
- };
8
- var tracerCache = /* @__PURE__ */ new Map();
9
- function getTracer(name, version = "1.0.0") {
10
- const cached = tracerCache.get(name);
11
- if (cached !== void 0) return cached.tracer ?? void 0;
12
- try {
13
- const r = createRequire(import.meta.url);
14
- const otel = r("@opentelemetry/api");
15
- if (otel.trace?.getTracer === void 0) {
16
- tracerCache.set(name, { tracer: null });
17
- return void 0;
18
- }
19
- const tracer = otel.trace.getTracer(name, version);
20
- tracerCache.set(name, { tracer });
21
- return tracer;
22
- } catch {
23
- tracerCache.set(name, { tracer: null });
24
- return void 0;
25
- }
26
- }
27
- function resetTracerCacheForTests() {
28
- tracerCache.clear();
29
- }
30
-
31
- export { getTracer, noopSpan, resetTracerCacheForTests };
32
- //# sourceMappingURL=index.js.map
33
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../../src/internal/observability/tracer-loader.ts"],"names":[],"mappings":";;;AAgBO,IAAM,QAAA,GAAqB;AAAA,EAChC,cAAc,MAAM,QAAA;AAAA,EACpB,KAAK,MAAM;AACb;AAaA,IAAM,WAAA,uBAAkB,GAAA,EAAwB;AAEzC,SAAS,SAAA,CAAU,IAAA,EAAc,OAAA,GAAU,OAAA,EAAiC;AACjF,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAA,CAAI,IAAI,CAAA;AACnC,EAAA,IAAI,MAAA,KAAW,MAAA,EAAW,OAAO,MAAA,CAAO,MAAA,IAAU,MAAA;AAClD,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA;AACvC,IAAA,MAAM,IAAA,GAAO,EAAE,oBAAoB,CAAA;AAGnC,IAAA,IAAI,IAAA,CAAK,KAAA,EAAO,SAAA,KAAc,KAAA,CAAA,EAAW;AACvC,MAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAM,CAAA;AACtC,MAAA,OAAO,KAAA,CAAA;AAAA,IACT;AACA,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,SAAA,CAAU,MAAM,OAAO,CAAA;AACjD,IAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,CAAA;AAChC,IAAA,OAAO,MAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,WAAA,CAAY,GAAA,CAAI,IAAA,EAAM,EAAE,MAAA,EAAQ,MAAM,CAAA;AACtC,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEO,SAAS,wBAAA,GAAiC;AAC/C,EAAA,WAAA,CAAY,KAAA,EAAM;AACpB","file":"index.js","sourcesContent":["/**\n * Shared OTel tracer loader (extracted to eliminate cross-module clones —\n * was previously inlined in cache/, workflow/, eval/, handoff/ telemetry\n * modules). Lazy-loads `@opentelemetry/api` via `createRequire`; users\n * without OTel installed pay zero cost.\n *\n * @internal\n */\n\nimport { createRequire } from \"node:module\";\n\nexport interface SpanLike {\n setAttribute(key: string, value: string | number | boolean): SpanLike;\n end(): void;\n}\n\nexport const noopSpan: SpanLike = {\n setAttribute: () => noopSpan,\n end: () => undefined,\n};\n\nexport interface TracerLike {\n startSpan(\n name: string,\n options?: { attributes?: Record<string, string | number | boolean> },\n ): SpanLike;\n}\n\ninterface CacheEntry {\n tracer: TracerLike | null;\n}\n\nconst tracerCache = new Map<string, CacheEntry>();\n\nexport function getTracer(name: string, version = \"1.0.0\"): TracerLike | undefined {\n const cached = tracerCache.get(name);\n if (cached !== undefined) return cached.tracer ?? undefined;\n try {\n const r = createRequire(import.meta.url);\n const otel = r(\"@opentelemetry/api\") as {\n trace?: { getTracer: (n: string, v?: string) => TracerLike };\n };\n if (otel.trace?.getTracer === undefined) {\n tracerCache.set(name, { tracer: null });\n return undefined;\n }\n const tracer = otel.trace.getTracer(name, version);\n tracerCache.set(name, { tracer });\n return tracer;\n } catch {\n tracerCache.set(name, { tracer: null });\n return undefined;\n }\n}\n\nexport function resetTracerCacheForTests(): void {\n tracerCache.clear();\n}\n"]}
@@ -1,363 +0,0 @@
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/errors.ts
81
- var TheokitAgentError = class extends Error {
82
- name = "TheokitAgentError";
83
- isRetryable;
84
- code;
85
- protoErrorCode;
86
- metadata;
87
- constructor(message, options = {}) {
88
- super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
89
- this.isRetryable = options.isRetryable ?? false;
90
- if (options.code !== void 0) this.code = options.code;
91
- if (options.protoErrorCode !== void 0) this.protoErrorCode = options.protoErrorCode;
92
- if (options.metadata !== void 0) this.metadata = options.metadata;
93
- }
94
- };
95
- var ConfigurationError = class extends TheokitAgentError {
96
- name = "ConfigurationError";
97
- constructor(message, options = {}) {
98
- super(message, { ...options, isRetryable: false });
99
- }
100
- };
101
-
102
- // src/internal/plugins/manager.ts
103
- var PluginManager = class {
104
- #aggregated = {
105
- tools: [],
106
- commands: [],
107
- hooks: /* @__PURE__ */ new Map(),
108
- injected: [],
109
- providerProfiles: [],
110
- memoryProviders: []
111
- };
112
- #initialized = false;
113
- // #68 — registrations of plugins added post-init via `register()`, keyed by
114
- // plugin name so a re-register REPLACES (not appends) the prior hooks.
115
- #byName = /* @__PURE__ */ new Map();
116
- async initialize(plugins) {
117
- if (this.#initialized) {
118
- throw new Error("PluginManager.initialize called twice \u2014 register only once per process");
119
- }
120
- this.#initialized = true;
121
- const seen = /* @__PURE__ */ new Set();
122
- for (const plugin of plugins) {
123
- if (seen.has(plugin.name)) {
124
- process.stderr.write(
125
- `[theokit-sdk] duplicate plugin name "${plugin.name}" \u2014 both will register independently
126
- `
127
- );
128
- }
129
- seen.add(plugin.name);
130
- await this.#dispatchPlugin(plugin);
131
- }
132
- }
133
- /**
134
- * #68 — register a single `general` plugin AFTER `initialize()` has run.
135
- *
136
- * The bulk `initialize()` is single-shot (one call per process); late
137
- * registration is a distinct, named operation used by adapters that install
138
- * a plugin per-session/per-request (e.g. the ACP permission veto, which is
139
- * installed once the permission mode + connection are known — after the
140
- * agent's own plugins were already initialized).
141
- *
142
- * Idempotent by plugin NAME: re-registering a plugin with the same name
143
- * REPLACES its prior hooks/tools instead of appending duplicates (the ACP
144
- * permission plugin is re-installed on every prompt).
145
- *
146
- * Only `general` plugins may be registered late — model-provider / memory
147
- * plugins are resolved during the bulk init and cannot be added afterwards.
148
- */
149
- async register(plugin) {
150
- if (plugin.kind !== "general") {
151
- throw new ConfigurationError(
152
- `late register supports general plugins only (got "${plugin.kind}" for "${plugin.name}")`,
153
- { code: "plugin_late_register_kind" }
154
- );
155
- }
156
- const prior = this.#byName.get(plugin.name);
157
- if (prior !== void 0) this.#unmerge(prior);
158
- const { ctx, registrations } = createPluginContext();
159
- await plugin.register(ctx);
160
- this.#byName.set(plugin.name, registrations);
161
- this.#merge(registrations);
162
- }
163
- get aggregated() {
164
- return this.#aggregated;
165
- }
166
- /**
167
- * Run all `pre_tool_call` hooks; first decision with `block: true` wins.
168
- * D101: veto pattern — return `{ block: true, message }` makes the loop
169
- * surface a tool_result with `isError: false, content: message` so the
170
- * LLM can self-correct.
171
- */
172
- async runPreToolCallHooks(ctx) {
173
- const handlers = this.#aggregated.hooks.get("pre_tool_call") ?? [];
174
- for (const h of handlers) {
175
- const decision = await h(ctx);
176
- if (decision !== void 0 && decision.block === true) {
177
- return decision;
178
- }
179
- }
180
- return void 0;
181
- }
182
- /** Aggregated handlers for a given hook (read-only view). @internal */
183
- hooksFor(name) {
184
- return this.#aggregated.hooks.get(name) ?? [];
185
- }
186
- /**
187
- * Run all `pre_user_send` hooks; concatenate non-empty `recalledContext`
188
- * outputs with `\n\n` and cap total length at `maxRecallContextBytes`
189
- * (EC-A). Per-handler failures are caught + logged to stderr (EC-8) so a
190
- * single broken adapter never blocks the LLM call (graceful degrade).
191
- *
192
- * Returns the assembled context (or undefined if empty after cap).
193
- *
194
- * @internal
195
- */
196
- // 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.
197
- async runPreUserSendHooks(ctx, maxRecallContextBytes) {
198
- const handlers = this.#aggregated.hooks.get("pre_user_send") ?? [];
199
- if (handlers.length === 0) return void 0;
200
- const parts = [];
201
- for (const h of handlers) {
202
- try {
203
- const result = await h(ctx);
204
- if (result?.recalledContext && result.recalledContext.length > 0) {
205
- parts.push(result.recalledContext);
206
- }
207
- } catch (err) {
208
- process.stderr.write(
209
- `[theokit-sdk] pre_user_send hook failed: ${err instanceof Error ? err.message : String(err)}
210
- `
211
- );
212
- }
213
- }
214
- if (parts.length === 0) return void 0;
215
- let combined = parts.join("\n\n");
216
- if (combined.length > maxRecallContextBytes) {
217
- combined = `${combined.slice(0, maxRecallContextBytes)}
218
- \u2026[truncated]`;
219
- }
220
- return combined;
221
- }
222
- /**
223
- * Run all `post_assistant_reply` hooks. Fire-and-forget: errors are
224
- * surfaced to stderr (EC-O) so a slow/broken sync never blocks the
225
- * caller's `wait()`. Returns a Promise that callers may optionally
226
- * await for tests; production code typically `void`s it.
227
- *
228
- * @internal
229
- */
230
- async runPostAssistantReplyHooks(ctx) {
231
- const handlers = this.#aggregated.hooks.get("post_assistant_reply") ?? [];
232
- for (const h of handlers) {
233
- try {
234
- await h(ctx);
235
- } catch (err) {
236
- process.stderr.write(
237
- `[theokit-sdk] post_assistant_reply hook failed: ${err instanceof Error ? err.message : String(err)}
238
- `
239
- );
240
- }
241
- }
242
- }
243
- // #65 — the previously-dead hooks, now wired. Fire-and-forget hooks run
244
- // in order (per-handler errors logged, never thrown); transform hooks fold
245
- // over the payload (a handler returning a value replaces it).
246
- /** @internal */
247
- async #runFireAndForget(name, ctx) {
248
- for (const h of this.#aggregated.hooks.get(name) ?? []) {
249
- try {
250
- await h(ctx);
251
- } catch (err) {
252
- process.stderr.write(
253
- `[theokit-sdk] ${name} hook failed: ${err instanceof Error ? err.message : String(err)}
254
- `
255
- );
256
- }
257
- }
258
- }
259
- /** @internal — fold: each handler may return a replacement payload; a throw keeps the prior value. */
260
- async #runTransform(name, payload, ctx) {
261
- let current = payload;
262
- for (const h of this.#aggregated.hooks.get(name) ?? []) {
263
- try {
264
- const out = await h(current, ctx);
265
- if (out !== void 0) current = out;
266
- } catch (err) {
267
- process.stderr.write(
268
- `[theokit-sdk] ${name} hook failed: ${err instanceof Error ? err.message : String(err)}
269
- `
270
- );
271
- }
272
- }
273
- return current;
274
- }
275
- /** #65 — fired after a tool call completes. @internal */
276
- runPostToolCallHooks(ctx) {
277
- return this.#runFireAndForget("post_tool_call", ctx);
278
- }
279
- /** #65 — fired before / after each LLM turn. @internal */
280
- runPreLlmCallHooks(ctx) {
281
- return this.#runFireAndForget("pre_llm_call", ctx);
282
- }
283
- runPostLlmCallHooks(ctx) {
284
- return this.#runFireAndForget("post_llm_call", ctx);
285
- }
286
- /** #65 — fired at run start / end. @internal */
287
- runOnSessionStartHooks(ctx) {
288
- return this.#runFireAndForget("on_session_start", ctx);
289
- }
290
- runOnSessionEndHooks(ctx) {
291
- return this.#runFireAndForget("on_session_end", ctx);
292
- }
293
- /** #65/#57 — transform tool results before they reach the LLM (the #57 seam). @internal */
294
- runTransformToolResultHooks(results, ctx) {
295
- return this.#runTransform("transform_tool_result", results, ctx);
296
- }
297
- /** #65 — transform the LLM output text before it is consumed. @internal */
298
- runTransformLlmOutputHooks(output, ctx) {
299
- return this.#runTransform("transform_llm_output", output, ctx);
300
- }
301
- async #dispatchPlugin(plugin) {
302
- if (plugin.kind === "general") {
303
- const { ctx, registrations } = createPluginContext();
304
- await plugin.register(ctx);
305
- this.#merge(registrations);
306
- } else if (plugin.kind === "model-provider") {
307
- this.#aggregated.providerProfiles.push({
308
- pluginName: plugin.name,
309
- profile: plugin.profile
310
- });
311
- } else if (plugin.kind === "memory") {
312
- this.#aggregated.memoryProviders.push({
313
- pluginName: plugin.name,
314
- createProvider: plugin.createProvider
315
- });
316
- }
317
- }
318
- #merge(r) {
319
- this.#aggregated.tools.push(...r.tools);
320
- this.#aggregated.commands.push(...r.commands);
321
- for (const [hook, handlers] of r.hooks.entries()) {
322
- const existing = this.#aggregated.hooks.get(hook) ?? [];
323
- existing.push(...handlers);
324
- this.#aggregated.hooks.set(hook, existing);
325
- }
326
- this.#aggregated.injected.push(...r.injected);
327
- }
328
- /**
329
- * #68 — inverse of #merge: remove a prior registration's contributions from
330
- * the aggregated view by object identity. Used by `register()` to replace a
331
- * same-named plugin's hooks/tools instead of accumulating duplicates.
332
- */
333
- #unmerge(r) {
334
- removeAll(this.#aggregated.tools, r.tools);
335
- removeAll(this.#aggregated.commands, r.commands);
336
- removeAll(this.#aggregated.injected, r.injected);
337
- for (const [hook, handlers] of r.hooks.entries()) {
338
- const existing = this.#aggregated.hooks.get(hook);
339
- if (existing === void 0) continue;
340
- removeAll(existing, handlers);
341
- if (existing.length === 0) this.#aggregated.hooks.delete(hook);
342
- }
343
- }
344
- };
345
- function removeAll(arr, toRemove) {
346
- for (const item of toRemove) {
347
- const idx = arr.indexOf(item);
348
- if (idx !== -1) arr.splice(idx, 1);
349
- }
350
- }
351
-
352
- // src/internal/plugins/types.ts
353
- function definePlugin(p) {
354
- return p;
355
- }
356
-
357
- exports.PluginManager = PluginManager;
358
- exports.createPluginContext = createPluginContext;
359
- exports.definePlugin = definePlugin;
360
- exports.runFireAndForgetHooks = runFireAndForgetHooks;
361
- exports.runTransformHooks = runTransformHooks;
362
- //# sourceMappingURL=index.cjs.map
363
- //# sourceMappingURL=index.cjs.map