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
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * @module
8
8
  */
9
- import type { TurnStopKind } from './schema.js';
9
+ import { type ContinueStopKind, type TurnStopKind } from './schema.js';
10
10
  /** Normalized stop attached to terminal `done` events and host continue requests. */
11
11
  export interface TurnStop {
12
12
  kind: TurnStopKind;
@@ -14,35 +14,65 @@ export interface TurnStop {
14
14
  native?: string;
15
15
  }
16
16
  /**
17
- * Fixed continue instruction for resumeable stops.
18
- * Hosts should not invent per-app continue prompts.
17
+ * Default continue instruction for resumeable stops — the registered lexicon
18
+ * default (`continue.instruction`). It rarely needs replacing, but hosts may
19
+ * override it per profile via `turnBehaviour.resumption.continueInstruction`
20
+ * or process-wide via `overrideLexicon`.
19
21
  */
20
- export declare const CONTINUE_INSTRUCTION = "Continue and finish the incomplete output from the previous turn. Do not restart from scratch; preserve what was already generated and complete it.";
22
+ export declare const CONTINUE_INSTRUCTION: string;
23
+ /** Default kinds hosts may offer Continue for (= full ContinueStopKind set). */
24
+ export declare const DEFAULT_ALLOW_CONTINUE: readonly ContinueStopKind[];
21
25
  /**
22
26
  * Default kinds for one silent auto-continue (hosts wait briefly, then resume once).
23
- * User `cancelled` is never included.
27
+ * Never includes kinds outside ContinueStopKind (e.g. cancelled / tool / gate / completed).
24
28
  */
25
- export declare const DEFAULT_AUTO_CONTINUE: readonly TurnStopKind[];
29
+ export declare const DEFAULT_AUTO_CONTINUE: readonly ContinueStopKind[];
26
30
  /** Pause before the one-shot auto-continue so a flaky tunnel can settle. */
27
31
  export declare const AUTO_CONTINUE_DELAY_MS = 1500;
28
- /** Profile turn-continuation policy under top-level `turnResumption`. */
32
+ /** Profile turn-continuation policy under `turnBehaviour.resumption`. */
29
33
  export interface ProfileTurnResumptionSpec {
30
34
  /**
31
35
  * Kinds eligible for a Continue / continueFrom turn.
32
36
  * When omitted, length / stream_incomplete / provider_error are eligible.
37
+ * Only `ContinueStopKind` values are valid — not tool / cancelled / completed / …
33
38
  */
34
- allowContinue?: TurnStopKind[];
39
+ allowContinue?: ContinueStopKind[];
35
40
  /**
36
41
  * Kinds the host may auto-continue without a CTA.
37
42
  * Kernel does not loop; hosts call continueFrom and pass `continuation`.
38
43
  */
39
- autoContinue?: TurnStopKind[];
44
+ autoContinue?: ContinueStopKind[];
40
45
  /**
41
46
  * Max continueFrom rounds the kernel will accept for this profile.
42
47
  * Compared against `TurnRequest.continuation` (1-based continue attempt).
43
48
  * When omitted, only kind allowlists apply (no count cap).
44
49
  */
45
50
  maxContinues?: number;
51
+ /**
52
+ * Host replacement for the continue instruction appended on continueFrom
53
+ * turns. Omitted means the registered default (`CONTINUE_INSTRUCTION`).
54
+ */
55
+ continueInstruction?: string;
56
+ }
57
+ /** True when `kind` may appear in allowContinue / autoContinue. */
58
+ export declare function isContinueStopKind(kind: string): kind is ContinueStopKind;
59
+ /**
60
+ * Mid-turn + resume policy for text / image / speech profiles.
61
+ *
62
+ * - `resumption` — continueFrom after a non-user stop (all three types).
63
+ * - `allowSteering` — stage **inject** gate on text and live (default true).
64
+ * Image / speech must omit. Stage events always emit when the runner uses stages.
65
+ *
66
+ * Stop / AbortSignal is not a profile knob — composer interfaces always
67
+ * project `canStop: true` because `TurnRequest.signal` is already wired.
68
+ */
69
+ export interface ProfileTurnBehaviourSpec {
70
+ resumption?: ProfileTurnResumptionSpec;
71
+ /**
72
+ * When true (default on text/live), host `onStage` inject affordances are applied
73
+ * (`profileAllowsInject`). Does not hide stage emission.
74
+ */
75
+ allowSteering?: boolean;
46
76
  }
47
77
  /** Partial state passed when continuing a resumeable stop. */
48
78
  export interface TurnContinueFrom {
@@ -52,11 +82,35 @@ export interface TurnContinueFrom {
52
82
  partialArtifact?: string;
53
83
  }
54
84
  /** True when this stop may be continued (profile allow list or default). */
55
- export declare function isResumeableStop(stop: TurnStop | undefined, allowContinue?: readonly TurnStopKind[]): boolean;
85
+ export declare function isResumeableStop(stop: TurnStop | undefined, allowContinue?: readonly ContinueStopKind[]): boolean;
56
86
  /** True when the host aborted (user Stop). */
57
87
  export declare function isUserCancelledStop(stop: TurnStop | undefined): boolean;
58
88
  /** True when profile policy allows one silent auto-continue for this stop. */
59
- export declare function shouldAutoContinue(stop: TurnStop | undefined, autoContinue?: readonly TurnStopKind[] | undefined): boolean;
89
+ export declare function shouldAutoContinue(stop: TurnStop | undefined, autoContinue?: readonly ContinueStopKind[] | undefined): boolean;
90
+ /** Read nested `turnBehaviour.resumption` from a non-live profile. */
91
+ export declare function profileTurnResumption(profile: {
92
+ type: string;
93
+ turnBehaviour?: ProfileTurnBehaviourSpec;
94
+ }): ProfileTurnResumptionSpec | undefined;
95
+ /**
96
+ * Text profiles may inject at stages unless `allowSteering: false`.
97
+ * Image / speech / host: use `profileAllowsInject` for the target matrix;
98
+ * this helper remains text-only for interface `allowSteering` projection.
99
+ */
100
+ export declare function profileAllowsSteering(profile: {
101
+ type: string;
102
+ turnBehaviour?: ProfileTurnBehaviourSpec;
103
+ }): boolean;
104
+ /**
105
+ * Whether stage **inject** affordances may be applied (`docs/contracts/stages.md`).
106
+ * Gates inject only — never stage emission or tool stages.
107
+ *
108
+ * Text + live when `allowSteering !== false`; never image / speech / host.
109
+ */
110
+ export declare function profileAllowsInject(profile: {
111
+ type: string;
112
+ turnBehaviour?: ProfileTurnBehaviourSpec;
113
+ }): boolean;
60
114
  /** OpenAI-compatible normalized `finish_reason` (+ optional `native_finish_reason`). */
61
115
  export declare function turnStopFromOpenAiFinishReason(finishReason: string | null | undefined, nativeFinishReason?: string | null): TurnStop;
62
116
  /** Gemini Interactions terminal `status`. */
@@ -6,29 +6,36 @@
6
6
  *
7
7
  * @module
8
8
  */
9
+ import { lexiconDefault } from '../guardrails/lexicon.js';
10
+ import { CONTINUE_STOP_KINDS } from './schema.js';
9
11
  /**
10
- * Fixed continue instruction for resumeable stops.
11
- * Hosts should not invent per-app continue prompts.
12
+ * Default continue instruction for resumeable stops — the registered lexicon
13
+ * default (`continue.instruction`). It rarely needs replacing, but hosts may
14
+ * override it per profile via `turnBehaviour.resumption.continueInstruction`
15
+ * or process-wide via `overrideLexicon`.
12
16
  */
13
- export const CONTINUE_INSTRUCTION = 'Continue and finish the incomplete output from the previous turn. Do not restart from scratch; preserve what was already generated and complete it.';
14
- /** Default kinds hosts may offer Continue for. */
15
- const DEFAULT_ALLOW_CONTINUE = [
16
- 'length',
17
- 'stream_incomplete',
18
- 'provider_error',
19
- ];
17
+ export const CONTINUE_INSTRUCTION = lexiconDefault('continue.instruction');
18
+ /** Default kinds hosts may offer Continue for (= full ContinueStopKind set). */
19
+ export const DEFAULT_ALLOW_CONTINUE = CONTINUE_STOP_KINDS;
20
20
  /**
21
21
  * Default kinds for one silent auto-continue (hosts wait briefly, then resume once).
22
- * User `cancelled` is never included.
22
+ * Never includes kinds outside ContinueStopKind (e.g. cancelled / tool / gate / completed).
23
23
  */
24
24
  export const DEFAULT_AUTO_CONTINUE = ['length', 'stream_incomplete'];
25
25
  /** Pause before the one-shot auto-continue so a flaky tunnel can settle. */
26
26
  export const AUTO_CONTINUE_DELAY_MS = 1_500;
27
+ const CONTINUE_KIND_SET = new Set(CONTINUE_STOP_KINDS);
28
+ /** True when `kind` may appear in allowContinue / autoContinue. */
29
+ export function isContinueStopKind(kind) {
30
+ return CONTINUE_KIND_SET.has(kind);
31
+ }
27
32
  const RESUMEABLE_DEFAULT = new Set(DEFAULT_ALLOW_CONTINUE);
28
33
  /** True when this stop may be continued (profile allow list or default). */
29
34
  export function isResumeableStop(stop, allowContinue) {
30
35
  if (!stop)
31
36
  return false;
37
+ if (!isContinueStopKind(stop.kind))
38
+ return false;
32
39
  const allow = allowContinue?.length ? new Set(allowContinue) : RESUMEABLE_DEFAULT;
33
40
  return allow.has(stop.kind);
34
41
  }
@@ -38,13 +45,41 @@ export function isUserCancelledStop(stop) {
38
45
  }
39
46
  /** True when profile policy allows one silent auto-continue for this stop. */
40
47
  export function shouldAutoContinue(stop, autoContinue = DEFAULT_AUTO_CONTINUE) {
41
- if (!stop)
48
+ if (!stop || !isContinueStopKind(stop.kind))
42
49
  return false;
43
50
  const list = autoContinue ?? DEFAULT_AUTO_CONTINUE;
44
51
  if (list.length === 0)
45
52
  return false;
46
53
  return list.includes(stop.kind) && isResumeableStop(stop);
47
54
  }
55
+ /** Read nested `turnBehaviour.resumption` from a non-live profile. */
56
+ export function profileTurnResumption(profile) {
57
+ if (profile.type === 'live')
58
+ return undefined;
59
+ return profile.turnBehaviour?.resumption;
60
+ }
61
+ /**
62
+ * Text profiles may inject at stages unless `allowSteering: false`.
63
+ * Image / speech / host: use `profileAllowsInject` for the target matrix;
64
+ * this helper remains text-only for interface `allowSteering` projection.
65
+ */
66
+ export function profileAllowsSteering(profile) {
67
+ if (profile.type !== 'text')
68
+ return false;
69
+ return profile.turnBehaviour?.allowSteering !== false;
70
+ }
71
+ /**
72
+ * Whether stage **inject** affordances may be applied (`docs/contracts/stages.md`).
73
+ * Gates inject only — never stage emission or tool stages.
74
+ *
75
+ * Text + live when `allowSteering !== false`; never image / speech / host.
76
+ */
77
+ export function profileAllowsInject(profile) {
78
+ if (profile.type === 'text' || profile.type === 'live') {
79
+ return profile.turnBehaviour?.allowSteering !== false;
80
+ }
81
+ return false;
82
+ }
48
83
  /** OpenAI-compatible normalized `finish_reason` (+ optional `native_finish_reason`). */
49
84
  export function turnStopFromOpenAiFinishReason(finishReason, nativeFinishReason) {
50
85
  const native = nativeFinishReason?.trim() || finishReason?.trim() || undefined;
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Tool event shapes and the preamble every executable tool path shares.
3
+ *
4
+ * Function, declarative HTTP, and remote MCP tools all announce themselves,
5
+ * validate their input, and — for the remote kinds — clear their target against
6
+ * the profile's SSRF policy. Keeping that here means the three paths cannot drift,
7
+ * and it holds the event constructors both `execute.ts` and `remote.ts` need
8
+ * without either importing the other.
9
+ *
10
+ * @module
11
+ */
12
+ import type { z } from 'zod';
13
+ import type { TurnEvent } from '../types.js';
14
+ import type { ToolCallEvent, ToolContext, ToolFailure } from './types.js';
15
+ /** Identifying fields repeated on every event for one tool call. */
16
+ export type ToolCallBase = Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>;
17
+ export declare function toolEvent(base: ToolCallBase, patch: Partial<ToolCallEvent>): TurnEvent;
18
+ export declare function failureEvent(base: ToolCallBase, failure: ToolFailure): TurnEvent;
19
+ /** Failure text for a thrown value, without leaking a stack. */
20
+ export declare function messageOf(err: unknown): string;
21
+ /**
22
+ * Announce the call and validate its input.
23
+ *
24
+ * Returns `{ ok: false }` after emitting the failure event, so callers bail
25
+ * without re-deciding what an invalid input means.
26
+ */
27
+ export declare function startToolExecution<T>(tool: {
28
+ input: z.ZodType<T>;
29
+ }, rawInput: unknown, ctx: ToolContext, base: ToolCallBase): Generator<TurnEvent, {
30
+ ok: true;
31
+ data: T;
32
+ } | {
33
+ ok: false;
34
+ }>;
35
+ /**
36
+ * Clear a remote target against the profile's network policy.
37
+ *
38
+ * Returns `undefined` after emitting the failure event when the target is
39
+ * blocked, so HTTP and MCP cannot diverge on what SSRF enforcement means.
40
+ */
41
+ export declare function guardToolTarget(url: string, ctx: ToolContext, base: ToolCallBase): Generator<TurnEvent, URL | undefined>;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Tool event shapes and the preamble every executable tool path shares.
3
+ *
4
+ * Function, declarative HTTP, and remote MCP tools all announce themselves,
5
+ * validate their input, and — for the remote kinds — clear their target against
6
+ * the profile's SSRF policy. Keeping that here means the three paths cannot drift,
7
+ * and it holds the event constructors both `execute.ts` and `remote.ts` need
8
+ * without either importing the other.
9
+ *
10
+ * @module
11
+ */
12
+ import { throwIfAborted } from '../../guardrails/error.js';
13
+ import { assertSafeUrl } from '../../guardrails/network.js';
14
+ import { resolveGuardrailPolicy } from '../../guardrails/policy.js';
15
+ export function toolEvent(base, patch) {
16
+ return {
17
+ type: 'tool',
18
+ tool: { ...base, ...patch },
19
+ };
20
+ }
21
+ export function failureEvent(base, failure) {
22
+ return toolEvent(base, { phase: 'error', failure });
23
+ }
24
+ /** Failure text for a thrown value, without leaking a stack. */
25
+ export function messageOf(err) {
26
+ return err instanceof Error ? err.message : String(err);
27
+ }
28
+ /**
29
+ * Announce the call and validate its input.
30
+ *
31
+ * Returns `{ ok: false }` after emitting the failure event, so callers bail
32
+ * without re-deciding what an invalid input means.
33
+ */
34
+ export function* startToolExecution(tool, rawInput, ctx, base) {
35
+ yield toolEvent(base, { phase: 'running' });
36
+ throwIfAborted(ctx.signal);
37
+ const parsed = tool.input.safeParse(rawInput);
38
+ if (!parsed.success) {
39
+ yield failureEvent(base, {
40
+ code: 'invalid_input',
41
+ message: 'Tool input validation failed', // lexicon-exempt: developer contract / internal diagnostic — not end-user or model copy (P2)
42
+ details: parsed.error.flatten(),
43
+ });
44
+ return { ok: false };
45
+ }
46
+ return { ok: true, data: parsed.data };
47
+ }
48
+ /**
49
+ * Clear a remote target against the profile's network policy.
50
+ *
51
+ * Returns `undefined` after emitting the failure event when the target is
52
+ * blocked, so HTTP and MCP cannot diverge on what SSRF enforcement means.
53
+ */
54
+ export function* guardToolTarget(url, ctx, base) {
55
+ try {
56
+ return assertSafeUrl(url, resolveGuardrailPolicy(ctx.profile.guardrails).network);
57
+ }
58
+ catch (err) {
59
+ yield {
60
+ type: 'guardrail',
61
+ guardrail: {
62
+ stage: 'network',
63
+ trust: 'untrusted',
64
+ action: 'block',
65
+ hits: [{ rule: 'network.blocked', severity: 'high' }],
66
+ },
67
+ };
68
+ yield failureEvent(base, { code: 'network_blocked', message: messageOf(err) });
69
+ return undefined;
70
+ }
71
+ }
@@ -3,37 +3,73 @@
3
3
  *
4
4
  * @module
5
5
  */
6
- import type { z } from 'zod';
7
- import type { Profile, TurnEvent } from '../types.js';
8
- import type { FunctionToolDef, InvokeToolResume, ModelToolResult, ToolCallEvent, ToolContext, ToolFailure, ToolPause, ToolPermission, ToolStreamEvent, TurnToolSnapshot } from './types.js';
9
- export declare function isResumeContinuation(resume?: InvokeToolResume): boolean;
10
- export declare function isToolPause(value: ToolFailure | ToolPause): value is ToolPause;
6
+ import { resolveGuardrailPolicy } from '../../guardrails/policy.js';
7
+ import type { Provenance } from '../../guardrails/types.js';
8
+ import type { InteractionPart, Profile, TurnEvent, TurnHistoryMessage } from '../types.js';
9
+ import { startToolExecution } from './events.js';
10
+ import { type ToolStageSupport } from './stage-run.js';
11
+ import type { FunctionToolDef, ModelToolResult, ToolCallEvent, ToolContext, ToolFailure, ToolGate, ToolStreamEvent, TurnToolSnapshot } from './types.js';
12
+ export { checkPermission, isGateResumeGranted, isResumeContinuation, permissionGranted, } from './permission.js';
13
+ /** Validate host-emitted InteractionPart shapes; drop invalid entries. */
14
+ export declare function coerceToolResultParts(raw: unknown): InteractionPart[] | undefined;
15
+ /** Copy tool output for model `data`, omitting media `parts`. */
16
+ export declare function leanToolResultData(output: unknown): unknown;
17
+ /** @deprecated Gates use `ToolGate` / `phase: 'gate'`. Kept for type narrowing during migration. */
18
+ export declare function isToolPause(value: ToolFailure | {
19
+ kind: string;
20
+ }): value is {
21
+ kind: 'interactive' | 'confirmation' | 'permission' | 'auth';
22
+ };
11
23
  export declare function yieldHandlerSideEvent(base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>, event: Exclude<ToolStreamEvent, {
12
24
  kind: 'complete';
13
25
  }>): Generator<TurnEvent>;
14
- export declare function permissionGranted(toolName: string, sessionPermissions?: string[]): boolean;
15
- export declare function checkPermission(toolName: string, permission: ToolPermission, sessionPermissions?: string[], resume?: InvokeToolResume): ToolPause | null;
16
26
  export declare function projectForModel(tool: FunctionToolDef, output: unknown): ModelToolResult;
17
- /** Format model-facing tool output for provider history continuation. */
27
+ /**
28
+ * Format model-facing tool output for provider history continuation.
29
+ *
30
+ * Text projection only — never embeds `parts[].data`; media travels on
31
+ * `TurnHistoryMessage.parts` and adapters wire it from there.
32
+ *
33
+ * `executeRegisteredTool` guards at the boundary and leaves `modelText` behind, so
34
+ * the common path returns already-fenced text. A result recorded elsewhere — a
35
+ * host replaying a transcript — is guarded here instead, under full detection.
36
+ */
18
37
  export declare function formatToolResult(result: ModelToolResult): string;
19
- /** Format a tool failure for provider history — structured so the model (or host) sees the code. */
20
- export declare function formatToolFailureForModel(failure: ToolFailure): ModelToolResult;
21
- export declare function startToolExecution<T>(tool: {
22
- input: z.ZodType<T>;
23
- }, rawInput: unknown, ctx: ToolContext, base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>): Generator<TurnEvent, {
24
- ok: true;
25
- data: T;
26
- } | {
27
- ok: false;
28
- }>;
29
- export declare function executeFunction(tool: FunctionToolDef, rawInput: unknown, ctx: ToolContext, base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>, snapshot?: TurnToolSnapshot): AsyncGenerator<TurnEvent, ModelToolResult | undefined>;
30
- export declare function notLoadedMessage(tool: FunctionToolDef): string;
38
+ /**
39
+ * Format a tool failure for provider history — structured so the model (or host)
40
+ * sees the code.
41
+ *
42
+ * The message is remote-authored on HTTP and MCP tools, so it is redacted before
43
+ * the kernel frames it as a system report.
44
+ */
45
+ export declare function formatToolFailureForModel(failure: ToolFailure, provenance?: Provenance, policy?: ReturnType<typeof resolveGuardrailPolicy>): ModelToolResult;
46
+ /** Settlement returned from `executeRegisteredTool` / function execute. */
47
+ export type ToolExecuteSettlement = {
48
+ modelResult?: ModelToolResult;
49
+ gated?: ToolGate;
50
+ aborted?: boolean | {
51
+ reason?: string;
52
+ };
53
+ callNotStarted?: boolean;
54
+ awaiting?: boolean;
55
+ failure?: ToolFailure;
56
+ /** Raw tool output when the body completed (incl. awaiting). */
57
+ outputRaw?: unknown;
58
+ /**
59
+ * post_tool inject messages — apply after recording the provider tool result
60
+ * so Interactions continuation exists.
61
+ */
62
+ pendingInject?: TurnHistoryMessage[];
63
+ };
64
+ export declare function executeFunction(tool: FunctionToolDef, rawInput: unknown, ctx: ToolContext, base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>, snapshot?: TurnToolSnapshot, stages?: ToolStageSupport): AsyncGenerator<TurnEvent, ToolExecuteSettlement>;
65
+ export declare function notLoadedMessage(tool: {
66
+ name: string;
67
+ loadTier?: string;
68
+ }): string;
31
69
  export declare function extractLoadedIds(output: unknown): string[] | undefined;
32
- /** Strip prototype-pollution keys from provider/host tool args before validation. */
33
- export declare function plainToolInput(input: unknown): unknown;
34
70
  export declare function executeBuiltin(tool: {
35
71
  name: string;
36
- }, ctx: ToolContext, base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>, snapshot: TurnToolSnapshot): AsyncGenerator<TurnEvent, ModelToolResult | undefined>;
72
+ }, ctx: ToolContext, base: Pick<ToolCallEvent, 'name' | 'callId' | 'arguments'>, snapshot: TurnToolSnapshot): AsyncGenerator<TurnEvent, ToolExecuteSettlement>;
37
73
  export declare function executeRegisteredTool(args: {
38
74
  profile: Profile;
39
75
  name: string;
@@ -41,5 +77,8 @@ export declare function executeRegisteredTool(args: {
41
77
  callId: string;
42
78
  ctx: Omit<ToolContext, 'callId' | 'profile'>;
43
79
  snapshot?: TurnToolSnapshot;
44
- }): AsyncGenerator<TurnEvent, ModelToolResult | undefined>;
80
+ stages?: ToolStageSupport;
81
+ }): AsyncGenerator<TurnEvent, ToolExecuteSettlement>;
82
+ export type { ToolStageSupport };
83
+ export { startToolExecution };
45
84
  export declare function newCallId(name: string): string;