@combycode/llm-sdk 1.1.0 → 1.2.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/CHANGELOG.md +30 -0
- package/dist/agent/guardrail-types.d.ts +25 -0
- package/dist/agent/loop-config.d.ts +5 -1
- package/dist/agent/loop.d.ts +1 -0
- package/dist/agent/types.d.ts +8 -0
- package/dist/index.browser.js +63 -9
- package/dist/index.d.ts +1 -1
- package/dist/index.js +63 -9
- package/dist/llm/types/response.d.ts +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,35 @@ All notable changes to `@combycode/llm-sdk` are documented here. The format foll
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [1.2.0] - 2026-07-05
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
- Anthropic hosted code-execution **file outputs** now surface on `response.files` (verified
|
|
13
|
+
live). Three fixes, found by real-key testing: (1) the producer parsed the outdated
|
|
14
|
+
`code_execution_tool_result` shape, but the current `code_execution_20260521` tool emits
|
|
15
|
+
`bash_code_execution_tool_result` → `bash_code_execution_output.file_id` (now both are
|
|
16
|
+
handled); (2) code execution needs the beta endpoint — requests using `code_interpreter` now
|
|
17
|
+
hit `/v1/messages?beta=true`, without which no file outputs are returned; (3) `AgentLoop`'s
|
|
18
|
+
final response dropped `files` (and `moderation`) — both are now propagated from the final
|
|
19
|
+
LLM response in `complete()` and `stream()`.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- `AgentLoopConfig.toolInputGuardrails` (`ToolInputGuardrail[]`) — per-tool-call input
|
|
23
|
+
guardrails that validate a call's arguments before the permission/approval check. A trip
|
|
24
|
+
denies just that call (error result to the model) without halting the run or invoking the
|
|
25
|
+
HITL approver; a pass runs the normal permission/approval/execution path.
|
|
26
|
+
- `AgentTool.customDataExtractor` — optional hook to derive out-of-band metadata from a
|
|
27
|
+
successful tool result, attached to that call's `ToolCallReport.customData`. The model never
|
|
28
|
+
sees it (for your own telemetry/routing/audit); a throwing extractor is swallowed.
|
|
29
|
+
- Code-execution **file outputs** now surface on `response.files` across **all** providers
|
|
30
|
+
(completes the channel shipped in 1.1, which had only the Anthropic producer):
|
|
31
|
+
- OpenAI Responses: code-interpreter image outputs (by URL) and downloadable container
|
|
32
|
+
files (`container_file_citation` → file id + name).
|
|
33
|
+
- Google: hosted code-execution `inlineData` artifacts (base64), routed to `files`
|
|
34
|
+
instead of `media` when the turn used code execution.
|
|
35
|
+
- xAI: inherited from the OpenAI Responses adapter.
|
|
36
|
+
- `FileOutput` gains a `url` field (for providers that return a fetchable URL).
|
|
37
|
+
|
|
9
38
|
## [1.1.0] - 2026-06-30
|
|
10
39
|
|
|
11
40
|
### Added
|
|
@@ -53,5 +82,6 @@ First public release.
|
|
|
53
82
|
- Service tiers end to end (request → bill → cost).
|
|
54
83
|
- Cross-environment: runs on Node, Bun, and the browser. ESM, zero runtime deps.
|
|
55
84
|
|
|
85
|
+
[1.2.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.2.0
|
|
56
86
|
[1.1.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.1.0
|
|
57
87
|
[1.0.0]: https://github.com/combycode/llm-sdk-ts/releases/tag/v1.0.0
|
|
@@ -46,6 +46,31 @@ export interface Guardrail {
|
|
|
46
46
|
/** Return a decision; throw only for unexpected infrastructure errors. */
|
|
47
47
|
check(ctx: GuardrailCheckContext): Promise<GuardrailDecision>;
|
|
48
48
|
}
|
|
49
|
+
/** Context for a tool-input guardrail: the specific tool call about to run. */
|
|
50
|
+
export interface ToolInputGuardrailContext {
|
|
51
|
+
toolName: string;
|
|
52
|
+
arguments: Record<string, unknown>;
|
|
53
|
+
callId: string;
|
|
54
|
+
step: number;
|
|
55
|
+
trace: TraceContext;
|
|
56
|
+
}
|
|
57
|
+
/** A tool-input guardrail decision. Unlike message-level guardrails it does NOT
|
|
58
|
+
* halt the run — a trip denies just this one tool call. */
|
|
59
|
+
export type ToolInputGuardrailDecision = {
|
|
60
|
+
pass: true;
|
|
61
|
+
} | {
|
|
62
|
+
pass: false;
|
|
63
|
+
reason: string;
|
|
64
|
+
};
|
|
65
|
+
/** Validates a tool call's arguments BEFORE it executes (and before any HITL
|
|
66
|
+
* approval interruption). On a trip the call is denied — the model receives the
|
|
67
|
+
* denial reason as an error tool result; the run continues and the approver is
|
|
68
|
+
* never consulted. Arguments are immutable once the model emits them, so a single
|
|
69
|
+
* pre-execution check is sufficient. */
|
|
70
|
+
export interface ToolInputGuardrail {
|
|
71
|
+
name: string;
|
|
72
|
+
check(ctx: ToolInputGuardrailContext): Promise<ToolInputGuardrailDecision> | ToolInputGuardrailDecision;
|
|
73
|
+
}
|
|
49
74
|
export interface GuardrailTriggeredContext {
|
|
50
75
|
runId: string;
|
|
51
76
|
agentId: string;
|
|
@@ -5,7 +5,7 @@ import type { CacheConfig, ThinkingConfig } from '../llm/types/request';
|
|
|
5
5
|
import type { ConversationHistory } from './history';
|
|
6
6
|
import type { HistorySnapshot } from './history-types';
|
|
7
7
|
import type { AgentTool } from './types';
|
|
8
|
-
import type { Guardrail } from './guardrail-types';
|
|
8
|
+
import type { Guardrail, ToolInputGuardrail } from './guardrail-types';
|
|
9
9
|
import type { PermissionPolicy } from '../plugins/permissions/policy';
|
|
10
10
|
import type { ApprovalRequest, ApprovalDecision } from './approval-types';
|
|
11
11
|
import type { Persistence } from '../plugins/persistence/types';
|
|
@@ -48,6 +48,10 @@ export interface AgentLoopConfig {
|
|
|
48
48
|
* output guardrails run after each step's response is produced.
|
|
49
49
|
* A tripwire decision halts the run with finishReason 'guardrail'. */
|
|
50
50
|
guardrails?: Guardrail[];
|
|
51
|
+
/** Per-tool-call input guardrails. Each runs against a tool call's arguments
|
|
52
|
+
* BEFORE the permission/approval check and execution. A trip denies just that
|
|
53
|
+
* call (error result to the model) without halting the run or invoking `approve`. */
|
|
54
|
+
toolInputGuardrails?: ToolInputGuardrail[];
|
|
51
55
|
/** Permission policy wired into the tool-execution path.
|
|
52
56
|
* Called after lookup, before execution.
|
|
53
57
|
* 'allow' -> proceed; 'deny' -> tool is blocked (error result to model);
|
package/dist/agent/loop.d.ts
CHANGED
package/dist/agent/types.d.ts
CHANGED
|
@@ -39,6 +39,11 @@ export interface AgentTool {
|
|
|
39
39
|
definition: Tool;
|
|
40
40
|
/** Execute the tool. Return string or structured content. */
|
|
41
41
|
execute: (args: Record<string, unknown>, context: ToolExecutionContext) => Promise<string | ContentPart[]>;
|
|
42
|
+
/** Optional: derive out-of-band metadata from a successful tool result, attached
|
|
43
|
+
* to this call's `ToolCallReport.customData`. The MODEL NEVER SEES IT — it is for
|
|
44
|
+
* your own telemetry/routing/audit. Runs after `execute`; may be async. Errors are
|
|
45
|
+
* swallowed (opt-in convenience must never break the tool result). */
|
|
46
|
+
customDataExtractor?: (result: string | ContentPart[], args: Record<string, unknown>, context: Omit<ToolExecutionContext, 'signal'>) => unknown | Promise<unknown>;
|
|
42
47
|
}
|
|
43
48
|
export interface ToolExecutionContext {
|
|
44
49
|
step: number;
|
|
@@ -65,6 +70,9 @@ export interface ToolCallReport {
|
|
|
65
70
|
value: number | string | boolean;
|
|
66
71
|
type: string;
|
|
67
72
|
}>;
|
|
73
|
+
/** Out-of-band metadata from the tool's `customDataExtractor`, if any. Never sent
|
|
74
|
+
* to the model; present only when an extractor returned a value. */
|
|
75
|
+
customData?: unknown;
|
|
68
76
|
}
|
|
69
77
|
export interface StepReport {
|
|
70
78
|
index: number;
|
package/dist/index.browser.js
CHANGED
|
@@ -23305,7 +23305,10 @@ var AnthropicAdapter = class {
|
|
|
23305
23305
|
});
|
|
23306
23306
|
const headers = {};
|
|
23307
23307
|
if (hasFileRef) headers["anthropic-beta"] = "files-api-2025-04-14";
|
|
23308
|
-
|
|
23308
|
+
const usesCodeExec = req.tools?.some(
|
|
23309
|
+
(t) => !isFunctionTool(t) && t.type === "code_interpreter"
|
|
23310
|
+
);
|
|
23311
|
+
return { body, headers, ...usesCodeExec ? { path: "/v1/messages?beta=true" } : {} };
|
|
23309
23312
|
}
|
|
23310
23313
|
enableStreaming(providerReq, _req) {
|
|
23311
23314
|
providerReq.body.stream = true;
|
|
@@ -23387,11 +23390,11 @@ var AnthropicAdapter = class {
|
|
|
23387
23390
|
};
|
|
23388
23391
|
content.push(tc);
|
|
23389
23392
|
toolCalls.push(tc);
|
|
23390
|
-
} else if (block.type === "code_execution_tool_result") {
|
|
23393
|
+
} else if (block.type === "bash_code_execution_tool_result" || block.type === "code_execution_tool_result") {
|
|
23391
23394
|
const result = block.content;
|
|
23392
|
-
if (result
|
|
23395
|
+
if (result && (result.type === "bash_code_execution_result" || result.type === "code_execution_result") && Array.isArray(result.content)) {
|
|
23393
23396
|
for (const out of result.content) {
|
|
23394
|
-
if (out.type === "code_execution_output" && typeof out.file_id === "string") {
|
|
23397
|
+
if ((out.type === "bash_code_execution_output" || out.type === "code_execution_output") && typeof out.file_id === "string") {
|
|
23395
23398
|
files.push({ id: out.file_id, source: "code_execution" });
|
|
23396
23399
|
}
|
|
23397
23400
|
}
|
|
@@ -23899,7 +23902,9 @@ var GoogleAdapter = class {
|
|
|
23899
23902
|
const content = [];
|
|
23900
23903
|
const toolCalls = [];
|
|
23901
23904
|
const media = [];
|
|
23905
|
+
const files = [];
|
|
23902
23906
|
let thinking = null;
|
|
23907
|
+
const hasCodeExec = parts.some((p) => p.executableCode || p.codeExecutionResult);
|
|
23903
23908
|
for (const part of parts) {
|
|
23904
23909
|
if (part.text !== void 0 && !part.thought) {
|
|
23905
23910
|
content.push({ type: "text", text: part.text });
|
|
@@ -23910,7 +23915,9 @@ var GoogleAdapter = class {
|
|
|
23910
23915
|
if (part.inlineData) {
|
|
23911
23916
|
const inline = part.inlineData;
|
|
23912
23917
|
const mime = inline.mimeType;
|
|
23913
|
-
if (
|
|
23918
|
+
if (hasCodeExec) {
|
|
23919
|
+
files.push({ data: inline.data, mimeType: mime, source: "code_execution" });
|
|
23920
|
+
} else if (mime.startsWith("image/")) {
|
|
23914
23921
|
const p = {
|
|
23915
23922
|
type: "image_output",
|
|
23916
23923
|
mediaId: "",
|
|
@@ -23971,6 +23978,7 @@ var GoogleAdapter = class {
|
|
|
23971
23978
|
toolCalls,
|
|
23972
23979
|
thinking,
|
|
23973
23980
|
media,
|
|
23981
|
+
...files.length ? { files } : {},
|
|
23974
23982
|
latencyMs,
|
|
23975
23983
|
raw
|
|
23976
23984
|
};
|
|
@@ -25949,6 +25957,7 @@ var OpenAIResponsesAdapter = class {
|
|
|
25949
25957
|
const content = [];
|
|
25950
25958
|
const toolCalls = [];
|
|
25951
25959
|
const media = [];
|
|
25960
|
+
const files = [];
|
|
25952
25961
|
let thinking = null;
|
|
25953
25962
|
let text = "";
|
|
25954
25963
|
for (const item of output) {
|
|
@@ -25960,6 +25969,22 @@ var OpenAIResponsesAdapter = class {
|
|
|
25960
25969
|
const t = c.text;
|
|
25961
25970
|
text += t;
|
|
25962
25971
|
content.push({ type: "text", text: t });
|
|
25972
|
+
for (const a of c.annotations ?? []) {
|
|
25973
|
+
if (a.type === "container_file_citation" && typeof a.file_id === "string") {
|
|
25974
|
+
files.push({
|
|
25975
|
+
id: a.file_id,
|
|
25976
|
+
...typeof a.filename === "string" ? { name: a.filename } : {},
|
|
25977
|
+
source: "code_execution"
|
|
25978
|
+
});
|
|
25979
|
+
}
|
|
25980
|
+
}
|
|
25981
|
+
}
|
|
25982
|
+
}
|
|
25983
|
+
}
|
|
25984
|
+
if (type === "code_interpreter_call") {
|
|
25985
|
+
for (const out of item.outputs ?? []) {
|
|
25986
|
+
if (out.type === "image" && typeof out.url === "string") {
|
|
25987
|
+
files.push({ url: out.url, source: "code_execution" });
|
|
25963
25988
|
}
|
|
25964
25989
|
}
|
|
25965
25990
|
}
|
|
@@ -26012,6 +26037,7 @@ var OpenAIResponsesAdapter = class {
|
|
|
26012
26037
|
toolCalls,
|
|
26013
26038
|
thinking,
|
|
26014
26039
|
media,
|
|
26040
|
+
...files.length ? { files } : {},
|
|
26015
26041
|
...moderation ? { moderation } : {},
|
|
26016
26042
|
latencyMs,
|
|
26017
26043
|
raw
|
|
@@ -27738,6 +27764,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
27738
27764
|
_toolTimeout;
|
|
27739
27765
|
_maxSteps;
|
|
27740
27766
|
_guardrails;
|
|
27767
|
+
_toolInputGuardrails;
|
|
27741
27768
|
_policy;
|
|
27742
27769
|
_approve;
|
|
27743
27770
|
_checkpoint;
|
|
@@ -27765,6 +27792,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
27765
27792
|
this._toolTimeout = config.toolTimeout ?? DEFAULT_TOOL_TIMEOUT_MS;
|
|
27766
27793
|
this._maxSteps = config.maxSteps !== void 0 && config.maxSteps > 0 ? config.maxSteps : DEFAULT_MAX_STEPS;
|
|
27767
27794
|
this._guardrails = config.guardrails ?? [];
|
|
27795
|
+
this._toolInputGuardrails = config.toolInputGuardrails ?? [];
|
|
27768
27796
|
this._policy = config.policy ?? null;
|
|
27769
27797
|
this._approve = config.approve ?? null;
|
|
27770
27798
|
this._checkpoint = config.checkpoint ?? null;
|
|
@@ -27983,6 +28011,10 @@ var AgentLoop = class _AgentLoop {
|
|
|
27983
28011
|
toolCalls: lastResponse?.toolCalls ?? [],
|
|
27984
28012
|
thinking: lastResponse?.thinking ?? null,
|
|
27985
28013
|
media: lastResponse?.media ?? [],
|
|
28014
|
+
// Propagate hosted-tool file outputs + inline-moderation result from the final
|
|
28015
|
+
// LLM response (e.g. code-execution files produced during the run).
|
|
28016
|
+
...lastResponse?.files ? { files: lastResponse.files } : {},
|
|
28017
|
+
...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
|
|
27986
28018
|
latencyMs: performance.now() - startPerf,
|
|
27987
28019
|
raw: lastResponse?.raw ?? null
|
|
27988
28020
|
};
|
|
@@ -28177,6 +28209,8 @@ var AgentLoop = class _AgentLoop {
|
|
|
28177
28209
|
toolCalls: lastResponse?.toolCalls ?? [],
|
|
28178
28210
|
thinking: lastResponse?.thinking ?? null,
|
|
28179
28211
|
media: [],
|
|
28212
|
+
...lastResponse?.files ? { files: lastResponse.files } : {},
|
|
28213
|
+
...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
|
|
28180
28214
|
latencyMs: performance.now() - startPerf,
|
|
28181
28215
|
raw: null
|
|
28182
28216
|
};
|
|
@@ -28263,6 +28297,18 @@ var AgentLoop = class _AgentLoop {
|
|
|
28263
28297
|
runTrace
|
|
28264
28298
|
);
|
|
28265
28299
|
if (!lookup.found) return lookup.errorResult;
|
|
28300
|
+
for (const g of this._toolInputGuardrails) {
|
|
28301
|
+
const decision = await g.check({
|
|
28302
|
+
toolName: tc.name,
|
|
28303
|
+
arguments: tc.arguments,
|
|
28304
|
+
callId: tc.id,
|
|
28305
|
+
step,
|
|
28306
|
+
trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id }
|
|
28307
|
+
});
|
|
28308
|
+
if (!decision.pass) {
|
|
28309
|
+
return this.buildDeniedResult(tc, decision.reason, reports);
|
|
28310
|
+
}
|
|
28311
|
+
}
|
|
28266
28312
|
if (this._policy !== null) {
|
|
28267
28313
|
const target = {
|
|
28268
28314
|
kind: "tool",
|
|
@@ -28279,7 +28325,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
28279
28325
|
try {
|
|
28280
28326
|
const baseCtx = { step, callId: tc.id, metrics, trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id } };
|
|
28281
28327
|
const result = await executeWithTimeout(lookup.tool, tc, baseCtx, this._toolTimeout);
|
|
28282
|
-
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace);
|
|
28328
|
+
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, lookup.tool, baseCtx);
|
|
28283
28329
|
} catch (e) {
|
|
28284
28330
|
return handleToolError(e, tc, this.hooks, runId, this.id, step, metrics, reports, toolStart, runTrace);
|
|
28285
28331
|
}
|
|
@@ -28370,7 +28416,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
28370
28416
|
try {
|
|
28371
28417
|
const baseCtx = { step, callId: tc.id, metrics, trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id } };
|
|
28372
28418
|
const result = await executeWithTimeout(tool, tc, baseCtx, this._toolTimeout);
|
|
28373
|
-
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace);
|
|
28419
|
+
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, tool, baseCtx);
|
|
28374
28420
|
} catch (e) {
|
|
28375
28421
|
return handleToolError(e, tc, this.hooks, runId, this.id, step, metrics, reports, toolStart, runTrace);
|
|
28376
28422
|
}
|
|
@@ -28382,9 +28428,16 @@ var AgentLoop = class _AgentLoop {
|
|
|
28382
28428
|
return this.buildDeniedResult(tc, denyMsg, reports);
|
|
28383
28429
|
}
|
|
28384
28430
|
/** Emit onToolCallComplete, push report, and return success content part. */
|
|
28385
|
-
async buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace) {
|
|
28431
|
+
async buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, tool, context) {
|
|
28386
28432
|
const latencyMs = performance.now() - toolStart;
|
|
28387
28433
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
28434
|
+
let customData;
|
|
28435
|
+
if (tool?.customDataExtractor && context) {
|
|
28436
|
+
try {
|
|
28437
|
+
customData = await tool.customDataExtractor(result, tc.arguments, context);
|
|
28438
|
+
} catch {
|
|
28439
|
+
}
|
|
28440
|
+
}
|
|
28388
28441
|
await this.hooks.emit("onToolCallComplete", {
|
|
28389
28442
|
runId,
|
|
28390
28443
|
agentId: this.id,
|
|
@@ -28406,7 +28459,8 @@ var AgentLoop = class _AgentLoop {
|
|
|
28406
28459
|
latencyMs,
|
|
28407
28460
|
skipped: false,
|
|
28408
28461
|
error: null,
|
|
28409
|
-
metrics: Object.fromEntries(metrics)
|
|
28462
|
+
metrics: Object.fromEntries(metrics),
|
|
28463
|
+
...customData !== void 0 ? { customData } : {}
|
|
28410
28464
|
});
|
|
28411
28465
|
return { type: "tool_result", id: tc.id, content: resultStr };
|
|
28412
28466
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -98,7 +98,7 @@ export type { ConversationHistoryConfig, HistoryEntry, HistorySnapshot } from '.
|
|
|
98
98
|
export { AgentLoop } from './agent/loop';
|
|
99
99
|
export type { AgentLoopConfig } from './agent/loop-config';
|
|
100
100
|
export type { AgentLoopSnapshot, AgentRunReport, AgentStreamEvent, AgentTool, ContentClass, LearnInput, StepReport, TokenCountContext, TokenCounter, ToolCallReport, ToolExecutionContext } from './agent/types';
|
|
101
|
-
export type { Guardrail, GuardrailDecision, GuardrailPass, GuardrailTrip, GuardrailCheckContext, InputGuardrailContext, OutputGuardrailContext, GuardrailTriggeredContext } from './agent/guardrail-types';
|
|
101
|
+
export type { Guardrail, GuardrailDecision, GuardrailPass, GuardrailTrip, GuardrailCheckContext, InputGuardrailContext, OutputGuardrailContext, GuardrailTriggeredContext, ToolInputGuardrail, ToolInputGuardrailContext, ToolInputGuardrailDecision } from './agent/guardrail-types';
|
|
102
102
|
export { BearerKeyAuth } from './server/auth';
|
|
103
103
|
export type { AuthPlugin, AuthVerifyResult } from './server/auth';
|
|
104
104
|
export { dispatch } from './server/dispatch';
|
package/dist/index.js
CHANGED
|
@@ -23232,7 +23232,10 @@ var AnthropicAdapter = class {
|
|
|
23232
23232
|
});
|
|
23233
23233
|
const headers = {};
|
|
23234
23234
|
if (hasFileRef) headers["anthropic-beta"] = "files-api-2025-04-14";
|
|
23235
|
-
|
|
23235
|
+
const usesCodeExec = req.tools?.some(
|
|
23236
|
+
(t) => !isFunctionTool(t) && t.type === "code_interpreter"
|
|
23237
|
+
);
|
|
23238
|
+
return { body, headers, ...usesCodeExec ? { path: "/v1/messages?beta=true" } : {} };
|
|
23236
23239
|
}
|
|
23237
23240
|
enableStreaming(providerReq, _req) {
|
|
23238
23241
|
providerReq.body.stream = true;
|
|
@@ -23314,11 +23317,11 @@ var AnthropicAdapter = class {
|
|
|
23314
23317
|
};
|
|
23315
23318
|
content.push(tc);
|
|
23316
23319
|
toolCalls.push(tc);
|
|
23317
|
-
} else if (block.type === "code_execution_tool_result") {
|
|
23320
|
+
} else if (block.type === "bash_code_execution_tool_result" || block.type === "code_execution_tool_result") {
|
|
23318
23321
|
const result = block.content;
|
|
23319
|
-
if (result
|
|
23322
|
+
if (result && (result.type === "bash_code_execution_result" || result.type === "code_execution_result") && Array.isArray(result.content)) {
|
|
23320
23323
|
for (const out of result.content) {
|
|
23321
|
-
if (out.type === "code_execution_output" && typeof out.file_id === "string") {
|
|
23324
|
+
if ((out.type === "bash_code_execution_output" || out.type === "code_execution_output") && typeof out.file_id === "string") {
|
|
23322
23325
|
files.push({ id: out.file_id, source: "code_execution" });
|
|
23323
23326
|
}
|
|
23324
23327
|
}
|
|
@@ -23826,7 +23829,9 @@ var GoogleAdapter = class {
|
|
|
23826
23829
|
const content = [];
|
|
23827
23830
|
const toolCalls = [];
|
|
23828
23831
|
const media = [];
|
|
23832
|
+
const files = [];
|
|
23829
23833
|
let thinking = null;
|
|
23834
|
+
const hasCodeExec = parts.some((p) => p.executableCode || p.codeExecutionResult);
|
|
23830
23835
|
for (const part of parts) {
|
|
23831
23836
|
if (part.text !== void 0 && !part.thought) {
|
|
23832
23837
|
content.push({ type: "text", text: part.text });
|
|
@@ -23837,7 +23842,9 @@ var GoogleAdapter = class {
|
|
|
23837
23842
|
if (part.inlineData) {
|
|
23838
23843
|
const inline = part.inlineData;
|
|
23839
23844
|
const mime = inline.mimeType;
|
|
23840
|
-
if (
|
|
23845
|
+
if (hasCodeExec) {
|
|
23846
|
+
files.push({ data: inline.data, mimeType: mime, source: "code_execution" });
|
|
23847
|
+
} else if (mime.startsWith("image/")) {
|
|
23841
23848
|
const p = {
|
|
23842
23849
|
type: "image_output",
|
|
23843
23850
|
mediaId: "",
|
|
@@ -23898,6 +23905,7 @@ var GoogleAdapter = class {
|
|
|
23898
23905
|
toolCalls,
|
|
23899
23906
|
thinking,
|
|
23900
23907
|
media,
|
|
23908
|
+
...files.length ? { files } : {},
|
|
23901
23909
|
latencyMs,
|
|
23902
23910
|
raw
|
|
23903
23911
|
};
|
|
@@ -25876,6 +25884,7 @@ var OpenAIResponsesAdapter = class {
|
|
|
25876
25884
|
const content = [];
|
|
25877
25885
|
const toolCalls = [];
|
|
25878
25886
|
const media = [];
|
|
25887
|
+
const files = [];
|
|
25879
25888
|
let thinking = null;
|
|
25880
25889
|
let text = "";
|
|
25881
25890
|
for (const item of output) {
|
|
@@ -25887,6 +25896,22 @@ var OpenAIResponsesAdapter = class {
|
|
|
25887
25896
|
const t = c.text;
|
|
25888
25897
|
text += t;
|
|
25889
25898
|
content.push({ type: "text", text: t });
|
|
25899
|
+
for (const a of c.annotations ?? []) {
|
|
25900
|
+
if (a.type === "container_file_citation" && typeof a.file_id === "string") {
|
|
25901
|
+
files.push({
|
|
25902
|
+
id: a.file_id,
|
|
25903
|
+
...typeof a.filename === "string" ? { name: a.filename } : {},
|
|
25904
|
+
source: "code_execution"
|
|
25905
|
+
});
|
|
25906
|
+
}
|
|
25907
|
+
}
|
|
25908
|
+
}
|
|
25909
|
+
}
|
|
25910
|
+
}
|
|
25911
|
+
if (type === "code_interpreter_call") {
|
|
25912
|
+
for (const out of item.outputs ?? []) {
|
|
25913
|
+
if (out.type === "image" && typeof out.url === "string") {
|
|
25914
|
+
files.push({ url: out.url, source: "code_execution" });
|
|
25890
25915
|
}
|
|
25891
25916
|
}
|
|
25892
25917
|
}
|
|
@@ -25939,6 +25964,7 @@ var OpenAIResponsesAdapter = class {
|
|
|
25939
25964
|
toolCalls,
|
|
25940
25965
|
thinking,
|
|
25941
25966
|
media,
|
|
25967
|
+
...files.length ? { files } : {},
|
|
25942
25968
|
...moderation ? { moderation } : {},
|
|
25943
25969
|
latencyMs,
|
|
25944
25970
|
raw
|
|
@@ -27665,6 +27691,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
27665
27691
|
_toolTimeout;
|
|
27666
27692
|
_maxSteps;
|
|
27667
27693
|
_guardrails;
|
|
27694
|
+
_toolInputGuardrails;
|
|
27668
27695
|
_policy;
|
|
27669
27696
|
_approve;
|
|
27670
27697
|
_checkpoint;
|
|
@@ -27692,6 +27719,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
27692
27719
|
this._toolTimeout = config.toolTimeout ?? DEFAULT_TOOL_TIMEOUT_MS;
|
|
27693
27720
|
this._maxSteps = config.maxSteps !== void 0 && config.maxSteps > 0 ? config.maxSteps : DEFAULT_MAX_STEPS;
|
|
27694
27721
|
this._guardrails = config.guardrails ?? [];
|
|
27722
|
+
this._toolInputGuardrails = config.toolInputGuardrails ?? [];
|
|
27695
27723
|
this._policy = config.policy ?? null;
|
|
27696
27724
|
this._approve = config.approve ?? null;
|
|
27697
27725
|
this._checkpoint = config.checkpoint ?? null;
|
|
@@ -27910,6 +27938,10 @@ var AgentLoop = class _AgentLoop {
|
|
|
27910
27938
|
toolCalls: lastResponse?.toolCalls ?? [],
|
|
27911
27939
|
thinking: lastResponse?.thinking ?? null,
|
|
27912
27940
|
media: lastResponse?.media ?? [],
|
|
27941
|
+
// Propagate hosted-tool file outputs + inline-moderation result from the final
|
|
27942
|
+
// LLM response (e.g. code-execution files produced during the run).
|
|
27943
|
+
...lastResponse?.files ? { files: lastResponse.files } : {},
|
|
27944
|
+
...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
|
|
27913
27945
|
latencyMs: performance.now() - startPerf,
|
|
27914
27946
|
raw: lastResponse?.raw ?? null
|
|
27915
27947
|
};
|
|
@@ -28104,6 +28136,8 @@ var AgentLoop = class _AgentLoop {
|
|
|
28104
28136
|
toolCalls: lastResponse?.toolCalls ?? [],
|
|
28105
28137
|
thinking: lastResponse?.thinking ?? null,
|
|
28106
28138
|
media: [],
|
|
28139
|
+
...lastResponse?.files ? { files: lastResponse.files } : {},
|
|
28140
|
+
...lastResponse?.moderation ? { moderation: lastResponse.moderation } : {},
|
|
28107
28141
|
latencyMs: performance.now() - startPerf,
|
|
28108
28142
|
raw: null
|
|
28109
28143
|
};
|
|
@@ -28190,6 +28224,18 @@ var AgentLoop = class _AgentLoop {
|
|
|
28190
28224
|
runTrace
|
|
28191
28225
|
);
|
|
28192
28226
|
if (!lookup.found) return lookup.errorResult;
|
|
28227
|
+
for (const g of this._toolInputGuardrails) {
|
|
28228
|
+
const decision = await g.check({
|
|
28229
|
+
toolName: tc.name,
|
|
28230
|
+
arguments: tc.arguments,
|
|
28231
|
+
callId: tc.id,
|
|
28232
|
+
step,
|
|
28233
|
+
trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id }
|
|
28234
|
+
});
|
|
28235
|
+
if (!decision.pass) {
|
|
28236
|
+
return this.buildDeniedResult(tc, decision.reason, reports);
|
|
28237
|
+
}
|
|
28238
|
+
}
|
|
28193
28239
|
if (this._policy !== null) {
|
|
28194
28240
|
const target = {
|
|
28195
28241
|
kind: "tool",
|
|
@@ -28206,7 +28252,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
28206
28252
|
try {
|
|
28207
28253
|
const baseCtx = { step, callId: tc.id, metrics, trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id } };
|
|
28208
28254
|
const result = await executeWithTimeout(lookup.tool, tc, baseCtx, this._toolTimeout);
|
|
28209
|
-
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace);
|
|
28255
|
+
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, lookup.tool, baseCtx);
|
|
28210
28256
|
} catch (e) {
|
|
28211
28257
|
return handleToolError(e, tc, this.hooks, runId, this.id, step, metrics, reports, toolStart, runTrace);
|
|
28212
28258
|
}
|
|
@@ -28297,7 +28343,7 @@ var AgentLoop = class _AgentLoop {
|
|
|
28297
28343
|
try {
|
|
28298
28344
|
const baseCtx = { step, callId: tc.id, metrics, trace: { sessionId: runTrace.sessionId, requestId: runTrace.requestId, callId: tc.id } };
|
|
28299
28345
|
const result = await executeWithTimeout(tool, tc, baseCtx, this._toolTimeout);
|
|
28300
|
-
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace);
|
|
28346
|
+
return await this.buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, tool, baseCtx);
|
|
28301
28347
|
} catch (e) {
|
|
28302
28348
|
return handleToolError(e, tc, this.hooks, runId, this.id, step, metrics, reports, toolStart, runTrace);
|
|
28303
28349
|
}
|
|
@@ -28309,9 +28355,16 @@ var AgentLoop = class _AgentLoop {
|
|
|
28309
28355
|
return this.buildDeniedResult(tc, denyMsg, reports);
|
|
28310
28356
|
}
|
|
28311
28357
|
/** Emit onToolCallComplete, push report, and return success content part. */
|
|
28312
|
-
async buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace) {
|
|
28358
|
+
async buildSuccessResult(tc, result, runId, step, metrics, reports, toolStart, runTrace, tool, context) {
|
|
28313
28359
|
const latencyMs = performance.now() - toolStart;
|
|
28314
28360
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
28361
|
+
let customData;
|
|
28362
|
+
if (tool?.customDataExtractor && context) {
|
|
28363
|
+
try {
|
|
28364
|
+
customData = await tool.customDataExtractor(result, tc.arguments, context);
|
|
28365
|
+
} catch {
|
|
28366
|
+
}
|
|
28367
|
+
}
|
|
28315
28368
|
await this.hooks.emit("onToolCallComplete", {
|
|
28316
28369
|
runId,
|
|
28317
28370
|
agentId: this.id,
|
|
@@ -28333,7 +28386,8 @@ var AgentLoop = class _AgentLoop {
|
|
|
28333
28386
|
latencyMs,
|
|
28334
28387
|
skipped: false,
|
|
28335
28388
|
error: null,
|
|
28336
|
-
metrics: Object.fromEntries(metrics)
|
|
28389
|
+
metrics: Object.fromEntries(metrics),
|
|
28390
|
+
...customData !== void 0 ? { customData } : {}
|
|
28337
28391
|
});
|
|
28338
28392
|
return { type: "tool_result", id: tc.id, content: resultStr };
|
|
28339
28393
|
}
|
|
@@ -34,6 +34,9 @@ export interface FileOutput {
|
|
|
34
34
|
mimeType?: string;
|
|
35
35
|
/** Inline bytes (base64) when the provider returns the file inline; else absent. */
|
|
36
36
|
data?: string;
|
|
37
|
+
/** URL to fetch the file when the provider returns one (e.g. OpenAI code-interpreter
|
|
38
|
+
* image outputs); else absent. */
|
|
39
|
+
url?: string;
|
|
37
40
|
/** What produced it (e.g. 'code_execution'). */
|
|
38
41
|
source?: string;
|
|
39
42
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@combycode/llm-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Unified, pluggable AI SDK for accessing the LLMs of every major provider (Anthropic, OpenAI, Google, xAI, OpenRouter) through one API. Cross-environment: Node, Bun, and the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|