theorum 1.0.0 → 1.1.3

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 (204) hide show
  1. package/README.md +81 -25
  2. package/esm/mod.d.ts +48 -29
  3. package/esm/mod.js +37 -24
  4. package/esm/src/cli/commands/bench.js +13 -16
  5. package/esm/src/cli/commands/fuzz-canary.js +25 -29
  6. package/esm/src/cli/commands/guardrails-eval.d.ts +14 -0
  7. package/esm/src/cli/commands/guardrails-eval.js +15 -0
  8. package/esm/src/cli/commands/profile.js +12 -3
  9. package/esm/src/cli/commands/run.js +8 -9
  10. package/esm/src/cli/commands/test.js +8 -8
  11. package/esm/src/cli/event-log.d.ts +1 -1
  12. package/esm/src/cli/index.js +12 -0
  13. package/esm/src/cli/matrix/synthesizer.d.ts +6 -6
  14. package/esm/src/cli/matrix/synthesizer.js +23 -22
  15. package/esm/src/guardrails/canary-gate.d.ts +2 -1
  16. package/esm/src/guardrails/canary-gate.js +2 -1
  17. package/esm/src/guardrails/canary.d.ts +9 -1
  18. package/esm/src/guardrails/canary.js +21 -10
  19. package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +1 -0
  20. package/esm/src/guardrails/corpus/fuzz-inbound.js +12 -15
  21. package/esm/src/guardrails/corpus/inbound-payloads.js +1 -0
  22. package/esm/src/guardrails/corpus/live-attacks.js +0 -1
  23. package/esm/src/guardrails/corpus/mod.d.ts +1 -0
  24. package/esm/src/guardrails/corpus/secrets.d.ts +1 -0
  25. package/esm/src/guardrails/corpus/secrets.js +1 -0
  26. package/esm/src/guardrails/corpus/strings.d.ts +1 -0
  27. package/esm/src/guardrails/corpus/strings.js +1 -0
  28. package/esm/src/guardrails/corpus/types.d.ts +1 -0
  29. package/esm/src/guardrails/egress.d.ts +26 -3
  30. package/esm/src/guardrails/egress.js +69 -18
  31. package/esm/src/guardrails/error.d.ts +14 -23
  32. package/esm/src/guardrails/error.js +86 -77
  33. package/esm/src/guardrails/eval/corpus.d.ts +108 -0
  34. package/esm/src/guardrails/eval/corpus.js +978 -0
  35. package/esm/src/guardrails/eval/mod.d.ts +51 -0
  36. package/esm/src/guardrails/eval/mod.js +133 -0
  37. package/esm/src/guardrails/eval/score.d.ts +66 -0
  38. package/esm/src/guardrails/eval/score.js +114 -0
  39. package/esm/src/guardrails/events.d.ts +25 -0
  40. package/esm/src/guardrails/events.js +56 -0
  41. package/esm/src/guardrails/hits.d.ts +24 -0
  42. package/esm/src/guardrails/hits.js +45 -0
  43. package/esm/src/guardrails/lexicon.d.ts +39 -0
  44. package/esm/src/guardrails/lexicon.js +200 -0
  45. package/esm/src/guardrails/live-outbound-gate.d.ts +15 -13
  46. package/esm/src/guardrails/live-outbound-gate.js +131 -89
  47. package/esm/src/guardrails/mod.d.ts +19 -4
  48. package/esm/src/guardrails/mod.js +12 -3
  49. package/esm/src/guardrails/network.d.ts +19 -0
  50. package/esm/src/guardrails/network.js +234 -0
  51. package/esm/src/guardrails/policy.d.ts +35 -0
  52. package/esm/src/guardrails/policy.js +50 -0
  53. package/esm/src/guardrails/progressive-yield.d.ts +51 -0
  54. package/esm/src/guardrails/progressive-yield.js +98 -0
  55. package/esm/src/guardrails/quota.d.ts +17 -3
  56. package/esm/src/guardrails/quota.js +18 -4
  57. package/esm/src/guardrails/sanitize.d.ts +36 -6
  58. package/esm/src/guardrails/sanitize.js +152 -60
  59. package/esm/src/guardrails/serialize.d.ts +35 -0
  60. package/esm/src/guardrails/serialize.js +58 -0
  61. package/esm/src/guardrails/testing.d.ts +7 -0
  62. package/esm/src/guardrails/testing.js +4 -0
  63. package/esm/src/guardrails/theorum-error.d.ts +12 -0
  64. package/esm/src/guardrails/theorum-error.js +15 -0
  65. package/esm/src/guardrails/tool-directives.d.ts +48 -0
  66. package/esm/src/guardrails/tool-directives.js +124 -0
  67. package/esm/src/guardrails/tool-result.d.ts +93 -0
  68. package/esm/src/guardrails/tool-result.js +276 -0
  69. package/esm/src/guardrails/types.d.ts +291 -0
  70. package/esm/src/guardrails/types.js +72 -0
  71. package/esm/src/host/client-turn.js +4 -0
  72. package/esm/src/host/mint-trace.d.ts +1 -1
  73. package/esm/src/kernel/auth/crypto.d.ts +42 -0
  74. package/esm/src/kernel/auth/crypto.js +106 -0
  75. package/esm/src/kernel/auth/mod.d.ts +11 -0
  76. package/esm/src/kernel/auth/mod.js +11 -0
  77. package/esm/src/kernel/auth/oauth.d.ts +47 -0
  78. package/esm/src/kernel/auth/oauth.js +278 -0
  79. package/esm/src/kernel/auth/types.d.ts +133 -0
  80. package/esm/src/kernel/auth/types.js +13 -0
  81. package/esm/src/kernel/engine/delta.js +43 -2
  82. package/esm/src/kernel/engine/live-inbound.d.ts +15 -3
  83. package/esm/src/kernel/engine/live-inbound.js +22 -8
  84. package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
  85. package/esm/src/kernel/engine/live-ingress.js +47 -0
  86. package/esm/src/kernel/engine/repair.js +13 -12
  87. package/esm/src/kernel/engine/runner/gates.js +127 -40
  88. package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
  89. package/esm/src/kernel/engine/runner/mod.js +182 -43
  90. package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
  91. package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
  92. package/esm/src/kernel/engine/runner/stages.js +89 -0
  93. package/esm/src/kernel/engine/runner/state.d.ts +24 -0
  94. package/esm/src/kernel/engine/runner/steps.js +128 -61
  95. package/esm/src/kernel/engine/runner/stream.d.ts +9 -2
  96. package/esm/src/kernel/engine/runner/stream.js +114 -55
  97. package/esm/src/kernel/engine/session/mod.d.ts +3 -1
  98. package/esm/src/kernel/engine/session/mod.js +386 -34
  99. package/esm/src/kernel/interaction-parts.d.ts +14 -0
  100. package/esm/src/kernel/interaction-parts.js +23 -0
  101. package/esm/src/kernel/mod.d.ts +19 -7
  102. package/esm/src/kernel/mod.js +10 -5
  103. package/esm/src/kernel/profile-graph.d.ts +159 -0
  104. package/esm/src/kernel/profile-graph.js +156 -0
  105. package/esm/src/kernel/registry/attachments.d.ts +10 -10
  106. package/esm/src/kernel/registry/attachments.js +29 -26
  107. package/esm/src/kernel/registry/catalog.d.ts +25 -11
  108. package/esm/src/kernel/registry/catalog.js +59 -24
  109. package/esm/src/kernel/registry/ingress.js +34 -22
  110. package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
  111. package/esm/src/kernel/registry/profile-outputs.js +8 -0
  112. package/esm/src/kernel/registry/profiles.d.ts +34 -14
  113. package/esm/src/kernel/registry/profiles.js +306 -59
  114. package/esm/src/kernel/registry/provider-request.js +2 -0
  115. package/esm/src/kernel/registry/resolve.d.ts +7 -6
  116. package/esm/src/kernel/registry/resolve.js +102 -117
  117. package/esm/src/kernel/registry/schemas.js +1 -1
  118. package/esm/src/kernel/registry/sole-model.d.ts +8 -0
  119. package/esm/src/kernel/registry/sole-model.js +10 -0
  120. package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
  121. package/esm/src/kernel/registry/system-prompt.js +40 -0
  122. package/esm/src/kernel/registry/system-role.d.ts +8 -0
  123. package/esm/src/kernel/registry/system-role.js +14 -0
  124. package/esm/src/kernel/registry/vault.d.ts +2 -2
  125. package/esm/src/kernel/registry/vault.js +4 -4
  126. package/esm/src/kernel/schema.d.ts +97 -11
  127. package/esm/src/kernel/schema.js +256 -111
  128. package/esm/src/kernel/stages.d.ts +175 -0
  129. package/esm/src/kernel/stages.js +476 -0
  130. package/esm/src/kernel/stop.d.ts +65 -11
  131. package/esm/src/kernel/stop.js +46 -11
  132. package/esm/src/kernel/tools/events.d.ts +41 -0
  133. package/esm/src/kernel/tools/events.js +71 -0
  134. package/esm/src/kernel/tools/execute.d.ts +63 -24
  135. package/esm/src/kernel/tools/execute.js +475 -224
  136. package/esm/src/kernel/tools/harness.js +16 -14
  137. package/esm/src/kernel/tools/invoke.js +26 -8
  138. package/esm/src/kernel/tools/mod.d.ts +3 -1
  139. package/esm/src/kernel/tools/mod.js +2 -1
  140. package/esm/src/kernel/tools/permission.d.ts +15 -0
  141. package/esm/src/kernel/tools/permission.js +47 -0
  142. package/esm/src/kernel/tools/project.js +5 -3
  143. package/esm/src/kernel/tools/registry.js +20 -10
  144. package/esm/src/kernel/tools/remote.d.ts +94 -0
  145. package/esm/src/kernel/tools/remote.js +577 -0
  146. package/esm/src/kernel/tools/resolve.d.ts +17 -7
  147. package/esm/src/kernel/tools/resolve.js +38 -17
  148. package/esm/src/kernel/tools/schema.d.ts +2 -0
  149. package/esm/src/kernel/tools/schema.js +23 -6
  150. package/esm/src/kernel/tools/stage-run.d.ts +105 -0
  151. package/esm/src/kernel/tools/stage-run.js +155 -0
  152. package/esm/src/kernel/tools/types.d.ts +198 -20
  153. package/esm/src/kernel/types.d.ts +253 -114
  154. package/esm/src/kernel/util/find-last.d.ts +2 -0
  155. package/esm/src/kernel/util/find-last.js +10 -0
  156. package/esm/src/observability/destinations.d.ts +31 -0
  157. package/esm/src/observability/destinations.js +67 -0
  158. package/esm/src/observability/mod.d.ts +10 -3
  159. package/esm/src/observability/mod.js +6 -2
  160. package/esm/src/observability/policy.d.ts +27 -0
  161. package/esm/src/observability/policy.js +80 -0
  162. package/esm/src/observability/resolve-policy.d.ts +16 -0
  163. package/esm/src/observability/resolve-policy.js +64 -0
  164. package/esm/src/observability/trace-attach.d.ts +3 -1
  165. package/esm/src/observability/trace-attach.js +17 -10
  166. package/esm/src/observability/trace-record.d.ts +12 -4
  167. package/esm/src/observability/trace-record.js +63 -19
  168. package/esm/src/observability/trace-sink.d.ts +19 -0
  169. package/esm/src/observability/trace-sink.js +10 -0
  170. package/esm/src/observability/trace.d.ts +14 -11
  171. package/esm/src/observability/trace.js +23 -14
  172. package/esm/src/observability/types.d.ts +113 -0
  173. package/esm/src/observability/types.js +11 -0
  174. package/esm/src/providers/create-provider.d.ts +7 -4
  175. package/esm/src/providers/create-provider.js +21 -7
  176. package/esm/src/providers/google/interactions/framing.d.ts +8 -0
  177. package/esm/src/providers/google/interactions/framing.js +74 -13
  178. package/esm/src/providers/google/live/framing.d.ts +5 -2
  179. package/esm/src/providers/google/live/framing.js +49 -12
  180. package/esm/src/providers/google/live/openapi-schema.js +3 -2
  181. package/esm/src/providers/google/live/stream.d.ts +9 -0
  182. package/esm/src/providers/google/live/stream.js +16 -3
  183. package/esm/src/providers/openrouter/cache-control.d.ts +24 -0
  184. package/esm/src/providers/openrouter/cache-control.js +23 -0
  185. package/esm/src/providers/openrouter/chat.d.ts +21 -1
  186. package/esm/src/providers/openrouter/chat.js +51 -6
  187. package/esm/src/providers/openrouter/image.js +8 -19
  188. package/esm/src/providers/openrouter/openai/chat-payload.js +23 -1
  189. package/esm/src/providers/openrouter/openai/compat.d.ts +7 -1
  190. package/esm/src/providers/openrouter/openai/compat.js +23 -4
  191. package/esm/src/providers/openrouter/openai/image-payload.js +8 -2
  192. package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +1 -1
  193. package/esm/src/providers/openrouter/openai/sdk-messages.js +32 -5
  194. package/package.json +1 -1
  195. package/esm/src/interface/blocks.d.ts +0 -20
  196. package/esm/src/interface/blocks.js +0 -180
  197. package/esm/src/interface/from-profile.d.ts +0 -14
  198. package/esm/src/interface/from-profile.js +0 -104
  199. package/esm/src/interface/inputs.d.ts +0 -8
  200. package/esm/src/interface/inputs.js +0 -127
  201. package/esm/src/interface/mod.d.ts +0 -10
  202. package/esm/src/interface/mod.js +0 -9
  203. package/esm/src/interface/types.d.ts +0 -153
  204. package/esm/src/interface/types.js +0 -13
@@ -4,6 +4,7 @@
4
4
  * @module
5
5
  */
6
6
  import { z } from 'zod';
7
+ import { AWAITING_USER_INPUT_STATUS } from '../schema.js';
7
8
  import { registerTool } from './registry.js';
8
9
  const AskInputSchema = z.object({
9
10
  kind: z.enum(['confirm', 'choice', 'text']),
@@ -11,14 +12,17 @@ const AskInputSchema = z.object({
11
12
  options: z.array(z.string()).optional(),
12
13
  });
13
14
  const AskOutputSchema = z.object({
14
- answer: z.unknown(),
15
+ status: z.literal(AWAITING_USER_INPUT_STATUS),
16
+ kind: z.enum(['confirm', 'choice', 'text']),
17
+ prompt: z.string().trim().min(1),
18
+ options: z.array(z.string()).optional(),
15
19
  });
16
20
  /** Register harness tools shipped with THEORUM. */
17
21
  function registerHarnessTools() {
18
22
  registerTool({
19
23
  type: 'function',
20
24
  name: 'ask_user',
21
- description: 'Ask the user a question and wait for a response',
25
+ description: 'Ask the user a question (completes with awaiting_user_input)', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
22
26
  category: 'conversation',
23
27
  access: 'read-only',
24
28
  paths: ['*'],
@@ -26,19 +30,17 @@ function registerHarnessTools() {
26
30
  permission: 'auto',
27
31
  input: AskInputSchema,
28
32
  output: AskOutputSchema,
29
- interactive: {
30
- render: (input) => {
31
- const ask = input;
32
- return {
33
- kind: ask.kind,
34
- prompt: ask.prompt,
35
- options: ask.options,
36
- };
37
- },
33
+ handler: (input) => {
34
+ const out = {
35
+ status: AWAITING_USER_INPUT_STATUS,
36
+ kind: input.kind,
37
+ prompt: input.prompt,
38
+ };
39
+ if (input.kind === 'choice' && input.options?.length) {
40
+ out.options = input.options;
41
+ }
42
+ return out;
38
43
  },
39
- handler: (_input, ctx) => ({
40
- answer: ctx.resume?.value ?? ctx.resume?.granted,
41
- }),
42
44
  });
43
45
  }
44
46
  export { registerHarnessTools };
@@ -14,12 +14,14 @@ function turnRequestFromInvoke(request) {
14
14
  path: request.path,
15
15
  sessionPermissions: request.sessionPermissions,
16
16
  input: request.turnInput,
17
- select: request.select,
17
+ model: request.model,
18
+ host: request.host,
18
19
  };
19
20
  }
20
21
  async function prepareInvokeSnapshot(request, profile) {
21
22
  const req = turnRequestFromInvoke(request);
22
- const model = pickModel(profile, request.select);
23
+ // Host profiles bind no model the allow list is the whole snapshot.
24
+ const model = profile.type === 'host' ? undefined : pickModel(profile, request.model);
23
25
  return await prepareTurnToolSnapshot(profile, req, model);
24
26
  }
25
27
  /** Execute a registered tool without calling a model provider. */
@@ -41,13 +43,14 @@ async function* invokeTool(request) {
41
43
  failure,
42
44
  },
43
45
  };
44
- yield { type: 'done', stop: { kind: 'tool' } };
46
+ yield { type: 'done', stop: { kind: 'completed' } };
45
47
  return;
46
48
  }
47
49
  }
48
- let sawPause = false;
50
+ let sawGate = false;
49
51
  let sawError = false;
50
52
  try {
53
+ const handlers = request.onStage ? [request.onStage] : [];
51
54
  for await (const event of executeRegisteredTool({
52
55
  profile,
53
56
  name: request.name,
@@ -55,18 +58,29 @@ async function* invokeTool(request) {
55
58
  callId,
56
59
  ctx: {
57
60
  sessionPermissions: request.sessionPermissions,
61
+ credentials: request.credentials,
58
62
  path: request.path,
59
63
  signal: request.signal,
60
64
  resume: request.resume,
65
+ host: request.host,
61
66
  },
62
67
  snapshot,
68
+ stages: {
69
+ handlers,
70
+ profile,
71
+ step: 1,
72
+ history: () => [],
73
+ injectAllowed: false,
74
+ host: request.host,
75
+ signal: request.signal,
76
+ },
63
77
  })) {
64
78
  yield event;
65
79
  if (event.type !== 'tool') {
66
80
  continue;
67
81
  }
68
- if (event.tool?.phase === 'pause') {
69
- sawPause = true;
82
+ if (event.tool?.phase === 'gate') {
83
+ sawGate = true;
70
84
  }
71
85
  if (event.tool?.phase === 'error') {
72
86
  sawError = true;
@@ -77,7 +91,11 @@ async function* invokeTool(request) {
77
91
  yield toErrorEvent(err);
78
92
  sawError = true;
79
93
  }
80
- const stopKind = sawError || sawPause ? 'tool' : 'completed';
81
- yield { type: 'done', stop: { kind: stopKind } };
94
+ const stopKind = sawGate ? 'gate' : sawError ? 'completed' : 'completed';
95
+ yield {
96
+ type: 'done',
97
+ stop: { kind: stopKind },
98
+ ...(sawGate ? { tools: snapshot } : {}),
99
+ };
82
100
  }
83
101
  export { invokeTool };
@@ -3,9 +3,11 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- export { formatToolResult } from './execute.js';
6
+ export { coerceToolResultParts, executeRegisteredTool, formatToolResult, leanToolResultData, projectForModel, } from './execute.js';
7
7
  export { registerHarnessTools } from './harness.js';
8
8
  export { invokeTool } from './invoke.js';
9
9
  export { getTool, hasTool, listBuiltinIds, listFunctionIds, listTools, registerTool, registerTools, requireTool, resetTools, } from './registry.js';
10
+ export type { McpProtocolVersion, McpRpcResponse } from './remote.js';
11
+ export { buildHttpToolTarget, executeHttpTool, executeMcpTool, isUnsupportedMcpProtocolError, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, resolveToolAuth, } from './remote.js';
10
12
  export { cloneTurnToolSnapshot, prepareTurnToolSnapshot } from './resolve.js';
11
13
  export type * from './types.js';
@@ -3,8 +3,9 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- export { formatToolResult } from './execute.js';
6
+ export { coerceToolResultParts, executeRegisteredTool, formatToolResult, leanToolResultData, projectForModel, } from './execute.js';
7
7
  export { registerHarnessTools } from './harness.js';
8
8
  export { invokeTool } from './invoke.js';
9
9
  export { getTool, hasTool, listBuiltinIds, listFunctionIds, listTools, registerTool, registerTools, requireTool, resetTools, } from './registry.js';
10
+ export { buildHttpToolTarget, executeHttpTool, executeMcpTool, isUnsupportedMcpProtocolError, MCP_PROTOCOL_VERSIONS, parseMcpRpcResponse, resolveToolAuth, } from './remote.js';
10
11
  export { cloneTurnToolSnapshot, prepareTurnToolSnapshot } from './resolve.js';
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Declarative catalog permission + gate-resume helpers.
3
+ *
4
+ * Shared by function and HTTP/MCP execute paths (no circular import with remote).
5
+ *
6
+ * @module
7
+ */
8
+ import type { InvokeToolResume, ToolGate, ToolPermission } from './types.js';
9
+ export declare function isResumeContinuation(resume?: InvokeToolResume): boolean;
10
+ /** Gate resume — only `granted: true` skips confirm/permission/`preTool` re-ask. */
11
+ export declare function isGateResumeGranted(resume?: InvokeToolResume): boolean;
12
+ /** Host denied after a gate — settle without running the body. */
13
+ export declare function isGateResumeDenied(resume?: InvokeToolResume): boolean;
14
+ export declare function permissionGranted(toolName: string, sessionPermissions?: string[]): boolean;
15
+ export declare function checkPermission(toolName: string, permission: ToolPermission, sessionPermissions?: string[], resume?: InvokeToolResume): ToolGate | null;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Declarative catalog permission + gate-resume helpers.
3
+ *
4
+ * Shared by function and HTTP/MCP execute paths (no circular import with remote).
5
+ *
6
+ * @module
7
+ */
8
+ export function isResumeContinuation(resume) {
9
+ return resume?.value !== undefined || typeof resume?.granted === 'boolean';
10
+ }
11
+ /** Gate resume — only `granted: true` skips confirm/permission/`preTool` re-ask. */
12
+ export function isGateResumeGranted(resume) {
13
+ return resume?.granted === true;
14
+ }
15
+ /** Host denied after a gate — settle without running the body. */
16
+ export function isGateResumeDenied(resume) {
17
+ return resume?.granted === false;
18
+ }
19
+ export function permissionGranted(toolName, sessionPermissions) {
20
+ if (!sessionPermissions) {
21
+ return false;
22
+ }
23
+ return sessionPermissions.includes('*') || sessionPermissions.includes(toolName);
24
+ }
25
+ export function checkPermission(toolName, permission, sessionPermissions, resume) {
26
+ if (permission === 'auto') {
27
+ return null;
28
+ }
29
+ if (permission === 'always_confirm') {
30
+ if (resume?.granted === true) {
31
+ return null;
32
+ }
33
+ return {
34
+ kind: 'permission',
35
+ tool: toolName,
36
+ permission,
37
+ };
38
+ }
39
+ if (permissionGranted(toolName, sessionPermissions)) {
40
+ return null;
41
+ }
42
+ return {
43
+ kind: 'permission',
44
+ tool: toolName,
45
+ permission,
46
+ };
47
+ }
@@ -13,9 +13,11 @@ function projectTool(name) {
13
13
  }
14
14
  function builtInToolIds(profile) {
15
15
  const seen = new Set();
16
- for (const modelId of profile.model.allow) {
17
- const spec = profile.model.config[modelId];
18
- for (const id of spec?.builtInTools ?? []) {
16
+ if (profile.type === 'host') {
17
+ return [];
18
+ }
19
+ for (const binding of Object.values(profile.models)) {
20
+ for (const id of binding.builtInTools ?? []) {
19
21
  seen.add(id);
20
22
  }
21
23
  }
@@ -11,22 +11,32 @@
11
11
  import { TheorumError } from '../../guardrails/error.js';
12
12
  import { jsonSchemaFromZod, validateToolInputSchema, validateToolOutputSchema } from './schema.js';
13
13
  const tools = new Map();
14
- function normalizeFunction(def) {
15
- const inputSchema = jsonSchemaFromZod(def.input, 'input');
14
+ function schemasFromZod(input, output) {
15
+ const inputSchema = jsonSchemaFromZod(input, 'input');
16
16
  validateToolInputSchema(inputSchema);
17
- const outputSchema = jsonSchemaFromZod(def.output, 'output');
17
+ const outputSchema = jsonSchemaFromZod(output, 'output');
18
18
  validateToolOutputSchema(outputSchema);
19
- return {
20
- ...def,
21
- type: 'function',
22
- inputSchema,
23
- outputSchema,
24
- };
19
+ return { inputSchema, outputSchema };
20
+ }
21
+ function normalizeHttp(def) {
22
+ return { ...def, type: 'http', ...schemasFromZod(def.input, def.output) };
23
+ }
24
+ function normalizeMcp(def) {
25
+ return { ...def, type: 'mcp', ...schemasFromZod(def.input, def.output) };
26
+ }
27
+ function normalizeFunction(def) {
28
+ return { ...def, type: 'function', ...schemasFromZod(def.input, def.output) };
25
29
  }
26
30
  function normalizeToolDefinition(def) {
27
31
  if (def.type === 'builtin') {
28
32
  return def;
29
33
  }
34
+ if (def.type === 'http') {
35
+ return normalizeHttp(def);
36
+ }
37
+ if (def.type === 'mcp') {
38
+ return normalizeMcp(def);
39
+ }
30
40
  return normalizeFunction(def);
31
41
  }
32
42
  /** Register or replace a tool definition. */
@@ -45,7 +55,7 @@ function getTool(name) {
45
55
  function requireTool(name) {
46
56
  const tool = getTool(name);
47
57
  if (!tool) {
48
- throw new TheorumError(`Tool '${name}' is not registered`);
58
+ throw new TheorumError(`Tool '${name}' is not registered`); // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
49
59
  }
50
60
  return tool;
51
61
  }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Execution runners for Declarative HTTP and Remote MCP tools.
3
+ *
4
+ * Implements:
5
+ * - URL parameter substitution and query/body mapping
6
+ * - Network SSRF guardrail enforcement via `assertSafeUrl`
7
+ * - Credential resolution (bearer, api_key, oauth2)
8
+ * - Proactive OAuth token refresh with progress event emission
9
+ * - ToolGate { kind: 'auth' } emission or model error reporting
10
+ * - Streamable HTTP MCP JSON-RPC protocol (`tools/call`) per 2026-07-28 spec
11
+ *
12
+ * @module
13
+ */
14
+ import type { TurnEvent } from '../types.js';
15
+ import { type ToolCallBase } from './events.js';
16
+ import { type ToolStageSupport } from './stage-run.js';
17
+ import type { HttpToolAuthConfig, HttpToolDef, McpToolDef, ModelToolResult, ToolBodyOutcome, ToolContext, ToolGate } from './types.js';
18
+ export type AuthResolveResult = {
19
+ headers: Record<string, string>;
20
+ unauthenticated?: boolean;
21
+ modelMessage?: string;
22
+ gate?: ToolGate;
23
+ };
24
+ /**
25
+ * Resolves credentials and handles missing/expired tokens.
26
+ * Yields TurnEvents for auth pauses or progress (e.g. refreshed tokens).
27
+ */
28
+ export declare function resolveToolAuth(toolName: string, authConfig: HttpToolAuthConfig | undefined, ctx: ToolContext, base: ToolCallBase): AsyncGenerator<TurnEvent, AuthResolveResult>;
29
+ export type HttpToolMapping = NonNullable<HttpToolDef['mapping']>;
30
+ export type HttpToolTarget = {
31
+ url: string;
32
+ body?: string;
33
+ };
34
+ /**
35
+ * Build the request URL (and optional JSON body) for a declarative HTTP tool
36
+ * from endpoint template, mapping, and validated input.
37
+ */
38
+ export declare function buildHttpToolTarget(endpoint: string, method: HttpToolDef['method'], input: Record<string, unknown>, mapping?: HttpToolMapping): HttpToolTarget;
39
+ export declare function parseToolOutput<T>(schema: {
40
+ safeParse: (data: unknown) => {
41
+ success: true;
42
+ data: T;
43
+ } | {
44
+ success: false;
45
+ error: {
46
+ flatten: () => unknown;
47
+ };
48
+ };
49
+ }, responseData: unknown): {
50
+ success: true;
51
+ data: T;
52
+ } | {
53
+ success: false;
54
+ error: {
55
+ flatten: () => unknown;
56
+ };
57
+ };
58
+ export declare function modelResultFromOutput(data: unknown): ModelToolResult;
59
+ /**
60
+ * Executes a Declarative HTTP tool.
61
+ * Order: schema → permission → auth → preTool/host stages → body.
62
+ */
63
+ export declare function executeHttpTool(tool: HttpToolDef, rawInput: unknown, ctx: ToolContext, base: ToolCallBase, stages?: ToolStageSupport): AsyncGenerator<TurnEvent, ToolBodyOutcome>;
64
+ /** Preferred-first Streamable HTTP protocol revisions the kernel will negotiate. */
65
+ export declare const MCP_PROTOCOL_VERSIONS: readonly ["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26"];
66
+ export type McpProtocolVersion = (typeof MCP_PROTOCOL_VERSIONS)[number];
67
+ export type McpRpcResponse = {
68
+ jsonrpc?: string;
69
+ id?: unknown;
70
+ result?: {
71
+ content?: Array<{
72
+ type: string;
73
+ text?: string;
74
+ [key: string]: unknown;
75
+ }>;
76
+ isError?: boolean;
77
+ [key: string]: unknown;
78
+ };
79
+ error?: {
80
+ code: number;
81
+ message: string;
82
+ data?: unknown;
83
+ };
84
+ method?: string;
85
+ };
86
+ /** Parse MCP JSON or SSE (`event: message` / `data:`) bodies into a JSON-RPC object. */
87
+ export declare function parseMcpRpcResponse(text: string): McpRpcResponse;
88
+ /** True when a JSON-RPC error indicates the server rejected our protocol revision. */
89
+ export declare function isUnsupportedMcpProtocolError(error: McpRpcResponse['error']): boolean;
90
+ /**
91
+ * Executes a Remote MCP tool over Streamable HTTP (spec revision 2026-07-28).
92
+ * Order: schema → permission → auth → preTool/host stages → body.
93
+ */
94
+ export declare function executeMcpTool(tool: McpToolDef, rawInput: unknown, ctx: ToolContext, base: ToolCallBase, stages?: ToolStageSupport): AsyncGenerator<TurnEvent, ToolBodyOutcome>;