@vextlabs/theron-agent-sdk 0.3.0 → 0.3.1
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 +16 -0
- package/dist/adapters/theron.cjs +13 -2
- package/dist/adapters/theron.js +13 -2
- package/dist/agent/index.cjs +111 -2
- package/dist/agent/index.d.cts +43 -2
- package/dist/agent/index.d.ts +43 -2
- package/dist/agent/index.js +108 -3
- package/dist/council/index.cjs +4 -0
- package/dist/council/index.d.cts +25 -1
- package/dist/council/index.d.ts +25 -1
- package/dist/council/index.js +4 -1
- package/dist/index.cjs +490 -65
- package/dist/index.d.cts +64 -5
- package/dist/index.d.ts +64 -5
- package/dist/index.js +479 -66
- package/dist/loop/index.cjs +2 -1
- package/dist/loop/index.d.cts +3 -0
- package/dist/loop/index.d.ts +3 -0
- package/dist/loop/index.js +2 -1
- package/dist/mcp/index.cjs +27 -10
- package/dist/mcp/index.d.cts +2 -1
- package/dist/mcp/index.d.ts +2 -1
- package/dist/mcp/index.js +27 -10
- package/dist/runtime/index.cjs +145 -33
- package/dist/runtime/index.d.cts +78 -3
- package/dist/runtime/index.d.ts +78 -3
- package/dist/runtime/index.js +144 -34
- package/dist/tools/index.cjs +45 -10
- package/dist/tools/index.js +45 -10
- package/package.json +1 -1
package/dist/runtime/index.d.ts
CHANGED
|
@@ -6,6 +6,65 @@ import { ToolContext } from '../tools/index.js';
|
|
|
6
6
|
import { VerifierResult } from '../verifiers/index.js';
|
|
7
7
|
import 'zod';
|
|
8
8
|
|
|
9
|
+
interface CloudExecResult {
|
|
10
|
+
stdout: string;
|
|
11
|
+
stderr: string;
|
|
12
|
+
/** 0 on success. Non-zero exit is RETURNED, never thrown. 124 = timeout. */
|
|
13
|
+
exitCode: number;
|
|
14
|
+
}
|
|
15
|
+
interface CloudExecOptions {
|
|
16
|
+
/** Working directory, relative to (or inside) the session root. */
|
|
17
|
+
cwd?: string;
|
|
18
|
+
/** Hard timeout in ms (default 120000). */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
/** Extra environment variables for the command. */
|
|
21
|
+
env?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* An isolated, per-session execution environment with a filesystem.
|
|
25
|
+
*
|
|
26
|
+
* Lifecycle: a {@link CloudSessionProvider} hands back a live session from
|
|
27
|
+
* `provision()`; call `dispose()` to release it (tear down the VM / delete the
|
|
28
|
+
* workspace). All file paths are resolved INSIDE the session root; a path that
|
|
29
|
+
* escapes the root is rejected.
|
|
30
|
+
*/
|
|
31
|
+
interface CloudSession {
|
|
32
|
+
/** Stable id, for receipts and logs. */
|
|
33
|
+
readonly id: string;
|
|
34
|
+
/** Absolute path to the session filesystem root (backend-specific). */
|
|
35
|
+
readonly root: string;
|
|
36
|
+
/** Run a shell command in the session. Non-zero exit is returned, not thrown. */
|
|
37
|
+
exec(command: string, options?: CloudExecOptions): Promise<CloudExecResult>;
|
|
38
|
+
/** Read a session file as UTF-8 (path resolved inside the root). */
|
|
39
|
+
readFile(path: string): Promise<string>;
|
|
40
|
+
/** Write a session file, creating parent dirs (path resolved inside the root). */
|
|
41
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
42
|
+
/** Release the session. Idempotent. */
|
|
43
|
+
dispose(): Promise<void>;
|
|
44
|
+
}
|
|
45
|
+
interface CloudSessionProvider {
|
|
46
|
+
/** Provision a fresh, isolated session. */
|
|
47
|
+
provision(): Promise<CloudSession>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* In-process {@link CloudSession} backend: a temp workspace on the host, commands
|
|
51
|
+
* via `/bin/sh -c`. For tests/CI/local dev only — NOT a security boundary.
|
|
52
|
+
*/
|
|
53
|
+
declare class LocalCloudSession implements CloudSession {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly root: string;
|
|
56
|
+
private disposed;
|
|
57
|
+
constructor(id: string, root: string);
|
|
58
|
+
exec(command: string, options?: CloudExecOptions): Promise<CloudExecResult>;
|
|
59
|
+
readFile(path: string): Promise<string>;
|
|
60
|
+
writeFile(path: string, content: string): Promise<void>;
|
|
61
|
+
dispose(): Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
/** Provisions {@link LocalCloudSession}s in fresh OS temp dirs. */
|
|
64
|
+
declare class LocalCloudSessionProvider implements CloudSessionProvider {
|
|
65
|
+
provision(): Promise<CloudSession>;
|
|
66
|
+
}
|
|
67
|
+
|
|
9
68
|
/** Events the Runner emits as it executes. Subscribe via runner.on(). */
|
|
10
69
|
type RunnerEvent = {
|
|
11
70
|
type: "agent_start";
|
|
@@ -47,6 +106,13 @@ type RunnerEvent = {
|
|
|
47
106
|
type: "council_done";
|
|
48
107
|
council: string;
|
|
49
108
|
output: CouncilOutput;
|
|
109
|
+
} | {
|
|
110
|
+
type: "max_turns_exhausted";
|
|
111
|
+
agent: string;
|
|
112
|
+
turns: number;
|
|
113
|
+
} | {
|
|
114
|
+
type: "aborted";
|
|
115
|
+
agent: string;
|
|
50
116
|
} | {
|
|
51
117
|
type: "error";
|
|
52
118
|
agent: string;
|
|
@@ -77,6 +143,8 @@ interface ModelAdapter {
|
|
|
77
143
|
max_tokens?: number;
|
|
78
144
|
temperature?: number;
|
|
79
145
|
onDelta?: (delta: string) => void;
|
|
146
|
+
/** Cancellation signal — adapters should forward it to fetch(). */
|
|
147
|
+
signal?: AbortSignal;
|
|
80
148
|
}): Promise<{
|
|
81
149
|
content: string;
|
|
82
150
|
tool_calls?: Array<{
|
|
@@ -87,8 +155,15 @@ interface ModelAdapter {
|
|
|
87
155
|
input: number;
|
|
88
156
|
output: number;
|
|
89
157
|
};
|
|
158
|
+
/** Optional per-call cost in USD. Adapters that can compute it should set
|
|
159
|
+
* it so AgentResult.cost_usd and the costUsdAtLeast stop-predicate work. */
|
|
160
|
+
cost_usd?: number;
|
|
90
161
|
}>;
|
|
91
162
|
}
|
|
163
|
+
/** Per-run options. `signal` cancels the loop cooperatively. */
|
|
164
|
+
interface RunOptions {
|
|
165
|
+
signal?: AbortSignal;
|
|
166
|
+
}
|
|
92
167
|
interface RunnerConfig {
|
|
93
168
|
/** The model adapter to use. */
|
|
94
169
|
model: ModelAdapter;
|
|
@@ -135,14 +210,14 @@ declare class Runner {
|
|
|
135
210
|
* 4. Run any registered verifier kernels on the final output
|
|
136
211
|
* 5. Return the AgentResult
|
|
137
212
|
*/
|
|
138
|
-
run(agent: Agent, query: string): Promise<AgentResult>;
|
|
213
|
+
run(agent: Agent, query: string, opts?: RunOptions): Promise<AgentResult>;
|
|
139
214
|
/**
|
|
140
215
|
* Run a Council on a query.
|
|
141
216
|
*
|
|
142
217
|
* Fan out to all specialists in parallel (with timeout), gather outputs,
|
|
143
218
|
* run council-level verifier kernels on each, and reconcile.
|
|
144
219
|
*/
|
|
145
|
-
runCouncil(council: Council, query: string): Promise<CouncilOutput>;
|
|
220
|
+
runCouncil(council: Council, query: string, opts?: RunOptions): Promise<CouncilOutput>;
|
|
146
221
|
}
|
|
147
222
|
|
|
148
|
-
export { type ModelAdapter, Runner, type RunnerConfig, type RunnerEvent };
|
|
223
|
+
export { type CloudExecOptions, type CloudExecResult, type CloudSession, type CloudSessionProvider, LocalCloudSession, LocalCloudSessionProvider, type ModelAdapter, type RunOptions, Runner, type RunnerConfig, type RunnerEvent };
|
package/dist/runtime/index.js
CHANGED
|
@@ -1,3 +1,73 @@
|
|
|
1
|
+
import { readFile, mkdir, writeFile, rm, mkdtemp } from 'fs/promises';
|
|
2
|
+
import { tmpdir } from 'os';
|
|
3
|
+
import { dirname, join, isAbsolute, resolve, relative, sep } from 'path';
|
|
4
|
+
import { execFile } from 'child_process';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
|
|
8
|
+
// src/runtime/cloud-session.ts
|
|
9
|
+
var pExecFile = promisify(execFile);
|
|
10
|
+
function resolveInside(root, p) {
|
|
11
|
+
const abs = isAbsolute(p) ? p : resolve(root, p);
|
|
12
|
+
const rel = relative(root, abs);
|
|
13
|
+
if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
|
|
14
|
+
throw new Error(`path escapes session root: ${p}`);
|
|
15
|
+
}
|
|
16
|
+
return abs;
|
|
17
|
+
}
|
|
18
|
+
var LocalCloudSession = class {
|
|
19
|
+
id;
|
|
20
|
+
root;
|
|
21
|
+
disposed = false;
|
|
22
|
+
constructor(id, root) {
|
|
23
|
+
this.id = id;
|
|
24
|
+
this.root = root;
|
|
25
|
+
}
|
|
26
|
+
async exec(command, options = {}) {
|
|
27
|
+
if (this.disposed) throw new Error("session disposed");
|
|
28
|
+
const cwd = options.cwd ? resolveInside(this.root, options.cwd) : this.root;
|
|
29
|
+
try {
|
|
30
|
+
const { stdout, stderr } = await pExecFile("/bin/sh", ["-c", command], {
|
|
31
|
+
cwd,
|
|
32
|
+
timeout: options.timeoutMs ?? 12e4,
|
|
33
|
+
env: { ...process.env, ...options.env ?? {} },
|
|
34
|
+
maxBuffer: 64 * 1024 * 1024
|
|
35
|
+
});
|
|
36
|
+
return { stdout: stdout.toString(), stderr: stderr.toString(), exitCode: 0 };
|
|
37
|
+
} catch (e) {
|
|
38
|
+
const err = e;
|
|
39
|
+
const exitCode = typeof err.code === "number" ? err.code : err.killed ? 124 : 1;
|
|
40
|
+
return {
|
|
41
|
+
stdout: (err.stdout ?? "").toString(),
|
|
42
|
+
stderr: (err.stderr ?? err.message ?? String(e)).toString(),
|
|
43
|
+
exitCode
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async readFile(path) {
|
|
48
|
+
if (this.disposed) throw new Error("session disposed");
|
|
49
|
+
return readFile(resolveInside(this.root, path), "utf8");
|
|
50
|
+
}
|
|
51
|
+
async writeFile(path, content) {
|
|
52
|
+
if (this.disposed) throw new Error("session disposed");
|
|
53
|
+
const abs = resolveInside(this.root, path);
|
|
54
|
+
await mkdir(dirname(abs), { recursive: true });
|
|
55
|
+
await writeFile(abs, content, "utf8");
|
|
56
|
+
}
|
|
57
|
+
async dispose() {
|
|
58
|
+
if (this.disposed) return;
|
|
59
|
+
this.disposed = true;
|
|
60
|
+
await rm(this.root, { recursive: true, force: true });
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var LocalCloudSessionProvider = class {
|
|
64
|
+
async provision() {
|
|
65
|
+
const id = randomUUID();
|
|
66
|
+
const root = await mkdtemp(join(tmpdir(), `theron-session-${id.slice(0, 8)}-`));
|
|
67
|
+
return new LocalCloudSession(id, root);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
1
71
|
// src/runtime/index.ts
|
|
2
72
|
var Runner = class {
|
|
3
73
|
model;
|
|
@@ -35,8 +105,9 @@ var Runner = class {
|
|
|
35
105
|
* 4. Run any registered verifier kernels on the final output
|
|
36
106
|
* 5. Return the AgentResult
|
|
37
107
|
*/
|
|
38
|
-
async run(agent, query) {
|
|
108
|
+
async run(agent, query, opts) {
|
|
39
109
|
const startedAt = Date.now();
|
|
110
|
+
const signal = opts?.signal;
|
|
40
111
|
this.emit({ type: "agent_start", agent: agent.name, query });
|
|
41
112
|
const messages = [
|
|
42
113
|
{ role: "system", content: agent.instruction.system }
|
|
@@ -49,49 +120,84 @@ var Runner = class {
|
|
|
49
120
|
const toolCalls = [];
|
|
50
121
|
let tokensIn = 0;
|
|
51
122
|
let tokensOut = 0;
|
|
123
|
+
let costUsd = 0;
|
|
52
124
|
let finalOutput = "";
|
|
125
|
+
let completed = false;
|
|
126
|
+
let aborted = false;
|
|
53
127
|
for (let turn = 0; turn < agent.max_turns; turn++) {
|
|
128
|
+
if (signal?.aborted) {
|
|
129
|
+
aborted = true;
|
|
130
|
+
this.emit({ type: "aborted", agent: agent.name });
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
54
133
|
const response = await this.model.chat({
|
|
55
134
|
model: agent.model ?? this.default_model,
|
|
56
135
|
messages,
|
|
57
136
|
tools: agent.toolSchemas(),
|
|
58
|
-
onDelta: (delta) => this.emit({ type: "agent_thinking", agent: agent.name, delta })
|
|
137
|
+
onDelta: (delta) => this.emit({ type: "agent_thinking", agent: agent.name, delta }),
|
|
138
|
+
signal
|
|
59
139
|
});
|
|
60
140
|
tokensIn += response.tokens.input;
|
|
61
141
|
tokensOut += response.tokens.output;
|
|
142
|
+
costUsd += response.cost_usd ?? 0;
|
|
62
143
|
if (response.tool_calls && response.tool_calls.length > 0) {
|
|
63
144
|
messages.push({ role: "assistant", content: response.content });
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
agent: agent.name,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
145
|
+
const calls = response.tool_calls;
|
|
146
|
+
const results = await Promise.all(
|
|
147
|
+
calls.map(async (call) => {
|
|
148
|
+
const subAgent = agent.findSubAgent(call.name);
|
|
149
|
+
if (subAgent) {
|
|
150
|
+
this.emit({ type: "tool_call_start", agent: agent.name, tool: call.name, input: call.input });
|
|
151
|
+
const t02 = Date.now();
|
|
152
|
+
try {
|
|
153
|
+
const task = typeof call.input?.task === "string" ? call.input.task : JSON.stringify(call.input);
|
|
154
|
+
const sub = await this.run(subAgent, task, { signal });
|
|
155
|
+
const ms = Date.now() - t02;
|
|
156
|
+
this.emit({ type: "tool_call_done", agent: agent.name, tool: call.name, output: sub.output, ms });
|
|
157
|
+
return { call, output: sub.output, content: sub.output, ok: true };
|
|
158
|
+
} catch (err) {
|
|
159
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
160
|
+
this.emit({ type: "error", agent: agent.name, message: `Sub-agent ${subAgent.name} threw: ${msg}` });
|
|
161
|
+
return { call, content: `error: ${msg}`, ok: false };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const tool = agent.tools.find((t) => t.schema.name === call.name);
|
|
165
|
+
if (!tool) {
|
|
166
|
+
this.emit({
|
|
167
|
+
type: "error",
|
|
168
|
+
agent: agent.name,
|
|
169
|
+
message: `Model called unknown tool: ${call.name}`
|
|
170
|
+
});
|
|
171
|
+
return { call, content: `error: unknown tool ${call.name}`, ok: false };
|
|
172
|
+
}
|
|
173
|
+
this.emit({ type: "tool_call_start", agent: agent.name, tool: call.name, input: call.input });
|
|
174
|
+
const t0 = Date.now();
|
|
175
|
+
try {
|
|
176
|
+
const output = await tool.execute(call.input, this.tool_context);
|
|
177
|
+
const ms = Date.now() - t0;
|
|
178
|
+
this.emit({ type: "tool_call_done", agent: agent.name, tool: call.name, output, ms });
|
|
179
|
+
return { call, output, content: JSON.stringify(output), ok: true };
|
|
180
|
+
} catch (err) {
|
|
181
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
182
|
+
this.emit({ type: "error", agent: agent.name, message: `Tool ${call.name} threw: ${msg}` });
|
|
183
|
+
return { call, content: `error: ${msg}`, ok: false };
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
);
|
|
187
|
+
for (const r of results) {
|
|
188
|
+
if (r.ok) toolCalls.push({ name: r.call.name, input: r.call.input, output: r.output });
|
|
189
|
+
messages.push({ role: "tool", content: r.content });
|
|
88
190
|
}
|
|
89
191
|
continue;
|
|
90
192
|
}
|
|
91
193
|
finalOutput = response.content;
|
|
92
194
|
messages.push({ role: "assistant", content: finalOutput });
|
|
195
|
+
completed = true;
|
|
93
196
|
break;
|
|
94
197
|
}
|
|
198
|
+
if (!completed && !aborted) {
|
|
199
|
+
this.emit({ type: "max_turns_exhausted", agent: agent.name, turns: agent.max_turns });
|
|
200
|
+
}
|
|
95
201
|
this.emit({ type: "agent_output", agent: agent.name, output: finalOutput });
|
|
96
202
|
const verifier_results = [];
|
|
97
203
|
for (const v of agent.verifiers) {
|
|
@@ -114,8 +220,8 @@ var Runner = class {
|
|
|
114
220
|
tool_calls: toolCalls,
|
|
115
221
|
verifier_results,
|
|
116
222
|
tokens_used: { input: tokensIn, output: tokensOut },
|
|
117
|
-
cost_usd:
|
|
118
|
-
// adapter-
|
|
223
|
+
cost_usd: costUsd,
|
|
224
|
+
// summed from adapter-reported per-call cost (0 if the adapter doesn't report it)
|
|
119
225
|
latency_ms
|
|
120
226
|
};
|
|
121
227
|
}
|
|
@@ -125,17 +231,18 @@ var Runner = class {
|
|
|
125
231
|
* Fan out to all specialists in parallel (with timeout), gather outputs,
|
|
126
232
|
* run council-level verifier kernels on each, and reconcile.
|
|
127
233
|
*/
|
|
128
|
-
async runCouncil(council, query) {
|
|
234
|
+
async runCouncil(council, query, opts) {
|
|
129
235
|
const startedAt = Date.now();
|
|
236
|
+
const signal = opts?.signal;
|
|
130
237
|
this.emit({ type: "council_start", council: council.name, query });
|
|
131
238
|
const withTimeout = (p, ms) => Promise.race([
|
|
132
239
|
p,
|
|
133
|
-
new Promise((
|
|
240
|
+
new Promise((resolve2) => setTimeout(() => resolve2(null), ms))
|
|
134
241
|
]);
|
|
135
242
|
const specialistResults = await Promise.all(
|
|
136
243
|
council.specialists.map(async (spec) => {
|
|
137
244
|
try {
|
|
138
|
-
const result = await withTimeout(this.run(spec, query), council.specialist_timeout_ms);
|
|
245
|
+
const result = await withTimeout(this.run(spec, query, { signal }), council.specialist_timeout_ms);
|
|
139
246
|
if (result === null) {
|
|
140
247
|
this.emit({
|
|
141
248
|
type: "error",
|
|
@@ -161,8 +268,11 @@ var Runner = class {
|
|
|
161
268
|
const out = {
|
|
162
269
|
specialist: spec.name,
|
|
163
270
|
output: result.output,
|
|
164
|
-
claims
|
|
165
|
-
//
|
|
271
|
+
// Extract claims if the council supplies an extractor; otherwise the
|
|
272
|
+
// reconciler is responsible (the default deterministic reconciler
|
|
273
|
+
// votes over these claims, so a council that wants automatic
|
|
274
|
+
// ratification should set `claimExtractor`).
|
|
275
|
+
claims: council.claimExtractor ? council.claimExtractor(result.output) : [],
|
|
166
276
|
// AgentResult.verifier_results widens issues to unknown[]; at the
|
|
167
277
|
// runtime layer we know every entry came from a Verifier.check()
|
|
168
278
|
// call (which produces VerifierIssue[]), so the cast is sound.
|
|
@@ -200,4 +310,4 @@ var Runner = class {
|
|
|
200
310
|
}
|
|
201
311
|
};
|
|
202
312
|
|
|
203
|
-
export { Runner };
|
|
313
|
+
export { LocalCloudSession, LocalCloudSessionProvider, Runner };
|
package/dist/tools/index.cjs
CHANGED
|
@@ -26,22 +26,57 @@ function defineTool(opts) {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
function zodToJsonSchema(schema) {
|
|
29
|
+
const description = schema._def?.description;
|
|
30
|
+
const withDesc = (s) => description ? { ...s, description } : s;
|
|
31
|
+
if (schema instanceof zod.z.ZodOptional) return zodToJsonSchema(schema.unwrap());
|
|
32
|
+
if (schema instanceof zod.z.ZodDefault) {
|
|
33
|
+
const innerType = schema._def.innerType;
|
|
34
|
+
const inner = zodToJsonSchema(innerType);
|
|
35
|
+
let def;
|
|
36
|
+
try {
|
|
37
|
+
def = schema._def.defaultValue?.();
|
|
38
|
+
} catch {
|
|
39
|
+
def = void 0;
|
|
40
|
+
}
|
|
41
|
+
return withDesc(def === void 0 ? inner : { ...inner, default: def });
|
|
42
|
+
}
|
|
43
|
+
if (schema instanceof zod.z.ZodNullable) {
|
|
44
|
+
return withDesc({ ...zodToJsonSchema(schema.unwrap()), nullable: true });
|
|
45
|
+
}
|
|
29
46
|
if (schema instanceof zod.z.ZodObject) {
|
|
30
47
|
const properties = {};
|
|
31
48
|
const required = [];
|
|
32
49
|
for (const [key, value] of Object.entries(schema.shape)) {
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
const field = value;
|
|
51
|
+
properties[key] = zodToJsonSchema(field);
|
|
52
|
+
if (!(field instanceof zod.z.ZodOptional) && !(field instanceof zod.z.ZodDefault)) {
|
|
53
|
+
required.push(key);
|
|
54
|
+
}
|
|
35
55
|
}
|
|
36
|
-
return { type: "object", properties, ...required.length > 0 ? { required } : {} };
|
|
56
|
+
return withDesc({ type: "object", properties, ...required.length > 0 ? { required } : {} });
|
|
37
57
|
}
|
|
38
|
-
if (schema instanceof zod.z.ZodString) return { type: "string" };
|
|
39
|
-
if (schema instanceof zod.z.ZodNumber) return { type: "number" };
|
|
40
|
-
if (schema instanceof zod.z.ZodBoolean) return { type: "boolean" };
|
|
41
|
-
if (schema instanceof zod.z.ZodArray) return { type: "array", items: zodToJsonSchema(schema.element) };
|
|
42
|
-
if (schema instanceof zod.z.
|
|
43
|
-
if (schema instanceof zod.z.
|
|
44
|
-
|
|
58
|
+
if (schema instanceof zod.z.ZodString) return withDesc({ type: "string" });
|
|
59
|
+
if (schema instanceof zod.z.ZodNumber) return withDesc({ type: "number" });
|
|
60
|
+
if (schema instanceof zod.z.ZodBoolean) return withDesc({ type: "boolean" });
|
|
61
|
+
if (schema instanceof zod.z.ZodArray) return withDesc({ type: "array", items: zodToJsonSchema(schema.element) });
|
|
62
|
+
if (schema instanceof zod.z.ZodEnum) return withDesc({ type: "string", enum: schema.options });
|
|
63
|
+
if (schema instanceof zod.z.ZodLiteral) {
|
|
64
|
+
const val = schema.value;
|
|
65
|
+
const t = typeof val === "number" ? "number" : typeof val === "boolean" ? "boolean" : "string";
|
|
66
|
+
return withDesc({ type: t, enum: [val] });
|
|
67
|
+
}
|
|
68
|
+
if (schema instanceof zod.z.ZodUnion) {
|
|
69
|
+
const options = schema._def.options;
|
|
70
|
+
return withDesc({ anyOf: options.map((o) => zodToJsonSchema(o)) });
|
|
71
|
+
}
|
|
72
|
+
if (schema instanceof zod.z.ZodRecord) {
|
|
73
|
+
const valueType = schema._def.valueType;
|
|
74
|
+
return withDesc({
|
|
75
|
+
type: "object",
|
|
76
|
+
additionalProperties: valueType ? zodToJsonSchema(valueType) : true
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return withDesc({ type: "string" });
|
|
45
80
|
}
|
|
46
81
|
|
|
47
82
|
Object.defineProperty(exports, "zod", {
|
package/dist/tools/index.js
CHANGED
|
@@ -25,22 +25,57 @@ function defineTool(opts) {
|
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
27
|
function zodToJsonSchema(schema) {
|
|
28
|
+
const description = schema._def?.description;
|
|
29
|
+
const withDesc = (s) => description ? { ...s, description } : s;
|
|
30
|
+
if (schema instanceof z.ZodOptional) return zodToJsonSchema(schema.unwrap());
|
|
31
|
+
if (schema instanceof z.ZodDefault) {
|
|
32
|
+
const innerType = schema._def.innerType;
|
|
33
|
+
const inner = zodToJsonSchema(innerType);
|
|
34
|
+
let def;
|
|
35
|
+
try {
|
|
36
|
+
def = schema._def.defaultValue?.();
|
|
37
|
+
} catch {
|
|
38
|
+
def = void 0;
|
|
39
|
+
}
|
|
40
|
+
return withDesc(def === void 0 ? inner : { ...inner, default: def });
|
|
41
|
+
}
|
|
42
|
+
if (schema instanceof z.ZodNullable) {
|
|
43
|
+
return withDesc({ ...zodToJsonSchema(schema.unwrap()), nullable: true });
|
|
44
|
+
}
|
|
28
45
|
if (schema instanceof z.ZodObject) {
|
|
29
46
|
const properties = {};
|
|
30
47
|
const required = [];
|
|
31
48
|
for (const [key, value] of Object.entries(schema.shape)) {
|
|
32
|
-
|
|
33
|
-
|
|
49
|
+
const field = value;
|
|
50
|
+
properties[key] = zodToJsonSchema(field);
|
|
51
|
+
if (!(field instanceof z.ZodOptional) && !(field instanceof z.ZodDefault)) {
|
|
52
|
+
required.push(key);
|
|
53
|
+
}
|
|
34
54
|
}
|
|
35
|
-
return { type: "object", properties, ...required.length > 0 ? { required } : {} };
|
|
55
|
+
return withDesc({ type: "object", properties, ...required.length > 0 ? { required } : {} });
|
|
36
56
|
}
|
|
37
|
-
if (schema instanceof z.ZodString) return { type: "string" };
|
|
38
|
-
if (schema instanceof z.ZodNumber) return { type: "number" };
|
|
39
|
-
if (schema instanceof z.ZodBoolean) return { type: "boolean" };
|
|
40
|
-
if (schema instanceof z.ZodArray) return { type: "array", items: zodToJsonSchema(schema.element) };
|
|
41
|
-
if (schema instanceof z.
|
|
42
|
-
if (schema instanceof z.
|
|
43
|
-
|
|
57
|
+
if (schema instanceof z.ZodString) return withDesc({ type: "string" });
|
|
58
|
+
if (schema instanceof z.ZodNumber) return withDesc({ type: "number" });
|
|
59
|
+
if (schema instanceof z.ZodBoolean) return withDesc({ type: "boolean" });
|
|
60
|
+
if (schema instanceof z.ZodArray) return withDesc({ type: "array", items: zodToJsonSchema(schema.element) });
|
|
61
|
+
if (schema instanceof z.ZodEnum) return withDesc({ type: "string", enum: schema.options });
|
|
62
|
+
if (schema instanceof z.ZodLiteral) {
|
|
63
|
+
const val = schema.value;
|
|
64
|
+
const t = typeof val === "number" ? "number" : typeof val === "boolean" ? "boolean" : "string";
|
|
65
|
+
return withDesc({ type: t, enum: [val] });
|
|
66
|
+
}
|
|
67
|
+
if (schema instanceof z.ZodUnion) {
|
|
68
|
+
const options = schema._def.options;
|
|
69
|
+
return withDesc({ anyOf: options.map((o) => zodToJsonSchema(o)) });
|
|
70
|
+
}
|
|
71
|
+
if (schema instanceof z.ZodRecord) {
|
|
72
|
+
const valueType = schema._def.valueType;
|
|
73
|
+
return withDesc({
|
|
74
|
+
type: "object",
|
|
75
|
+
additionalProperties: valueType ? zodToJsonSchema(valueType) : true
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return withDesc({ type: "string" });
|
|
44
79
|
}
|
|
45
80
|
|
|
46
81
|
export { defineTool };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vextlabs/theron-agent-sdk",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Open-source agent SDK with a Council of specialists, deterministic verifier kernels, and Stoa-signed integrations. Build any agent against any model. From Vext Labs.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://tryvext.com/adk",
|