@sponsio/sdk 0.1.0 → 0.2.0-alpha.8

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 (123) hide show
  1. package/contracts/benchmark/agentdojo.yaml +551 -0
  2. package/contracts/benchmark/odcv_bench.yaml +393 -0
  3. package/contracts/benchmark/redcode_exec.yaml +488 -0
  4. package/contracts/benchmark/swebench.yaml +176 -0
  5. package/contracts/benchmark/tau2_bench.yaml +984 -0
  6. package/contracts/capability/destructive.yaml +213 -0
  7. package/contracts/capability/factual-claims.yaml +79 -0
  8. package/contracts/capability/host-config-integrity.yaml +42 -9
  9. package/contracts/capability/self-modify.yaml +32 -1
  10. package/contracts/capability/shell.yaml +19 -10
  11. package/contracts/incident/claude-code-secret-bypass.yaml +48 -16
  12. package/contracts/incident/cursor-railway-wipe.yaml +60 -4
  13. package/contracts/incident/openclaw.yaml +9 -62
  14. package/contracts/premium/.gitkeep +5 -6
  15. package/dist/cli/cli.js +32 -0
  16. package/dist/cli/cli.js.map +1 -1
  17. package/dist/cli/packs.d.ts.map +1 -1
  18. package/dist/cli/packs.js +14 -8
  19. package/dist/cli/packs.js.map +1 -1
  20. package/dist/cli/patterns.d.ts +5 -4
  21. package/dist/cli/patterns.d.ts.map +1 -1
  22. package/dist/cli/patterns.js +11 -10
  23. package/dist/cli/patterns.js.map +1 -1
  24. package/dist/cli/prompt.js +5 -5
  25. package/dist/cli/prompt.js.map +1 -1
  26. package/dist/cli/scan.js +2 -2
  27. package/dist/cli/skill.d.ts +1 -1
  28. package/dist/cli/skill.js +1 -1
  29. package/dist/cli/validate.js +5 -5
  30. package/dist/cli/validate.js.map +1 -1
  31. package/dist/cloud/client.d.ts +76 -0
  32. package/dist/cloud/client.d.ts.map +1 -0
  33. package/dist/cloud/client.js +198 -0
  34. package/dist/cloud/client.js.map +1 -0
  35. package/dist/cloud/evidence.d.ts +108 -0
  36. package/dist/cloud/evidence.d.ts.map +1 -0
  37. package/dist/cloud/evidence.js +184 -0
  38. package/dist/cloud/evidence.js.map +1 -0
  39. package/dist/cloud/privacy.d.ts +67 -0
  40. package/dist/cloud/privacy.d.ts.map +1 -0
  41. package/dist/cloud/privacy.js +170 -0
  42. package/dist/cloud/privacy.js.map +1 -0
  43. package/dist/cloud/view-model.d.ts +49 -0
  44. package/dist/cloud/view-model.d.ts.map +1 -0
  45. package/dist/cloud/view-model.js +172 -0
  46. package/dist/cloud/view-model.js.map +1 -0
  47. package/dist/core/config-loader.d.ts.map +1 -1
  48. package/dist/core/config-loader.js +81 -9
  49. package/dist/core/config-loader.js.map +1 -1
  50. package/dist/core/evaluator.d.ts +11 -1
  51. package/dist/core/evaluator.d.ts.map +1 -1
  52. package/dist/core/evaluator.js +275 -13
  53. package/dist/core/evaluator.js.map +1 -1
  54. package/dist/core/formula.d.ts +76 -17
  55. package/dist/core/formula.d.ts.map +1 -1
  56. package/dist/core/formula.js +83 -1
  57. package/dist/core/formula.js.map +1 -1
  58. package/dist/core/grounding.d.ts +44 -8
  59. package/dist/core/grounding.d.ts.map +1 -1
  60. package/dist/core/grounding.js +197 -26
  61. package/dist/core/grounding.js.map +1 -1
  62. package/dist/core/nl-parser.d.ts +2 -2
  63. package/dist/core/nl-parser.d.ts.map +1 -1
  64. package/dist/core/nl-parser.js +617 -41
  65. package/dist/core/nl-parser.js.map +1 -1
  66. package/dist/core/pack-loader.d.ts.map +1 -1
  67. package/dist/core/pack-loader.js +14 -2
  68. package/dist/core/pack-loader.js.map +1 -1
  69. package/dist/core/parser.d.ts.map +1 -1
  70. package/dist/core/parser.js +30 -1
  71. package/dist/core/parser.js.map +1 -1
  72. package/dist/core/pattern-factory.d.ts.map +1 -1
  73. package/dist/core/pattern-factory.js +14 -1
  74. package/dist/core/pattern-factory.js.map +1 -1
  75. package/dist/core/patterns.d.ts +118 -1
  76. package/dist/core/patterns.d.ts.map +1 -1
  77. package/dist/core/patterns.js +189 -10
  78. package/dist/core/patterns.js.map +1 -1
  79. package/dist/core/session-log.d.ts.map +1 -1
  80. package/dist/core/session-log.js +20 -1
  81. package/dist/core/session-log.js.map +1 -1
  82. package/dist/core/sto.d.ts +21 -27
  83. package/dist/core/sto.d.ts.map +1 -1
  84. package/dist/core/sto.js +30 -33
  85. package/dist/core/sto.js.map +1 -1
  86. package/dist/core/tool-names.d.ts +59 -0
  87. package/dist/core/tool-names.d.ts.map +1 -0
  88. package/dist/core/tool-names.js +128 -0
  89. package/dist/core/tool-names.js.map +1 -0
  90. package/dist/index.d.ts +181 -32
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +415 -67
  93. package/dist/index.js.map +1 -1
  94. package/dist/integrations/claude-agent.d.ts +5 -0
  95. package/dist/integrations/claude-agent.d.ts.map +1 -1
  96. package/dist/integrations/claude-agent.js +42 -13
  97. package/dist/integrations/claude-agent.js.map +1 -1
  98. package/dist/integrations/google-adk.d.ts +5 -3
  99. package/dist/integrations/google-adk.d.ts.map +1 -1
  100. package/dist/integrations/google-adk.js +9 -5
  101. package/dist/integrations/google-adk.js.map +1 -1
  102. package/dist/integrations/langchain.d.ts +7 -0
  103. package/dist/integrations/langchain.d.ts.map +1 -1
  104. package/dist/integrations/langchain.js +21 -3
  105. package/dist/integrations/langchain.js.map +1 -1
  106. package/dist/integrations/openai-agents.d.ts +22 -10
  107. package/dist/integrations/openai-agents.d.ts.map +1 -1
  108. package/dist/integrations/openai-agents.js +55 -15
  109. package/dist/integrations/openai-agents.js.map +1 -1
  110. package/dist/integrations/openai.d.ts +11 -0
  111. package/dist/integrations/openai.d.ts.map +1 -1
  112. package/dist/integrations/openai.js +130 -48
  113. package/dist/integrations/openai.js.map +1 -1
  114. package/dist/integrations/vercel-ai.d.ts +20 -9
  115. package/dist/integrations/vercel-ai.d.ts.map +1 -1
  116. package/dist/integrations/vercel-ai.js +131 -32
  117. package/dist/integrations/vercel-ai.js.map +1 -1
  118. package/package.json +17 -9
  119. package/prompts/onboard.md +26 -17
  120. package/prompts/scan.md +3 -5
  121. package/skills/SKILL.md +13 -83
  122. package/contracts/core/llm_safety.yaml +0 -140
  123. package/prompts/refresh.md +0 -118
@@ -8,64 +8,146 @@
8
8
  * const guard = new Sponsio({ contracts: [...] })
9
9
  * const client = wrapOpenAI(new OpenAI(), guard)
10
10
  *
11
+ * Covers ``chat.completions.create`` / ``parse`` and, when the client has
12
+ * it, ``responses.create`` / ``parse``. Every tool call the model emits
13
+ * is checked before the caller's tool loop can run it; refused calls are
14
+ * removed from the response and a ``[BLOCKED] <tool>: <reason>`` line is
15
+ * added to the assistant text so the model learns why.
16
+ *
17
+ * ``stream: true`` throws at call time on every wrapped method: tool
18
+ * calls arrive as deltas and could only be checked after the caller has
19
+ * already assembled and run them. Call without ``stream``, or run your
20
+ * own executor through ``guard.guardBefore()`` before each tool call.
21
+ *
11
22
  * ``patchOpenAI`` is an alias matching Python's ``patch_openai``
12
23
  * factory (same monkey-patch semantics — no wrapped return value
13
24
  * required; the client passed in is mutated in place).
14
25
  */
26
+ const STREAM_UNSUPPORTED = "sponsio: the OpenAI guard does not support stream: true. Tool calls " +
27
+ "arrive as deltas and could only be checked after the caller has already " +
28
+ "assembled and run them. Call without stream, or run your own executor " +
29
+ "through guard.guardBefore() before each tool call.";
15
30
  export function wrapOpenAI(client, guard) {
16
31
  const c = client;
17
- const original = c.chat.completions.create.bind(c.chat.completions);
18
- c.chat.completions.create = async function (...args) {
19
- const response = await original(...args);
20
- for (const choice of response.choices ?? []) {
21
- const msg = choice.message;
22
- if (!msg?.tool_calls)
32
+ const completions = c?.chat?.completions;
33
+ if (!completions || typeof completions.create !== "function") {
34
+ throw new TypeError("wrapOpenAI: expected an OpenAI client with chat.completions.create");
35
+ }
36
+ patchMethod(completions, "create", guard, "chat");
37
+ patchMethod(completions, "parse", guard, "chat");
38
+ if (c.responses) {
39
+ patchMethod(c.responses, "create", guard, "responses");
40
+ patchMethod(c.responses, "parse", guard, "responses");
41
+ }
42
+ return client;
43
+ }
44
+ function patchMethod(target, name, guard, kind) {
45
+ const original = target[name];
46
+ if (typeof original !== "function")
47
+ return;
48
+ const bound = original.bind(target);
49
+ target[name] = async function (...args) {
50
+ const params = args[0];
51
+ if (params && typeof params === "object" && params.stream) {
52
+ throw new Error(STREAM_UNSUPPORTED);
53
+ }
54
+ const response = await bound(...args);
55
+ return kind === "chat"
56
+ ? guardChatResponse(response, guard)
57
+ : guardResponsesOutput(response, guard);
58
+ };
59
+ }
60
+ /**
61
+ * Decide one emitted call. Malformed JSON arguments are refused in
62
+ * enforce mode without touching the trace (a call that never runs must
63
+ * not count as a call); in observe mode they pass through and are
64
+ * recorded with a sentinel so the session log shows what arrived.
65
+ */
66
+ function decide(guard, toolName, rawArgs) {
67
+ let args;
68
+ try {
69
+ const parsed = JSON.parse(rawArgs || "{}");
70
+ args =
71
+ parsed && typeof parsed === "object" && !Array.isArray(parsed)
72
+ ? parsed
73
+ : { input: parsed };
74
+ }
75
+ catch {
76
+ if (guard.mode === "enforce") {
77
+ return {
78
+ blocked: true,
79
+ note: `[BLOCKED] ${toolName}: malformed JSON arguments — refusing to forward to the tool loop`,
80
+ };
81
+ }
82
+ args = { _sponsio_malformed_args: rawArgs ?? "" };
83
+ }
84
+ const result = guard.guardBefore(toolName, args);
85
+ // ``stopOriginal`` covers a redirect verdict as well as a block: the
86
+ // wrapper has no substitution path, so a redirect strips the call.
87
+ if (result.stopOriginal) {
88
+ return { blocked: true, note: `[BLOCKED] ${toolName}: ${result.message}` };
89
+ }
90
+ return { blocked: false };
91
+ }
92
+ function guardChatResponse(response, guard) {
93
+ for (const choice of response?.choices ?? []) {
94
+ const msg = choice.message;
95
+ if (!msg?.tool_calls)
96
+ continue;
97
+ const kept = [];
98
+ const blocked = [];
99
+ for (const tc of msg.tool_calls) {
100
+ const d = decide(guard, tc.function.name, tc.function.arguments);
101
+ if (d.blocked)
102
+ blocked.push(d.note);
103
+ else
104
+ kept.push(tc);
105
+ }
106
+ msg.tool_calls = kept.length > 0 ? kept : null;
107
+ if (blocked.length > 0 && !msg.tool_calls) {
108
+ // Match Python's ``_filter_blocked_calls``: join with a newline
109
+ // separator but no leading newline before the first message.
110
+ msg.content = (msg.content ?? "") + blocked.join("\n");
111
+ }
112
+ }
113
+ return response;
114
+ }
115
+ function guardResponsesOutput(response, guard) {
116
+ const output = response?.output;
117
+ if (!Array.isArray(output))
118
+ return response;
119
+ const kept = [];
120
+ const blocked = [];
121
+ for (const item of output) {
122
+ if (item?.type === "function_call") {
123
+ const d = decide(guard, item.name ?? "", item.arguments);
124
+ if (d.blocked) {
125
+ blocked.push(d.note);
23
126
  continue;
24
- const kept = [];
25
- const blocked = [];
26
- for (const tc of msg.tool_calls) {
27
- let tcArgs = {};
28
- let parseFailed = false;
29
- try {
30
- tcArgs = JSON.parse(tc.function.arguments || "{}");
31
- }
32
- catch {
33
- parseFailed = true;
34
- }
35
- // Malformed arguments bypass any arg-based contract
36
- // (``arg_blacklist``, ``arg_length_limit``, ``scope_limit``,
37
- // ``dangerous_sql_verbs``, ``arg_value_range``) if we treat
38
- // them as empty. Feed a sentinel so the guard still sees
39
- // *something* distinctive, and block-by-default so a
40
- // malformed payload doesn't silently slip through.
41
- if (parseFailed) {
42
- guard.guardBefore(tc.function.name, {
43
- _sponsio_malformed_args: tc.function.arguments ?? "",
44
- });
45
- blocked.push(`[BLOCKED] ${tc.function.name}: malformed JSON arguments — ` +
46
- `refusing to forward to tool loop (set ` +
47
- `SPONSIO_OPENAI_STRICT_TOOL_ARGS=0 to downgrade once the ` +
48
- `parity flag ships in TS)`);
49
- continue;
50
- }
51
- const result = guard.guardBefore(tc.function.name, tcArgs);
52
- if (result.blocked) {
53
- blocked.push(`[BLOCKED] ${tc.function.name}: ${result.message}`);
54
- }
55
- else {
56
- kept.push(tc);
57
- }
58
- }
59
- msg.tool_calls = kept.length > 0 ? kept : null;
60
- if (blocked.length > 0 && !msg.tool_calls) {
61
- // Match Python's ``_filter_blocked_calls``: join with a newline
62
- // separator but no leading newline before the first message.
63
- msg.content = (msg.content ?? "") + blocked.join("\n");
64
127
  }
65
128
  }
129
+ kept.push(item);
130
+ }
131
+ if (blocked.length === 0)
66
132
  return response;
67
- };
68
- return client;
133
+ response.output = kept;
134
+ const note = blocked.join("\n");
135
+ const lastMessage = [...kept].reverse().find((i) => i?.type === "message");
136
+ const textPart = lastMessage?.content
137
+ ? [...lastMessage.content].reverse().find((p) => typeof p?.text === "string")
138
+ : undefined;
139
+ if (textPart) {
140
+ textPart.text = `${textPart.text}\n${note}`;
141
+ }
142
+ else {
143
+ kept.push({
144
+ type: "message",
145
+ role: "assistant",
146
+ status: "completed",
147
+ content: [{ type: "output_text", text: note, annotations: [] }],
148
+ });
149
+ }
150
+ return response;
69
151
  }
70
152
  /**
71
153
  * Alias for ``wrapOpenAI`` — matches Python's
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/integrations/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,UAAU,UAAU,CAAC,MAAe,EAAE,KAAc;IACxD,MAAM,CAAC,GAAG,MAeT,CAAC;IAEF,MAAM,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAEpE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,KAAK,WAAW,GAAG,IAAe;QAC5D,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;QAEzC,KAAK,MAAM,MAAM,IAAI,QAAQ,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;YAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC;YAC3B,IAAI,CAAC,GAAG,EAAE,UAAU;gBAAE,SAAS;YAE/B,MAAM,IAAI,GAA0B,EAAE,CAAC;YACvC,MAAM,OAAO,GAAa,EAAE,CAAC;YAE7B,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;gBAChC,IAAI,MAAM,GAA4B,EAAE,CAAC;gBACzC,IAAI,WAAW,GAAG,KAAK,CAAC;gBACxB,IAAI,CAAC;oBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC;gBACrD,CAAC;gBAAC,MAAM,CAAC;oBACP,WAAW,GAAG,IAAI,CAAC;gBACrB,CAAC;gBAED,oDAAoD;gBACpD,6DAA6D;gBAC7D,4DAA4D;gBAC5D,yDAAyD;gBACzD,qDAAqD;gBACrD,mDAAmD;gBACnD,IAAI,WAAW,EAAE,CAAC;oBAChB,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE;wBAClC,uBAAuB,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,IAAI,EAAE;qBACrD,CAAC,CAAC;oBACH,OAAO,CAAC,IAAI,CACV,aAAa,EAAE,CAAC,QAAQ,CAAC,IAAI,+BAA+B;wBAC1D,wCAAwC;wBACxC,0DAA0D;wBAC1D,0BAA0B,CAC7B,CAAC;oBACF,SAAS;gBACX,CAAC;gBAED,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC3D,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;oBACnB,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,QAAQ,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBACnE,CAAC;qBAAM,CAAC;oBACN,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC;YAED,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YAC/C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,CAAC;gBAC1C,gEAAgE;gBAChE,6DAA6D;gBAC7D,GAAG,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzD,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAoB,CAAC;IAErB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC"}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../src/integrations/openai.ts"],"names":[],"mappings":"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"}
@@ -10,19 +10,30 @@
10
10
  * const model = wrapLanguageModel({ model, middleware: sponsioMiddleware(guard) })
11
11
  *
12
12
  * Behaviour:
13
- * - guardBefore is called for every tool call the model emits.
13
+ * - guardBefore runs for every tool call the model emits, on both
14
+ * ``generateText`` (``wrapGenerate``) and ``streamText``
15
+ * (``wrapStream``), before the AI SDK executes the tool.
14
16
  * - Allowed calls pass through untouched.
15
- * - Blocked calls are *dropped* from ``result.toolCalls`` (so the AI
16
- * SDK's parseToolCall doesn't reject the response with NoSuchToolError),
17
- * and a `[Sponsio blocked: <reason>]` line is appended to the
18
- * model's text output. If every emitted call was blocked, the
19
- * finishReason is forced to ``stop`` so the agent loop terminates
20
- * instead of spinning on an empty turn.
21
- * - The model's args are JSON-stringified at the language-model layer;
22
- * the middleware parses defensively before handing them to the
17
+ * - Blocked calls are *dropped* (so the AI SDK never executes them and
18
+ * ``parseToolCall`` doesn't reject the response), and a
19
+ * ``[Sponsio blocked: <reason>]`` note is added to the model's text.
20
+ * If every emitted call was blocked, the finishReason is forced to
21
+ * ``stop`` so the agent loop terminates instead of spinning.
22
+ * - Both provider result shapes are handled: ``ai`` v4
23
+ * (``LanguageModelV1``: ``result.toolCalls[]`` with ``args``) and
24
+ * ``ai`` v5 and later (``LanguageModelV2`` / ``V3``:
25
+ * ``result.content[]`` with ``{ type: "tool-call", input }`` parts).
26
+ * - The model's args arrive JSON-stringified at the language-model
27
+ * layer; the middleware parses defensively before handing them to the
23
28
  * guard so the contract evaluator sees a real object.
24
29
  */
25
30
  import type { Sponsio } from "../index.js";
31
+ /**
32
+ * The model's arguments as an object. A string that is not JSON is kept
33
+ * under ``_sponsio_malformed_args`` so coarse regex contracts still see
34
+ * it instead of an empty object that passes every argument rule.
35
+ */
36
+ export declare function parseArgs(raw: unknown): Record<string, unknown>;
26
37
  export declare function sponsioMiddleware(guard: Sponsio): {
27
38
  transformParams: ({ params }: {
28
39
  params: any;
@@ -1 +1 @@
1
- {"version":3,"file":"vercel-ai.d.ts","sourceRoot":"","sources":["../../src/integrations/vercel-ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAgD3C,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO;kCAER;QAAE,MAAM,EAAE,GAAG,CAAA;KAAE,KAAG,OAAO,CAAC,GAAG,CAAC;oCAI/D;QACD,UAAU,EAAE,MAAM,GAAG,CAAC;QACtB,MAAM,EAAE,GAAG,CAAC;KACb,KAAG,OAAO,CAAC,GAAG,CAAC;+BAqCiB;QAAE,QAAQ,EAAE,MAAM,GAAG,CAAA;KAAE,KAAG,OAAO,CAAC,GAAG,CAAC;EAQ1E"}
1
+ {"version":3,"file":"vercel-ai.d.ts","sourceRoot":"","sources":["../../src/integrations/vercel-ai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAsC3C;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAc/D;AA0CD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO;kCAER;QAAE,MAAM,EAAE,GAAG,CAAA;KAAE,KAAG,OAAO,CAAC,GAAG,CAAC;oCAI/D;QACD,UAAU,EAAE,MAAM,GAAG,CAAC;QACtB,MAAM,EAAE,GAAG,CAAC;KACb,KAAG,OAAO,CAAC,GAAG,CAAC;+BAuDiB;QAAE,QAAQ,EAAE,MAAM,GAAG,CAAA;KAAE,KAAG,OAAO,CAAC,GAAG,CAAC;EA4C1E"}
@@ -10,16 +10,21 @@
10
10
  * const model = wrapLanguageModel({ model, middleware: sponsioMiddleware(guard) })
11
11
  *
12
12
  * Behaviour:
13
- * - guardBefore is called for every tool call the model emits.
13
+ * - guardBefore runs for every tool call the model emits, on both
14
+ * ``generateText`` (``wrapGenerate``) and ``streamText``
15
+ * (``wrapStream``), before the AI SDK executes the tool.
14
16
  * - Allowed calls pass through untouched.
15
- * - Blocked calls are *dropped* from ``result.toolCalls`` (so the AI
16
- * SDK's parseToolCall doesn't reject the response with NoSuchToolError),
17
- * and a `[Sponsio blocked: <reason>]` line is appended to the
18
- * model's text output. If every emitted call was blocked, the
19
- * finishReason is forced to ``stop`` so the agent loop terminates
20
- * instead of spinning on an empty turn.
21
- * - The model's args are JSON-stringified at the language-model layer;
22
- * the middleware parses defensively before handing them to the
17
+ * - Blocked calls are *dropped* (so the AI SDK never executes them and
18
+ * ``parseToolCall`` doesn't reject the response), and a
19
+ * ``[Sponsio blocked: <reason>]`` note is added to the model's text.
20
+ * If every emitted call was blocked, the finishReason is forced to
21
+ * ``stop`` so the agent loop terminates instead of spinning.
22
+ * - Both provider result shapes are handled: ``ai`` v4
23
+ * (``LanguageModelV1``: ``result.toolCalls[]`` with ``args``) and
24
+ * ``ai`` v5 and later (``LanguageModelV2`` / ``V3``:
25
+ * ``result.content[]`` with ``{ type: "tool-call", input }`` parts).
26
+ * - The model's args arrive JSON-stringified at the language-model
27
+ * layer; the middleware parses defensively before handing them to the
23
28
  * guard so the contract evaluator sees a real object.
24
29
  */
25
30
  function emitBanner(toolName, reason, agentId) {
@@ -38,7 +43,12 @@ function emitBanner(toolName, reason, agentId) {
38
43
  ];
39
44
  process.stderr.write(lines.join("\n"));
40
45
  }
41
- function parseArgs(raw) {
46
+ /**
47
+ * The model's arguments as an object. A string that is not JSON is kept
48
+ * under ``_sponsio_malformed_args`` so coarse regex contracts still see
49
+ * it instead of an empty object that passes every argument rule.
50
+ */
51
+ export function parseArgs(raw) {
42
52
  if (raw == null)
43
53
  return {};
44
54
  if (typeof raw === "object" && !Array.isArray(raw))
@@ -48,37 +58,91 @@ function parseArgs(raw) {
48
58
  const parsed = JSON.parse(raw);
49
59
  return parsed && typeof parsed === "object" && !Array.isArray(parsed)
50
60
  ? parsed
51
- : {};
61
+ : { input: parsed };
52
62
  }
53
63
  catch {
54
- return {};
64
+ return { _sponsio_malformed_args: raw };
55
65
  }
56
66
  }
57
- return {};
67
+ return { input: raw };
68
+ }
69
+ /** Compact one-line reason for the appended note; full message stays in the session log. */
70
+ function trimReason(msg) {
71
+ // Strip prefix via indexOf rather than regex — every regex form that
72
+ // matched the pattern ``^[A-Z-]*BLOCKED:\s*[^—]+—\s*`` kept tripping
73
+ // CodeQL js/polynomial-redos (the ``\s*`` and ``[^—]+`` overlap on
74
+ // spaces). indexOf is O(n) with no backtracking.
75
+ let trimmed = msg;
76
+ const blockedIdx = trimmed.indexOf("BLOCKED:");
77
+ if (blockedIdx >= 0 && blockedIdx <= 64) {
78
+ const dashIdx = trimmed.indexOf("—", blockedIdx + "BLOCKED:".length);
79
+ if (dashIdx >= 0) {
80
+ trimmed = trimmed.slice(dashIdx + "—".length).trimStart();
81
+ }
82
+ }
83
+ const head = trimmed.toLowerCase();
84
+ if (head.startsWith("det constraint violated:")) {
85
+ trimmed = trimmed.slice("det constraint violated:".length).trimStart();
86
+ }
87
+ else if (head.startsWith("violated:")) {
88
+ trimmed = trimmed.slice("violated:".length).trimStart();
89
+ }
90
+ return trimmed.split("\n")[0];
91
+ }
92
+ /** Run one emitted tool call through the guard, before anything executes it. */
93
+ function decide(guard, tc) {
94
+ const check = guard.guardBefore(tc.toolName, parseArgs(tc.input ?? tc.args));
95
+ // ``stopOriginal`` covers a redirect verdict as well as a block: the
96
+ // middleware has no substitution path, so a redirect drops the call.
97
+ if (!check.stopOriginal)
98
+ return { blocked: false };
99
+ const reason = trimReason(check.message ?? `${tc.toolName} blocked by Sponsio`);
100
+ emitBanner(tc.toolName, reason, guard.agentId);
101
+ return { blocked: true, reason };
102
+ }
103
+ function blockNote(reasons) {
104
+ return `[Sponsio blocked: ${reasons.join("; ")}]`;
58
105
  }
59
106
  export function sponsioMiddleware(guard) {
60
107
  return {
61
108
  transformParams: async ({ params }) => params,
62
109
  wrapGenerate: async ({ doGenerate, }) => {
63
110
  const result = await doGenerate();
111
+ // ai v5+: tool calls are ``tool-call`` parts inside ``content``.
112
+ if (Array.isArray(result.content)) {
113
+ const content = [];
114
+ const blockedReasons = [];
115
+ let survivingCalls = 0;
116
+ for (const part of result.content) {
117
+ if (part?.type === "tool-call") {
118
+ const d = decide(guard, part);
119
+ if (d.blocked) {
120
+ blockedReasons.push(`${String(part.toolName)}: ${d.reason}`);
121
+ continue;
122
+ }
123
+ survivingCalls++;
124
+ }
125
+ content.push(part);
126
+ }
127
+ if (blockedReasons.length === 0)
128
+ return result;
129
+ content.push({ type: "text", text: blockNote(blockedReasons) });
130
+ return {
131
+ ...result,
132
+ content,
133
+ finishReason: survivingCalls === 0 ? "stop" : result.finishReason,
134
+ };
135
+ }
136
+ // ai v4: tool calls are ``result.toolCalls``.
64
137
  const calls = result.toolCalls ?? [];
65
138
  if (calls.length === 0)
66
139
  return result;
67
140
  const surviving = [];
68
141
  const blockedReasons = [];
69
142
  for (const tc of calls) {
70
- const check = guard.guardBefore(tc.toolName, parseArgs(tc.args));
71
- if (check.blocked) {
72
- // Strip the leading "BLOCKED: agent.tool — det constraint violated: "
73
- // prefix and any "det constraint violated:" / "violated:" boilerplate
74
- // so the appended text is concise; full message stays in the session log.
75
- const msg = check.message ?? `${tc.toolName} blocked by Sponsio`;
76
- const trimmed = msg
77
- .replace(/^[A-Z-]*BLOCKED:\s*[^—]+—\s*/, "")
78
- .replace(/^(?:det\s+constraint\s+)?violated:\s*/i, "");
79
- const reason = trimmed.split("\n")[0];
80
- emitBanner(tc.toolName, reason, guard.agentId);
81
- blockedReasons.push(`${tc.toolName}: ${reason}`);
143
+ const d = decide(guard, tc);
144
+ if (d.blocked) {
145
+ blockedReasons.push(`${tc.toolName}: ${d.reason}`);
82
146
  }
83
147
  else {
84
148
  surviving.push(tc);
@@ -86,8 +150,8 @@ export function sponsioMiddleware(guard) {
86
150
  }
87
151
  if (blockedReasons.length === 0)
88
152
  return result;
89
- const blockNote = `[Sponsio blocked: ${blockedReasons.join("; ")}]`;
90
- const newText = result.text ? `${result.text}\n\n${blockNote}` : blockNote;
153
+ const note = blockNote(blockedReasons);
154
+ const newText = result.text ? `${result.text}\n\n${note}` : note;
91
155
  return {
92
156
  ...result,
93
157
  toolCalls: surviving,
@@ -96,11 +160,46 @@ export function sponsioMiddleware(guard) {
96
160
  };
97
161
  },
98
162
  wrapStream: async ({ doStream }) => {
99
- // Stream support is intentionally pass-through for now; the
100
- // stream parts API is more involved and the demo / OSS hot
101
- // path uses generateText. We can add full stream filtering in
102
- // a follow-up without changing the wrapGenerate contract.
103
- return doStream();
163
+ const streamed = await doStream();
164
+ const source = streamed?.stream;
165
+ if (!source || typeof source.pipeThrough !== "function")
166
+ return streamed;
167
+ // ``streamText`` executes a tool when the ``tool-call`` part arrives,
168
+ // so that part is the gate. Earlier ``tool-input-*`` /
169
+ // ``tool-call-delta`` parts only render partial arguments and pass
170
+ // through; nothing runs on them.
171
+ let survivingCalls = 0;
172
+ let blockedAny = false;
173
+ let noteId = 0;
174
+ const gated = source.pipeThrough(new TransformStream({
175
+ transform(part, controller) {
176
+ if (part?.type === "tool-call") {
177
+ const d = decide(guard, part);
178
+ if (d.blocked) {
179
+ blockedAny = true;
180
+ const note = blockNote([`${String(part.toolName)}: ${d.reason}`]);
181
+ if ("input" in part) {
182
+ // v5+ text streams are start / delta / end triples.
183
+ const id = `sponsio-block-${++noteId}`;
184
+ controller.enqueue({ type: "text-start", id });
185
+ controller.enqueue({ type: "text-delta", id, delta: note });
186
+ controller.enqueue({ type: "text-end", id });
187
+ }
188
+ else {
189
+ controller.enqueue({ type: "text-delta", textDelta: note });
190
+ }
191
+ return;
192
+ }
193
+ survivingCalls++;
194
+ }
195
+ if (part?.type === "finish" && blockedAny && survivingCalls === 0) {
196
+ controller.enqueue({ ...part, finishReason: "stop" });
197
+ return;
198
+ }
199
+ controller.enqueue(part);
200
+ },
201
+ }));
202
+ return { ...streamed, stream: gated };
104
203
  },
105
204
  };
106
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vercel-ai.js","sourceRoot":"","sources":["../../src/integrations/vercel-ai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vercel-ai.js","sourceRoot":"","sources":["../../src/integrations/vercel-ai.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sponsio/sdk",
3
- "version": "0.1.0",
4
- "description": "Runtime contract enforcement for LLM agents — native TypeScript",
3
+ "version": "0.2.0-alpha.8",
4
+ "description": "Runtime contract enforcement for LLM agents \u2014 native TypeScript",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -13,6 +13,9 @@
13
13
  },
14
14
  "homepage": "https://github.com/SponsioLabs/Sponsio#readme",
15
15
  "type": "module",
16
+ "sideEffects": [
17
+ "./dist/cli/**"
18
+ ],
16
19
  "main": "dist/index.js",
17
20
  "types": "dist/index.d.ts",
18
21
  "exports": {
@@ -43,6 +46,10 @@
43
46
  "./langchain": {
44
47
  "types": "./dist/integrations/langchain.d.ts",
45
48
  "default": "./dist/integrations/langchain.js"
49
+ },
50
+ "./cloud/evidence": {
51
+ "types": "./dist/cloud/evidence.d.ts",
52
+ "import": "./dist/cloud/evidence.js"
46
53
  }
47
54
  },
48
55
  "bin": {
@@ -60,26 +67,27 @@
60
67
  ],
61
68
  "scripts": {
62
69
  "build": "tsc && tsc -p tsconfig.cli.json && node -e \"require('fs').writeFileSync('dist/cli/package.json', '{\\\"type\\\":\\\"commonjs\\\"}\\n')\"",
63
- "test": "node --test dist/__tests__/*.test.js",
70
+ "test": "node --test dist/",
64
71
  "test:cli": "node --test dist/cli/__tests__/*.test.js",
65
72
  "test:src": "npx tsx src/__tests__/core.test.ts",
66
73
  "test:parity": "npx tsx src/__tests__/parity.test.ts && npx tsx src/__tests__/parity.scenarios.test.ts"
67
74
  },
68
75
  "dependencies": {
69
- "yaml": "^2.7.0",
70
76
  "fast-glob": "^3.3.0",
71
- "js-yaml": "^4.1.0",
72
- "ts-morph": "^22.0.0"
77
+ "js-yaml": "^5.4.2",
78
+ "ts-morph": "^28.0.0",
79
+ "yaml": "^2.9.1"
73
80
  },
74
81
  "devDependencies": {
75
82
  "@types/js-yaml": "^4.0.5",
76
- "@types/node": "^25.6.0",
77
- "tsx": "^4.0.0",
83
+ "@types/node": "^26.6.2",
84
+ "esbuild": "^0.28.2",
85
+ "tsx": "^4.23.15",
78
86
  "typescript": "^5.5.0"
79
87
  },
80
88
  "peerDependencies": {
81
- "@langchain/core": ">=0.3.0",
82
89
  "@google/adk": ">=0.2.0",
90
+ "@langchain/core": ">=0.3.0",
83
91
  "ai": ">=4.0.0",
84
92
  "claude-agent-sdk": ">=0.1.0",
85
93
  "openai": ">=4.0.0"
@@ -33,10 +33,9 @@ A JSON object from `sponsio onboard --emit-context`:
33
33
  ## Hard rules (apply before authoring anything)
34
34
 
35
35
  - **Deterministic atoms only.** Use ONLY pattern names from the
36
- *Pattern vocabulary* section below. Do NOT propose stochastic
37
- atoms (`injection_free`, `pii_free`, `semantic_pii`, `faithful`,
38
- `harmful`, `tone_*`, `relevant`, `metric_integrity`, etc.).
39
- Sponsio OSS does not load them; the YAML will fail to parse.
36
+ *Pattern vocabulary* section below. The engine is
37
+ deterministic-only; any pattern name outside that vocabulary will
38
+ fail to parse.
40
39
 
41
40
  - **Dedupe against `pre_existing_contracts`.** The CLI already
42
41
  emitted starter rules (likely `idempotent`, generic
@@ -49,16 +48,14 @@ A JSON object from `sponsio onboard --emit-context`:
49
48
  the user has to clean up.
50
49
 
51
50
  - **Source tagging.** Every contract YOU author carries
52
- `source: agent-extracted` so future `sponsio refresh` runs can
53
- distinguish your additions from pack rules and from
54
- CLI-emitted starter rules.
51
+ `source: agent-extracted` so later tooling can distinguish your
52
+ additions from pack rules and from CLI-emitted starter rules.
55
53
 
56
54
  - **One contract per concrete failure mode.** Plain-English
57
55
  `desc:` so the user can review by reading. No omnibus rules.
58
56
 
59
- - **Strip `extractor:` / `judge:` blocks.** Those drive Sponsio
60
- Cloud features (parse-time / runtime LLM judges) and add noise
61
- to the OSS file unless the user explicitly asks for them.
57
+ - **Strip `extractor:` / `judge:` blocks.** The engine does not use
58
+ them; they only add noise to the file.
62
59
 
63
60
  - **Placeholders only as last resort.** Use `___AGENT_ID___`,
64
61
  `___WORKSPACE___`, `___ALLOWED_HOST___` etc. ONLY when no
@@ -178,17 +175,29 @@ agents:
178
175
 
179
176
  ## Pattern vocabulary
180
177
 
181
- (Same as plugin scan — `arg_blacklist`, `arg_value_range`,
182
- `arg_length_limit`, `rate_limit`, `loop_detection`,
183
- `irreversible_once`, `must_precede`. See
184
- ``sponsio plugin prompt mcp-bare`` for full signatures.)
178
+ Run ``sponsio patterns`` and use the FULL list it prints — do not
179
+ rely on a memorized subset. The library spans temporal ordering
180
+ (`must_precede`, `no_reversal`, `always_followed_by`, …), argument &
181
+ path constraints (`arg_blacklist`, `arg_allowlist`, `scope_limit`,
182
+ `arg_value_range`, `arg_length_limit`, …), OWASP presets
183
+ (`dangerous_sql_verbs`, `dangerous_bash_commands`,
184
+ `destructive_action_gate`, `tool_allowlist`, …), rate / resource
185
+ caps (`rate_limit`, `idempotent`, `loop_detection`, …), and data
186
+ flow (`no_data_leak`). Policy docs about SQL safety, data
187
+ isolation, taint, or approval gates almost always need patterns
188
+ outside the arg-constraint family — check the full list before
189
+ concluding a rule can't be expressed.
190
+
191
+ If no pattern fits, two fallbacks (in order): a plain NL rule that
192
+ ``sponsio validate`` accepts, or a raw formula over the atomic
193
+ propositions in ``sponsio/tracer/grounding.py`` (`called`,
194
+ `called_with`, `arg_has`, `arg_field_has`, `contains`, `flow`).
185
195
 
186
196
  ## Source tagging
187
197
 
188
198
  Every contract YOU author should carry `source: agent-extracted` so
189
- future `sponsio refresh` runs know they were agent-generated and
190
- can be re-considered. Don't tag pack-included rules — those have
191
- their own source from the pack.
199
+ later tooling knows they were agent-generated. Don't tag
200
+ pack-included rules; those have their own source from the pack.
192
201
 
193
202
  ## What to do after
194
203