@mongodb-js/agent-engine-runner-shared 0.11.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 (220) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/LICENSE.md +201 -0
  3. package/README.md +29 -0
  4. package/dist/agent_config.d.ts +167 -0
  5. package/dist/agent_config.d.ts.map +1 -0
  6. package/dist/agent_config.js +544 -0
  7. package/dist/call_interrupted.d.ts +12 -0
  8. package/dist/call_interrupted.d.ts.map +1 -0
  9. package/dist/call_interrupted.js +11 -0
  10. package/dist/checkpoint_workspace.d.ts +25 -0
  11. package/dist/checkpoint_workspace.d.ts.map +1 -0
  12. package/dist/checkpoint_workspace.js +44 -0
  13. package/dist/context.d.ts +235 -0
  14. package/dist/context.d.ts.map +1 -0
  15. package/dist/context.js +322 -0
  16. package/dist/db_config.d.ts +28 -0
  17. package/dist/db_config.d.ts.map +1 -0
  18. package/dist/db_config.js +66 -0
  19. package/dist/db_naming.d.ts +54 -0
  20. package/dist/db_naming.d.ts.map +1 -0
  21. package/dist/db_naming.js +94 -0
  22. package/dist/error_reporting.d.ts +67 -0
  23. package/dist/error_reporting.d.ts.map +1 -0
  24. package/dist/error_reporting.js +311 -0
  25. package/dist/generated/workflow/v1/activity_pb.d.ts +342 -0
  26. package/dist/generated/workflow/v1/activity_pb.d.ts.map +1 -0
  27. package/dist/generated/workflow/v1/activity_pb.js +115 -0
  28. package/dist/generated/workflow/v1/common_pb.d.ts +184 -0
  29. package/dist/generated/workflow/v1/common_pb.d.ts.map +1 -0
  30. package/dist/generated/workflow/v1/common_pb.js +86 -0
  31. package/dist/generated/workflow/v1/runtime_pb.d.ts +200 -0
  32. package/dist/generated/workflow/v1/runtime_pb.d.ts.map +1 -0
  33. package/dist/generated/workflow/v1/runtime_pb.js +40 -0
  34. package/dist/generated/workflow/v1/state_pb.d.ts +254 -0
  35. package/dist/generated/workflow/v1/state_pb.d.ts.map +1 -0
  36. package/dist/generated/workflow/v1/state_pb.js +68 -0
  37. package/dist/guardrails_evaluator/core.d.ts +23 -0
  38. package/dist/guardrails_evaluator/core.d.ts.map +1 -0
  39. package/dist/guardrails_evaluator/core.js +122 -0
  40. package/dist/guardrails_evaluator/index.d.ts +10 -0
  41. package/dist/guardrails_evaluator/index.d.ts.map +1 -0
  42. package/dist/guardrails_evaluator/index.js +11 -0
  43. package/dist/guardrails_evaluator/regex.d.ts +20 -0
  44. package/dist/guardrails_evaluator/regex.d.ts.map +1 -0
  45. package/dist/guardrails_evaluator/regex.js +233 -0
  46. package/dist/hooks.d.ts +109 -0
  47. package/dist/hooks.d.ts.map +1 -0
  48. package/dist/hooks.js +216 -0
  49. package/dist/http_path.d.ts +18 -0
  50. package/dist/http_path.d.ts.map +1 -0
  51. package/dist/http_path.js +53 -0
  52. package/dist/index.d.ts +35 -0
  53. package/dist/index.d.ts.map +1 -0
  54. package/dist/index.js +41 -0
  55. package/dist/launcher.d.ts +130 -0
  56. package/dist/launcher.d.ts.map +1 -0
  57. package/dist/launcher.js +325 -0
  58. package/dist/logger.d.ts +96 -0
  59. package/dist/logger.d.ts.map +1 -0
  60. package/dist/logger.js +204 -0
  61. package/dist/mcp_oauth.d.ts +51 -0
  62. package/dist/mcp_oauth.d.ts.map +1 -0
  63. package/dist/mcp_oauth.js +389 -0
  64. package/dist/mcp_oauth_secret.d.ts +21 -0
  65. package/dist/mcp_oauth_secret.d.ts.map +1 -0
  66. package/dist/mcp_oauth_secret.js +122 -0
  67. package/dist/mcp_tools.d.ts +71 -0
  68. package/dist/mcp_tools.d.ts.map +1 -0
  69. package/dist/mcp_tools.js +301 -0
  70. package/dist/memory_appbound.d.ts +42 -0
  71. package/dist/memory_appbound.d.ts.map +1 -0
  72. package/dist/memory_appbound.js +159 -0
  73. package/dist/memory_writer.d.ts +49 -0
  74. package/dist/memory_writer.d.ts.map +1 -0
  75. package/dist/memory_writer.js +171 -0
  76. package/dist/metrics.d.ts +84 -0
  77. package/dist/metrics.d.ts.map +1 -0
  78. package/dist/metrics.js +205 -0
  79. package/dist/models.d.ts +1458 -0
  80. package/dist/models.d.ts.map +1 -0
  81. package/dist/models.js +1726 -0
  82. package/dist/node_logger.d.ts +43 -0
  83. package/dist/node_logger.d.ts.map +1 -0
  84. package/dist/node_logger.js +158 -0
  85. package/dist/owner_callback.d.ts +16 -0
  86. package/dist/owner_callback.d.ts.map +1 -0
  87. package/dist/owner_callback.js +40 -0
  88. package/dist/progress.d.ts +57 -0
  89. package/dist/progress.d.ts.map +1 -0
  90. package/dist/progress.js +140 -0
  91. package/dist/runtime.d.ts +131 -0
  92. package/dist/runtime.d.ts.map +1 -0
  93. package/dist/runtime.js +351 -0
  94. package/dist/secure_llm_proxy.d.ts +115 -0
  95. package/dist/secure_llm_proxy.d.ts.map +1 -0
  96. package/dist/secure_llm_proxy.js +922 -0
  97. package/dist/secure_wrapper.d.ts +332 -0
  98. package/dist/secure_wrapper.d.ts.map +1 -0
  99. package/dist/secure_wrapper.js +1249 -0
  100. package/dist/server/aer.d.ts +61 -0
  101. package/dist/server/aer.d.ts.map +1 -0
  102. package/dist/server/aer.js +1124 -0
  103. package/dist/server/auth.d.ts +56 -0
  104. package/dist/server/auth.d.ts.map +1 -0
  105. package/dist/server/auth.js +132 -0
  106. package/dist/server/base.d.ts +104 -0
  107. package/dist/server/base.d.ts.map +1 -0
  108. package/dist/server/base.js +150 -0
  109. package/dist/server/callInterrupt.d.ts +49 -0
  110. package/dist/server/callInterrupt.d.ts.map +1 -0
  111. package/dist/server/callInterrupt.js +68 -0
  112. package/dist/server/callback_delivery.d.ts +14 -0
  113. package/dist/server/callback_delivery.d.ts.map +1 -0
  114. package/dist/server/callback_delivery.js +141 -0
  115. package/dist/server/chunk_types.d.ts +50 -0
  116. package/dist/server/chunk_types.d.ts.map +1 -0
  117. package/dist/server/chunk_types.js +62 -0
  118. package/dist/server/cors.d.ts +52 -0
  119. package/dist/server/cors.d.ts.map +1 -0
  120. package/dist/server/cors.js +107 -0
  121. package/dist/server/drain.d.ts +169 -0
  122. package/dist/server/drain.d.ts.map +1 -0
  123. package/dist/server/drain.js +455 -0
  124. package/dist/server/function.d.ts +77 -0
  125. package/dist/server/function.d.ts.map +1 -0
  126. package/dist/server/function.js +337 -0
  127. package/dist/server/http_retry.d.ts +37 -0
  128. package/dist/server/http_retry.d.ts.map +1 -0
  129. package/dist/server/http_retry.js +157 -0
  130. package/dist/server/index.d.ts +7 -0
  131. package/dist/server/index.d.ts.map +1 -0
  132. package/dist/server/index.js +5 -0
  133. package/dist/server/metadata.d.ts +50 -0
  134. package/dist/server/metadata.d.ts.map +1 -0
  135. package/dist/server/metadata.js +193 -0
  136. package/dist/server/oe_url.d.ts +36 -0
  137. package/dist/server/oe_url.d.ts.map +1 -0
  138. package/dist/server/oe_url.js +50 -0
  139. package/dist/server/owner_url.d.ts +35 -0
  140. package/dist/server/owner_url.d.ts.map +1 -0
  141. package/dist/server/owner_url.js +146 -0
  142. package/dist/server/query.d.ts +42 -0
  143. package/dist/server/query.d.ts.map +1 -0
  144. package/dist/server/query.js +28 -0
  145. package/dist/server/tool.d.ts +138 -0
  146. package/dist/server/tool.d.ts.map +1 -0
  147. package/dist/server/tool.js +1017 -0
  148. package/dist/span_names.d.ts +21 -0
  149. package/dist/span_names.d.ts.map +1 -0
  150. package/dist/span_names.js +31 -0
  151. package/dist/structured_logging/constants.d.ts +17 -0
  152. package/dist/structured_logging/constants.d.ts.map +1 -0
  153. package/dist/structured_logging/constants.js +71 -0
  154. package/dist/structured_logging/env.d.ts +18 -0
  155. package/dist/structured_logging/env.d.ts.map +1 -0
  156. package/dist/structured_logging/env.js +39 -0
  157. package/dist/structured_logging/install.d.ts +56 -0
  158. package/dist/structured_logging/install.d.ts.map +1 -0
  159. package/dist/structured_logging/install.js +107 -0
  160. package/dist/structured_logging/layout.d.ts +9 -0
  161. package/dist/structured_logging/layout.d.ts.map +1 -0
  162. package/dist/structured_logging/layout.js +144 -0
  163. package/dist/structured_logging/serialize.d.ts +27 -0
  164. package/dist/structured_logging/serialize.d.ts.map +1 -0
  165. package/dist/structured_logging/serialize.js +61 -0
  166. package/dist/structured_logging/stdio_capture.d.ts +59 -0
  167. package/dist/structured_logging/stdio_capture.d.ts.map +1 -0
  168. package/dist/structured_logging/stdio_capture.js +164 -0
  169. package/dist/structured_logging/uncaught.d.ts +14 -0
  170. package/dist/structured_logging/uncaught.d.ts.map +1 -0
  171. package/dist/structured_logging/uncaught.js +58 -0
  172. package/dist/structured_logging.d.ts +48 -0
  173. package/dist/structured_logging.d.ts.map +1 -0
  174. package/dist/structured_logging.js +47 -0
  175. package/dist/tls_client.d.ts +61 -0
  176. package/dist/tls_client.d.ts.map +1 -0
  177. package/dist/tls_client.js +298 -0
  178. package/dist/tool_api_error.d.ts +62 -0
  179. package/dist/tool_api_error.d.ts.map +1 -0
  180. package/dist/tool_api_error.js +399 -0
  181. package/dist/tool_memory_ownership.d.ts +10 -0
  182. package/dist/tool_memory_ownership.d.ts.map +1 -0
  183. package/dist/tool_memory_ownership.js +36 -0
  184. package/dist/toolpod_handlers.d.ts +126 -0
  185. package/dist/toolpod_handlers.d.ts.map +1 -0
  186. package/dist/toolpod_handlers.js +1016 -0
  187. package/dist/tracing/exporters.d.ts +51 -0
  188. package/dist/tracing/exporters.d.ts.map +1 -0
  189. package/dist/tracing/exporters.js +327 -0
  190. package/dist/tracing/index.d.ts +3 -0
  191. package/dist/tracing/index.d.ts.map +1 -0
  192. package/dist/tracing/index.js +2 -0
  193. package/dist/tracing/setup.d.ts +76 -0
  194. package/dist/tracing/setup.d.ts.map +1 -0
  195. package/dist/tracing/setup.js +436 -0
  196. package/dist/utils.d.ts +204 -0
  197. package/dist/utils.d.ts.map +1 -0
  198. package/dist/utils.js +867 -0
  199. package/dist/workflow/activity.d.ts +71 -0
  200. package/dist/workflow/activity.d.ts.map +1 -0
  201. package/dist/workflow/activity.js +357 -0
  202. package/dist/workflow/attempt.d.ts +12 -0
  203. package/dist/workflow/attempt.d.ts.map +1 -0
  204. package/dist/workflow/attempt.js +96 -0
  205. package/dist/workflow/client.d.ts +46 -0
  206. package/dist/workflow/client.d.ts.map +1 -0
  207. package/dist/workflow/client.js +299 -0
  208. package/dist/workflow/context.d.ts +37 -0
  209. package/dist/workflow/context.d.ts.map +1 -0
  210. package/dist/workflow/context.js +350 -0
  211. package/dist/workflow/heartbeat.d.ts +15 -0
  212. package/dist/workflow/heartbeat.d.ts.map +1 -0
  213. package/dist/workflow/heartbeat.js +78 -0
  214. package/dist/workflow/index.d.ts +14 -0
  215. package/dist/workflow/index.d.ts.map +1 -0
  216. package/dist/workflow/index.js +10 -0
  217. package/dist/workflow/memory.d.ts +17 -0
  218. package/dist/workflow/memory.d.ts.map +1 -0
  219. package/dist/workflow/memory.js +184 -0
  220. package/package.json +73 -0
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Core guardrail policy evaluation orchestration.
3
+ *
4
+ * Mirrors Python's `agent_engine_runner_shared/guardrails_evaluator/core.py`: a registry of
5
+ * per-`policy_type` engines plus `evaluateGuardrailCheck`, which aggregates the
6
+ * strictest decision across the OE-selected policies for one runtime boundary.
7
+ */
8
+ import { type GuardrailCheckEvidence, type GuardrailCheckRequest, type GuardrailCheckResponse, type GuardrailRuntimePolicy } from "../models.js";
9
+ /** Engine-owned result for a policy evaluation. */
10
+ export interface GuardrailPolicyEngineResult {
11
+ evidence: GuardrailCheckEvidence[];
12
+ transformedText?: string | null;
13
+ }
14
+ /** Contract implemented by native and future remote guardrail engines. */
15
+ export interface GuardrailPolicyEngine {
16
+ readonly policyType: string;
17
+ /** Return engine-owned evidence and optional transformed text when triggered. */
18
+ evaluate(policy: GuardrailRuntimePolicy, text: string): GuardrailPolicyEngineResult | null;
19
+ }
20
+ export declare function registerGuardrailPolicyEngine(engine: GuardrailPolicyEngine): void;
21
+ /** Evaluate guardrail policies for one runtime boundary. */
22
+ export declare function evaluateGuardrailCheck(request: GuardrailCheckRequest): GuardrailCheckResponse;
23
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/guardrails_evaluator/core.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAIL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AActB,mDAAmD;AACnD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAED,0EAA0E;AAC1E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,iFAAiF;IACjF,QAAQ,CACN,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,GACX,2BAA2B,GAAG,IAAI,CAAC;CACvC;AAID,wBAAgB,6BAA6B,CAC3C,MAAM,EAAE,qBAAqB,GAC5B,IAAI,CAEN;AAED,4DAA4D;AAC5D,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,qBAAqB,GAC7B,sBAAsB,CA4GxB"}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Core guardrail policy evaluation orchestration.
3
+ *
4
+ * Mirrors Python's `agent_engine_runner_shared/guardrails_evaluator/core.py`: a registry of
5
+ * per-`policy_type` engines plus `evaluateGuardrailCheck`, which aggregates the
6
+ * strictest decision across the OE-selected policies for one runtime boundary.
7
+ */
8
+ import { getLogger } from "../logger.js";
9
+ import { Metrics } from "../metrics.js";
10
+ import { appliesToStage, checkDecision, GuardrailCheckDecision, } from "../models.js";
11
+ const logger = getLogger("agent_engine_runner_shared.guardrails_evaluator.core");
12
+ const DECISION_PRIORITY = {
13
+ [GuardrailCheckDecision.ALLOW]: 0,
14
+ [GuardrailCheckDecision.LOG_ONLY]: 1,
15
+ [GuardrailCheckDecision.MODIFY]: 2,
16
+ [GuardrailCheckDecision.REQUIRE_REVIEW]: 3,
17
+ [GuardrailCheckDecision.BLOCK]: 4,
18
+ };
19
+ const POLICY_ENGINES = new Map();
20
+ export function registerGuardrailPolicyEngine(engine) {
21
+ POLICY_ENGINES.set(engine.policyType, engine);
22
+ }
23
+ /** Evaluate guardrail policies for one runtime boundary. */
24
+ export function evaluateGuardrailCheck(request) {
25
+ const triggeredPolicyIds = [];
26
+ const evidence = [];
27
+ let transformedText = request.input.text;
28
+ let decision = GuardrailCheckDecision.ALLOW;
29
+ for (const policy of request.policies) {
30
+ if (!appliesToStage(policy, request.stage)) {
31
+ continue;
32
+ }
33
+ const engine = POLICY_ENGINES.get(policy.type);
34
+ if (engine === undefined) {
35
+ // An unsupported policy type cannot be enforced, so fail closed to BLOCK
36
+ // rather than silently allowing content through.
37
+ const reason = `Unsupported guardrail policy type: ${policy.type}`;
38
+ const policyIds = [...triggeredPolicyIds, policy.id];
39
+ return {
40
+ decision: GuardrailCheckDecision.BLOCK,
41
+ allowed: false,
42
+ transformed_text: null,
43
+ triggered_policy_ids: policyIds,
44
+ evidence: [
45
+ ...evidence,
46
+ {
47
+ policy_id: policy.id,
48
+ message: reason,
49
+ metadata: { policy_type: policy.type },
50
+ },
51
+ ],
52
+ reason,
53
+ metadata: { triggered_count: policyIds.length },
54
+ };
55
+ }
56
+ let policyDecision = checkDecision(policy);
57
+ const shouldTransform = policyDecision === GuardrailCheckDecision.MODIFY;
58
+ const result = engine.evaluate(policy, transformedText);
59
+ if (result === null) {
60
+ continue;
61
+ }
62
+ // A policy that actually triggered but whose `action` (and `on_fail`) does
63
+ // not resolve to a known verb would otherwise fall through to ALLOW and let
64
+ // the matching content pass. That is fail-open on a misconfiguration (e.g.
65
+ // an operator typo), and inconsistent with the fail-closed handling of an
66
+ // unknown policy type above. Fail closed to BLOCK and make the misconfig
67
+ // observable instead.
68
+ if (policyDecision === GuardrailCheckDecision.ALLOW) {
69
+ logger.warn(`Guardrail policy ${policy.id} triggered but its action ` +
70
+ `"${policy.action}" did not resolve to a known decision; ` +
71
+ `failing closed to BLOCK`);
72
+ Metrics.recordError("guardrails_unresolved_action", {
73
+ policy_id: policy.id,
74
+ });
75
+ policyDecision = GuardrailCheckDecision.BLOCK;
76
+ }
77
+ evidence.push(...result.evidence);
78
+ if (shouldTransform && result.transformedText != null) {
79
+ transformedText = result.transformedText;
80
+ }
81
+ triggeredPolicyIds.push(policy.id);
82
+ if (DECISION_PRIORITY[policyDecision] > DECISION_PRIORITY[decision]) {
83
+ decision = policyDecision;
84
+ }
85
+ }
86
+ if (decision === GuardrailCheckDecision.ALLOW) {
87
+ return {
88
+ decision: GuardrailCheckDecision.ALLOW,
89
+ allowed: true,
90
+ transformed_text: request.input.text,
91
+ triggered_policy_ids: [],
92
+ evidence: [],
93
+ reason: null,
94
+ metadata: {},
95
+ };
96
+ }
97
+ const policyCount = triggeredPolicyIds.length;
98
+ let reason;
99
+ if (decision === GuardrailCheckDecision.BLOCK) {
100
+ reason = `${policyCount} guardrail policy triggered a block decision`;
101
+ }
102
+ else if (decision === GuardrailCheckDecision.REQUIRE_REVIEW) {
103
+ reason = `${policyCount} guardrail policy requires review`;
104
+ }
105
+ else if (decision === GuardrailCheckDecision.MODIFY) {
106
+ reason = `${policyCount} guardrail policy modified the content`;
107
+ }
108
+ else {
109
+ reason = `${policyCount} guardrail policy triggered`;
110
+ }
111
+ const allowed = decision === GuardrailCheckDecision.LOG_ONLY ||
112
+ decision === GuardrailCheckDecision.MODIFY;
113
+ return {
114
+ decision,
115
+ allowed,
116
+ transformed_text: allowed ? transformedText : null,
117
+ triggered_policy_ids: triggeredPolicyIds,
118
+ evidence,
119
+ reason,
120
+ metadata: { triggered_count: policyCount },
121
+ };
122
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Guardrails evaluator public surface.
3
+ *
4
+ * Importing this module registers the native `output_validation` regex engine
5
+ * as a side effect (mirroring Python's `guardrails_evaluator/__init__.py`), so
6
+ * `evaluateGuardrailCheck` can resolve it without an explicit registration call.
7
+ */
8
+ export { evaluateGuardrailCheck, registerGuardrailPolicyEngine, type GuardrailPolicyEngine, type GuardrailPolicyEngineResult, } from "./core.js";
9
+ export { OutputValidationPolicyEngine, registerRegexGuardrailPolicyEngine, } from "./regex.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guardrails_evaluator/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EACL,sBAAsB,EACtB,6BAA6B,EAC7B,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,GACjC,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Guardrails evaluator public surface.
3
+ *
4
+ * Importing this module registers the native `output_validation` regex engine
5
+ * as a side effect (mirroring Python's `guardrails_evaluator/__init__.py`), so
6
+ * `evaluateGuardrailCheck` can resolve it without an explicit registration call.
7
+ */
8
+ import { registerRegexGuardrailPolicyEngine } from "./regex.js";
9
+ registerRegexGuardrailPolicyEngine();
10
+ export { evaluateGuardrailCheck, registerGuardrailPolicyEngine, } from "./core.js";
11
+ export { OutputValidationPolicyEngine, registerRegexGuardrailPolicyEngine, } from "./regex.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Regex guardrail policy engine (`output_validation`).
3
+ *
4
+ * Mirrors Python's `agent_engine_runner_shared/guardrails_evaluator/regex.py`, with one
5
+ * deliberate divergence: Python uses the `regex` module's per-call `timeout=`
6
+ * to bound each pattern. Stock JS `RegExp` has no per-match timeout, so a single
7
+ * catastrophically-backtracking pattern cannot be interrupted mid-match. Per the
8
+ * approved scope we bound risk with a
9
+ * total wall-clock deadline checked *between* patterns plus hard pattern-count
10
+ * and input-length caps, and emit a `guardrails_regex_overrun` metric so the
11
+ * alarm signal exists if we later need RE2/worker isolation (option (b)).
12
+ */
13
+ import { type GuardrailRuntimePolicy } from "../models.js";
14
+ import { type GuardrailPolicyEngine, type GuardrailPolicyEngineResult } from "./core.js";
15
+ export declare class OutputValidationPolicyEngine implements GuardrailPolicyEngine {
16
+ readonly policyType = "output_validation";
17
+ evaluate(policy: GuardrailRuntimePolicy, text: string): GuardrailPolicyEngineResult | null;
18
+ }
19
+ export declare function registerRegexGuardrailPolicyEngine(): void;
20
+ //# sourceMappingURL=regex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.d.ts","sourceRoot":"","sources":["../../src/guardrails_evaluator/regex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAIL,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,2BAA2B,EACjC,MAAM,WAAW,CAAC;AAuBnB,qBAAa,4BAA6B,YAAW,qBAAqB;IACxE,QAAQ,CAAC,UAAU,uBAAiC;IAEpD,QAAQ,CACN,MAAM,EAAE,sBAAsB,EAC9B,IAAI,EAAE,MAAM,GACX,2BAA2B,GAAG,IAAI;CAkEtC;AAED,wBAAgB,kCAAkC,IAAI,IAAI,CAEzD"}
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Regex guardrail policy engine (`output_validation`).
3
+ *
4
+ * Mirrors Python's `agent_engine_runner_shared/guardrails_evaluator/regex.py`, with one
5
+ * deliberate divergence: Python uses the `regex` module's per-call `timeout=`
6
+ * to bound each pattern. Stock JS `RegExp` has no per-match timeout, so a single
7
+ * catastrophically-backtracking pattern cannot be interrupted mid-match. Per the
8
+ * approved scope we bound risk with a
9
+ * total wall-clock deadline checked *between* patterns plus hard pattern-count
10
+ * and input-length caps, and emit a `guardrails_regex_overrun` metric so the
11
+ * alarm signal exists if we later need RE2/worker isolation (option (b)).
12
+ */
13
+ import { getLogger } from "../logger.js";
14
+ import { Metrics } from "../metrics.js";
15
+ import { checkDecision, GuardrailCheckDecision, } from "../models.js";
16
+ import { registerGuardrailPolicyEngine, } from "./core.js";
17
+ const DEFAULT_REPLACEMENT_TEXT = "[BLOCKED]";
18
+ const OUTPUT_VALIDATION_POLICY_TYPE = "output_validation";
19
+ const MAX_REGEX_PATTERNS = 100;
20
+ const MAX_REGEX_TEXT_LENGTH = 20_000;
21
+ const TOTAL_REGEX_TIMEOUT_MS = 200;
22
+ const logger = getLogger("agent_engine_runner_shared.guardrails_evaluator.regex");
23
+ export class OutputValidationPolicyEngine {
24
+ policyType = OUTPUT_VALIDATION_POLICY_TYPE;
25
+ evaluate(policy, text) {
26
+ const { patterns, invalidPatterns } = compileRegexPatterns(policy);
27
+ const checkedPatterns = patterns.slice(0, MAX_REGEX_PATTERNS);
28
+ let skippedPatterns = patterns
29
+ .slice(MAX_REGEX_PATTERNS)
30
+ .map((p) => p.pattern);
31
+ const textTooLong = text.length > MAX_REGEX_TEXT_LENGTH;
32
+ if (skippedPatterns.length > 0) {
33
+ logger.warn(`Guardrail policy ${policy.id} has ${patterns.length} regex patterns, ` +
34
+ `exceeding max ${MAX_REGEX_PATTERNS}; skipping ${skippedPatterns.length} patterns`);
35
+ }
36
+ let matches;
37
+ let timedOutPatterns;
38
+ if (textTooLong) {
39
+ logger.warn(`Guardrail policy ${policy.id} regex input length ${text.length} ` +
40
+ `exceeds max ${MAX_REGEX_TEXT_LENGTH}; failing closed`);
41
+ matches = [];
42
+ timedOutPatterns = [];
43
+ skippedPatterns = patterns.map((p) => p.pattern);
44
+ }
45
+ else {
46
+ ({ matches, timedOutPatterns } = findRegexMatches(text, checkedPatterns, policy.id));
47
+ }
48
+ if (matches.length === 0 &&
49
+ timedOutPatterns.length === 0 &&
50
+ skippedPatterns.length === 0 &&
51
+ invalidPatterns.length === 0) {
52
+ return null;
53
+ }
54
+ const replacementText = replacementTextFor(policy);
55
+ // An invalid pattern means the policy cannot be enforced as written, so it
56
+ // fails closed alongside timed-out and skipped patterns rather than silently
57
+ // passing content through as a clean allow.
58
+ const failClosed = timedOutPatterns.length > 0 ||
59
+ skippedPatterns.length > 0 ||
60
+ invalidPatterns.length > 0;
61
+ return {
62
+ evidence: [
63
+ regexEvidence(policy, matches, timedOutPatterns, skippedPatterns, invalidPatterns, textTooLong),
64
+ ],
65
+ transformedText: failClosed
66
+ ? replacementText
67
+ : redactPatterns(text, matches, replacementText),
68
+ };
69
+ }
70
+ }
71
+ export function registerRegexGuardrailPolicyEngine() {
72
+ registerGuardrailPolicyEngine(new OutputValidationPolicyEngine());
73
+ }
74
+ function findRegexMatches(text, patterns, policyId) {
75
+ const matches = [];
76
+ const timedOutPatterns = [];
77
+ const deadline = performance.now() + TOTAL_REGEX_TIMEOUT_MS;
78
+ for (let index = 0; index < patterns.length; index += 1) {
79
+ if (performance.now() >= deadline) {
80
+ // Deadline exceeded: JS cannot interrupt a running match, so the best we
81
+ // can do is stop before the remaining patterns and fail closed on them.
82
+ timedOutPatterns.push(...patterns.slice(index).map((p) => p.pattern));
83
+ Metrics.recordError("guardrails_regex_overrun", { policy_id: policyId });
84
+ logger.warn(`Guardrail policy ${policyId} regex evaluation exceeded ` +
85
+ `${TOTAL_REGEX_TIMEOUT_MS}ms; failing closed on ` +
86
+ `${patterns.length - index} remaining patterns`);
87
+ break;
88
+ }
89
+ const pattern = patterns[index];
90
+ for (const match of text.matchAll(pattern.compiled)) {
91
+ // `match.index` is typed as optional; a `NaN`/undefined start would
92
+ // corrupt the sort and span-merge redaction below, so skip such matches
93
+ // rather than emit a match with a `NaN` offset.
94
+ const start = match.index;
95
+ if (start === undefined || Number.isNaN(start)) {
96
+ continue;
97
+ }
98
+ matches.push({
99
+ pattern: pattern.pattern,
100
+ start,
101
+ end: start + match[0].length,
102
+ });
103
+ }
104
+ }
105
+ matches.sort((a, b) => a.start - b.start || a.end - b.end);
106
+ return { matches, timedOutPatterns };
107
+ }
108
+ function regexEvidence(policy, matches, timedOutPatterns, skippedPatterns, invalidPatterns, textTooLong) {
109
+ const matchedPatterns = [...new Set(matches.map((m) => m.pattern))];
110
+ const triggeredPatterns = [
111
+ ...new Set([
112
+ ...matchedPatterns,
113
+ ...timedOutPatterns,
114
+ ...skippedPatterns,
115
+ ...invalidPatterns,
116
+ ]),
117
+ ];
118
+ const regexMatches = matches.map(regexMatchMetadata);
119
+ return {
120
+ policy_id: policy.id,
121
+ message: regexEvidenceMessage(policy, triggeredPatterns, invalidPatterns, textTooLong || timedOutPatterns.length > 0 || skippedPatterns.length > 0),
122
+ metadata: {
123
+ engine: OUTPUT_VALIDATION_POLICY_TYPE,
124
+ validator: "regex_match",
125
+ matched_patterns: matchedPatterns,
126
+ timed_out_patterns: timedOutPatterns,
127
+ skipped_patterns: skippedPatterns,
128
+ invalid_patterns: invalidPatterns,
129
+ text_too_long: textTooLong,
130
+ matches: regexMatches,
131
+ regex_matches: regexMatches,
132
+ },
133
+ };
134
+ }
135
+ function regexEvidenceMessage(policy, triggeredPatterns, invalidPatterns, safetyLimited) {
136
+ const patternSummary = triggeredPatterns.join(", ");
137
+ if (invalidPatterns.length > 0) {
138
+ return ("Regex guardrail failed closed; invalid patterns could not be " +
139
+ `evaluated: ${invalidPatterns.join(", ")}`);
140
+ }
141
+ if (safetyLimited) {
142
+ return `Regex evaluation exceeded safety limits: ${patternSummary}`;
143
+ }
144
+ const decision = checkDecision(policy);
145
+ if (triggeredPatterns.length > 0 &&
146
+ decision === GuardrailCheckDecision.BLOCK) {
147
+ return `Regex match blocked content: ${patternSummary}`;
148
+ }
149
+ if (triggeredPatterns.length > 0 &&
150
+ decision === GuardrailCheckDecision.MODIFY) {
151
+ return `Regex match modified content: ${patternSummary}`;
152
+ }
153
+ if (triggeredPatterns.length > 0 &&
154
+ decision === GuardrailCheckDecision.LOG_ONLY) {
155
+ return `Regex match logged: ${patternSummary}`;
156
+ }
157
+ if (triggeredPatterns.length > 0 &&
158
+ decision === GuardrailCheckDecision.REQUIRE_REVIEW) {
159
+ return `Regex match requires review: ${patternSummary}`;
160
+ }
161
+ return `Regex match triggered: ${patternSummary}`;
162
+ }
163
+ function regexMatchMetadata(match) {
164
+ return {
165
+ pattern: match.pattern,
166
+ start: match.start,
167
+ end: match.end,
168
+ length: match.end - match.start,
169
+ };
170
+ }
171
+ function redactPatterns(text, matches, replacementText) {
172
+ let redacted = text;
173
+ const spans = mergedSpans(matches);
174
+ for (let i = spans.length - 1; i >= 0; i -= 1) {
175
+ const [start, end] = spans[i];
176
+ redacted = `${redacted.slice(0, start)}${replacementText}${redacted.slice(end)}`;
177
+ }
178
+ return redacted;
179
+ }
180
+ function mergedSpans(matches) {
181
+ const spans = [];
182
+ const sorted = [...matches].sort((a, b) => a.start - b.start || a.end - b.end);
183
+ for (const match of sorted) {
184
+ if (match.start === match.end) {
185
+ continue;
186
+ }
187
+ const last = spans[spans.length - 1];
188
+ if (last === undefined || match.start > last[1]) {
189
+ spans.push([match.start, match.end]);
190
+ continue;
191
+ }
192
+ last[1] = Math.max(last[1], match.end);
193
+ }
194
+ return spans;
195
+ }
196
+ /**
197
+ * Compile configured patterns, returning valid patterns and the raw strings of
198
+ * any that failed to compile. Un-compilable patterns are surfaced (not dropped)
199
+ * so the caller can fail closed — a pattern that cannot compile means the
200
+ * operator's policy is not being enforced as written. The warning omits the
201
+ * pattern text to avoid leaking policy content into logs; the pattern is still
202
+ * returned so it can appear in operator-facing evidence.
203
+ */
204
+ function compileRegexPatterns(policy) {
205
+ const raw = policy.config.regex_patterns;
206
+ if (!Array.isArray(raw)) {
207
+ return { patterns: [], invalidPatterns: [] };
208
+ }
209
+ const patterns = [];
210
+ const invalidPatterns = [];
211
+ for (const value of raw) {
212
+ if (typeof value !== "string") {
213
+ continue;
214
+ }
215
+ const pattern = value.trim();
216
+ if (pattern === "") {
217
+ continue;
218
+ }
219
+ try {
220
+ // `g` for finditer-style global scan, `i` to mirror Python's IGNORECASE.
221
+ patterns.push({ pattern, compiled: new RegExp(pattern, "gi") });
222
+ }
223
+ catch {
224
+ logger.warn(`Invalid guardrail regex pattern for policy ${policy.id}; failing closed`);
225
+ invalidPatterns.push(pattern);
226
+ }
227
+ }
228
+ return { patterns, invalidPatterns };
229
+ }
230
+ function replacementTextFor(policy) {
231
+ const value = policy.config.replacement_text;
232
+ return typeof value === "string" ? value : DEFAULT_REPLACEMENT_TEXT;
233
+ }
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Framework hook registry for runner-shared.
3
+ *
4
+ * Most hooks are registered once at process startup by the framework SDK
5
+ * before the server starts. The workflow adapter is the exception: it is
6
+ * register-or-clear on every graph materialization so eligibility cannot
7
+ * leak from a durable graph into a later native one. Consumers in
8
+ * runner-shared call `get*()` instead of importing framework-specific
9
+ * modules directly.
10
+ *
11
+ * Type aliases use sdk-core interfaces where possible. The suspend handler
12
+ * remains loosely typed because its signature is framework-specific
13
+ * (e.g. langgraph's `interrupt` returns whatever the resume caller provides).
14
+ */
15
+ import type { BaseLLM } from "@mongodb-js/agent-engine-sdk";
16
+ import type { AERQueryPlugin } from "./server/query.js";
17
+ export type SuspendHandler = (payload: Record<string, unknown>) => Record<string, unknown>;
18
+ export type LLMAdapterFactory = (rawLlm: unknown, options?: {
19
+ tools?: unknown[];
20
+ tool_choice?: unknown;
21
+ }) => BaseLLM;
22
+ export type Instrumentor = () => void;
23
+ export interface WorkflowAdapter {
24
+ readonly name: string;
25
+ readonly version: string;
26
+ }
27
+ /**
28
+ * Mark the dynamic extent of the user's @app.entrypoint call.
29
+ *
30
+ * **Framework-internal — user agent code must never call this.** Users only
31
+ * declare an entrypoint (`app.entrypoint(fn)`); the framework SDK wraps its
32
+ * own evaluation of that function (during AER graph construction and
33
+ * during Tool preparation, retried after failure) in this helper so
34
+ * that `registerLlm()` can reject `app.llm()` calls made outside the
35
+ * entrypoint. Tests that call `app.llm()`/`registerLlm()` directly (bypassing
36
+ * `app.entrypoint` + `getAgent()`) use it to simulate that framework
37
+ * evaluation.
38
+ */
39
+ export declare function entrypointScope<T>(fn: () => T): T;
40
+ export declare function registerSuspendHandler(handler: SuspendHandler): void;
41
+ export declare function getSuspendHandler(): SuspendHandler | null;
42
+ export declare function registerLLMAdapterFactory(factory: LLMAdapterFactory): void;
43
+ export declare function getLLMAdapterFactory(): LLMAdapterFactory;
44
+ export declare function registerInstrumentor(fn: Instrumentor): void;
45
+ export declare function getInstrumentor(): Instrumentor | null;
46
+ /**
47
+ * Register the framework adapter's `AERQueryPlugin`.
48
+ *
49
+ * Mirrors Python's `TenantRuntime.register_query_plugin`. The AER's
50
+ * `/query/sessions` routes return 501 until a plugin is registered.
51
+ */
52
+ export declare function registerQueryPlugin(plugin: AERQueryPlugin): void;
53
+ /** Return the registered `AERQueryPlugin`, or `null` if none has been registered. */
54
+ export declare function getQueryPlugin(): AERQueryPlugin | null;
55
+ /**
56
+ * Declare that the materialized graph supports OE durable workflow routing.
57
+ *
58
+ * Call this or {@link clearWorkflowAdapter} on every `getAgent()` materialization
59
+ * so a later ineligible graph cannot reuse the previous request's identity.
60
+ */
61
+ export declare function registerWorkflowAdapter(name: string, version: string): void;
62
+ /** Drop durable eligibility for the latest materialized graph. */
63
+ export declare function clearWorkflowAdapter(): void;
64
+ export declare function getWorkflowAdapter(): WorkflowAdapter | null;
65
+ /**
66
+ * Register an LLM by id. Throws on duplicate id.
67
+ *
68
+ * Framework SDKs call this from `app.llm()` for every LLM the agent uses.
69
+ * The unnamed-LLM convenience case is represented by registering under the
70
+ * sentinel id `"__default__"`; a second unnamed call therefore raises the
71
+ * same duplicate-id error as a second named call with the same id.
72
+ */
73
+ export declare function registerLlm(llmId: string, llm: unknown): void;
74
+ export declare function getNamedLlm(llmId: string): unknown;
75
+ export declare function hasNamedLlms(): boolean;
76
+ export declare function resetLlmRegistry(): void;
77
+ /** Return a shallow copy of the current registry. */
78
+ export declare function snapshotLlmRegistry(): Map<string, unknown>;
79
+ export declare function resetHooks(): void;
80
+ /**
81
+ * Run the user's agent entrypoint to populate the named-LLM registry.
82
+ *
83
+ * Resets the registry before invoking `graphBuilder.getAgent()` so
84
+ * import-time registrations don't collide if the entrypoint re-registers
85
+ * them. If the entrypoint registers nothing, restores the pre-reset snapshot
86
+ * so import-time-only agents still work.
87
+ *
88
+ * Returns false after failed construction, including when a snapshot is restored.
89
+ * Successful construction with no named LLMs is still complete.
90
+ *
91
+ * `onEntrypointError`, when supplied, receives the thrown value on that same
92
+ * path so the caller can attribute a later registry lookup miss to its real
93
+ * cause rather than to a missing `app.llm()` call.
94
+ *
95
+ * Shared by ToolServer.onStartup and ToolFunctionRunner._prepare — mirrors
96
+ * Python's ToolExecution.prepare() which both inherit.
97
+ *
98
+ * @internal — exported for server/ consumers; not part of the public API.
99
+ */
100
+ export declare function populateLlmRegistryFromEntrypoint(graphBuilder: {
101
+ getAgent?: () => unknown;
102
+ } | null, logger: {
103
+ warn(msg: string): void;
104
+ info(msg: string): void;
105
+ }, warnings: {
106
+ entrypointFailed: string;
107
+ noLlmRegistered: string;
108
+ }, onEntrypointError?: (error: unknown) => void): boolean;
109
+ //# sourceMappingURL=hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../src/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8BAA8B,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAIxD,MAAM,MAAM,cAAc,GAAG,CAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7B,MAAM,MAAM,iBAAiB,GAAG,CAC9B,MAAM,EAAE,OAAO,EACf,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,KACnD,OAAO,CAAC;AAEb,MAAM,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC;AACtC,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAiBD;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAQjD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI,CAEpE;AAED,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,IAAI,CAEzD;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAE1E;AAED,wBAAgB,oBAAoB,IAAI,iBAAiB,CAOxD;AAED,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CAE3D;AAED,wBAAgB,eAAe,IAAI,YAAY,GAAG,IAAI,CAErD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,cAAc,GAAG,IAAI,CAEhE;AAED,qFAAqF;AACrF,wBAAgB,cAAc,IAAI,cAAc,GAAG,IAAI,CAEtD;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK3E;AAED,kEAAkE;AAClE,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,wBAAgB,kBAAkB,IAAI,eAAe,GAAG,IAAI,CAE3D;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,GAAG,IAAI,CAe7D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAQlD;AAED,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED,qDAAqD;AACrD,wBAAgB,mBAAmB,IAAI,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAE1D;AAED,wBAAgB,UAAU,IAAI,IAAI,CASjC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iCAAiC,CAC/C,YAAY,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAA;CAAE,GAAG,IAAI,EACjD,MAAM,EAAE;IAAE,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,EAC5D,QAAQ,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,EAC/D,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAC3C,OAAO,CA+CT"}