@rulvar/bridge-ai-sdk 1.187.0 → 1.188.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +16 -0
- package/dist/index.js +38 -2
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,22 @@ interface BridgeAiSdkOptions {
|
|
|
17
17
|
provider?: string;
|
|
18
18
|
/** Per-model capability overrides merged over the conservative defaults. */
|
|
19
19
|
caps?: (model: string) => ModelCaps | Partial<ModelCaps>;
|
|
20
|
+
/**
|
|
21
|
+
* Provider-executed tool policy (RV1806). The wrapped provider can
|
|
22
|
+
* run tools SERVER-SIDE (web search, code execution, computer use):
|
|
23
|
+
* those calls never pass the engine's ToolDef registry, risk
|
|
24
|
+
* classes, ask rules, or approvals, and their effects happen on
|
|
25
|
+
* provider infrastructure regardless of any engine permission chain.
|
|
26
|
+
* The default 'deny' fails the turn with a typed terminal error the
|
|
27
|
+
* moment a provider-executed exchange appears, because a policy
|
|
28
|
+
* surface that cannot see a call must not silently absorb it.
|
|
29
|
+
* 'allow' opts in: the exchange is retained for prompt
|
|
30
|
+
* reconstruction exactly as before, and the finish metadata
|
|
31
|
+
* additionally names every provider-executed call
|
|
32
|
+
* (`providerExecutedTools: [{ toolName, toolCallId }]`) so the
|
|
33
|
+
* journaled record of the turn says what the provider ran.
|
|
34
|
+
*/
|
|
35
|
+
providerExecutedTools?: "allow" | "deny";
|
|
20
36
|
}
|
|
21
37
|
/**
|
|
22
38
|
* Wraps a Vercel AI SDK LanguageModelV4 as a ProviderAdapter. The bridge
|
package/dist/index.js
CHANGED
|
@@ -106,6 +106,8 @@ function bridgeAiSdk(model, options = {}) {
|
|
|
106
106
|
const id = options.id ?? model.provider;
|
|
107
107
|
if (id === void 0 || id === "") throw new ConfigError("bridgeAiSdk requires a non-empty adapter id (model.provider was empty)");
|
|
108
108
|
const family = options.provider ?? model.provider;
|
|
109
|
+
const providerExecutedTools = options.providerExecutedTools ?? "deny";
|
|
110
|
+
if (providerExecutedTools !== "allow" && providerExecutedTools !== "deny") throw new ConfigError("bridgeAiSdk options.providerExecutedTools must be 'allow' or 'deny' when given");
|
|
109
111
|
const ids = new BridgeIdMap(createCanonicalIdMinter());
|
|
110
112
|
return {
|
|
111
113
|
id,
|
|
@@ -136,7 +138,7 @@ function bridgeAiSdk(model, options = {}) {
|
|
|
136
138
|
};
|
|
137
139
|
return;
|
|
138
140
|
}
|
|
139
|
-
const mapper = new StreamMapper(id, ids, built.effortDownmapped);
|
|
141
|
+
const mapper = new StreamMapper(id, ids, built.effortDownmapped, providerExecutedTools);
|
|
140
142
|
try {
|
|
141
143
|
for await (const part of iterateStream(result.stream)) {
|
|
142
144
|
for (const event of mapper.map(part)) yield event;
|
|
@@ -394,16 +396,42 @@ var StreamMapper = class {
|
|
|
394
396
|
adapterId;
|
|
395
397
|
ids;
|
|
396
398
|
effortDownmapped;
|
|
399
|
+
providerExecutedPolicy;
|
|
397
400
|
startedToolWireIds = /* @__PURE__ */ new Set();
|
|
398
401
|
providerExecutedWireIds = /* @__PURE__ */ new Set();
|
|
402
|
+
/** Provider-executed calls seen under 'allow' (RV1806), by wire id. */
|
|
403
|
+
providerExecutedSeen = /* @__PURE__ */ new Map();
|
|
399
404
|
reasoning = /* @__PURE__ */ new Map();
|
|
400
405
|
retained = [];
|
|
401
406
|
warnings = [];
|
|
402
407
|
response;
|
|
403
|
-
constructor(adapterId, ids, effortDownmapped) {
|
|
408
|
+
constructor(adapterId, ids, effortDownmapped, providerExecutedPolicy = "deny") {
|
|
404
409
|
this.adapterId = adapterId;
|
|
405
410
|
this.ids = ids;
|
|
406
411
|
this.effortDownmapped = effortDownmapped;
|
|
412
|
+
this.providerExecutedPolicy = providerExecutedPolicy;
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* The deny arm (RV1806): a provider-executed exchange under the
|
|
416
|
+
* default policy fails the turn typed. The refusal cannot un-run a
|
|
417
|
+
* tool the provider already executed server-side; it refuses to
|
|
418
|
+
* CONTINUE a turn the engine's permission chain cannot see, and the
|
|
419
|
+
* journaled terminal names the tool that ran.
|
|
420
|
+
*/
|
|
421
|
+
denyProviderExecuted(toolName) {
|
|
422
|
+
this.terminal = true;
|
|
423
|
+
return [{
|
|
424
|
+
type: "error",
|
|
425
|
+
error: {
|
|
426
|
+
code: "agent",
|
|
427
|
+
message: `the bridged provider executed tool '${toolName}' server-side; provider-executed tools bypass the engine's ToolDef registry, risk classes, and approvals, and are refused by default. Opt in with bridgeAiSdk(model, { providerExecutedTools: 'allow' })`,
|
|
428
|
+
retryable: false,
|
|
429
|
+
data: {
|
|
430
|
+
kind: "terminal",
|
|
431
|
+
providerExecutedTool: toolName
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}];
|
|
407
435
|
}
|
|
408
436
|
map(part) {
|
|
409
437
|
switch (part.type) {
|
|
@@ -455,7 +483,9 @@ var StreamMapper = class {
|
|
|
455
483
|
}
|
|
456
484
|
case "tool-input-start":
|
|
457
485
|
if (part.providerExecuted === true) {
|
|
486
|
+
if (this.providerExecutedPolicy === "deny") return this.denyProviderExecuted(part.toolName);
|
|
458
487
|
this.providerExecutedWireIds.add(part.id);
|
|
488
|
+
this.providerExecutedSeen.set(part.id, part.toolName);
|
|
459
489
|
return [];
|
|
460
490
|
}
|
|
461
491
|
this.startedToolWireIds.add(part.id);
|
|
@@ -474,7 +504,9 @@ var StreamMapper = class {
|
|
|
474
504
|
case "tool-input-end": return [];
|
|
475
505
|
case "tool-call": {
|
|
476
506
|
if (part.providerExecuted === true) {
|
|
507
|
+
if (this.providerExecutedPolicy === "deny") return this.denyProviderExecuted(part.toolName);
|
|
477
508
|
this.providerExecutedWireIds.add(part.toolCallId);
|
|
509
|
+
this.providerExecutedSeen.set(part.toolCallId, part.toolName);
|
|
478
510
|
const parsed = parseToolArgs(part.input);
|
|
479
511
|
this.retained.push({
|
|
480
512
|
type: "tool-call",
|
|
@@ -587,6 +619,10 @@ var StreamMapper = class {
|
|
|
587
619
|
if (typeof this.response.id === "string") bag.responseId = this.response.id;
|
|
588
620
|
}
|
|
589
621
|
if (part.providerMetadata !== void 0) bag.upstream = part.providerMetadata;
|
|
622
|
+
if (this.providerExecutedSeen.size > 0) bag.providerExecutedTools = [...this.providerExecutedSeen.entries()].map(([toolCallId, toolName]) => ({
|
|
623
|
+
toolName,
|
|
624
|
+
toolCallId
|
|
625
|
+
}));
|
|
590
626
|
if (this.effortDownmapped) bag.effortDownmap = "max->xhigh";
|
|
591
627
|
if (part.finishReason.unified === "other" && part.finishReason.raw !== void 0) bag.finishRaw = part.finishReason.raw;
|
|
592
628
|
return [{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rulvar/bridge-ai-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.188.0",
|
|
4
4
|
"description": "Rulvar bridge adapter wrapping any Vercel AI SDK LanguageModelV4 as a ProviderAdapter.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@ai-sdk/provider": "^4.0.3",
|
|
26
|
-
"@rulvar/core": "1.
|
|
26
|
+
"@rulvar/core": "1.188.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@ai-sdk/google": "^4.0.24",
|
|
30
30
|
"@types/node": "^22.20.1",
|
|
31
31
|
"tsdown": "^0.22.14",
|
|
32
32
|
"typescript": "~6.0.3",
|
|
33
|
-
"@rulvar/testing": "1.
|
|
33
|
+
"@rulvar/testing": "1.188.0"
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|