@zhanla/sdk-ts 0.1.0 → 0.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/README.md +19 -5
- package/bin/discover.js +204 -13
- package/dist/executor.js +4 -0
- package/dist/manifest.d.ts +18 -9
- package/dist/manifest.js +40 -12
- package/dist/types.d.ts +45 -11
- package/dist/types.js +63 -78
- package/package.json +1 -2
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ Requires Node `>=18`.
|
|
|
14
14
|
|
|
15
15
|
Provider packages such as `@anthropic-ai/sdk`, `openai`, and `@google/genai` are optional. Install them only if you use `Runner` with those clients.
|
|
16
16
|
|
|
17
|
+
Every component requires an explicit stable `key`. Use a lowercase, hyphenated identifier such as `support-agent`.
|
|
18
|
+
|
|
17
19
|
## Quick Start
|
|
18
20
|
|
|
19
21
|
```ts
|
|
@@ -27,6 +29,7 @@ const runner = new Runner({
|
|
|
27
29
|
export const supportAgent = new Agent({
|
|
28
30
|
name: "support_agent",
|
|
29
31
|
description: "Respond to support requests.",
|
|
32
|
+
key: "support-agent",
|
|
30
33
|
instructions: 'Answer clearly. Return JSON: {"answer": "..."}',
|
|
31
34
|
model: "claude-sonnet-4-6",
|
|
32
35
|
runner,
|
|
@@ -42,6 +45,7 @@ export const supportAgent = new Agent({
|
|
|
42
45
|
export const supportEval = new CodeEval({
|
|
43
46
|
name: "support_eval",
|
|
44
47
|
description: "Check whether an answer was returned.",
|
|
48
|
+
key: "support-eval",
|
|
45
49
|
fn: (kwargs: unknown) => {
|
|
46
50
|
const { model_response } = kwargs as { model_response?: string };
|
|
47
51
|
const parsed = model_response ? JSON.parse(model_response) : {};
|
|
@@ -53,7 +57,7 @@ export const supportEval = new CodeEval({
|
|
|
53
57
|
Run it with the CLI:
|
|
54
58
|
|
|
55
59
|
```bash
|
|
56
|
-
|
|
60
|
+
zhanla run components.ts:support_agent --dataset tickets.json --eval components.ts:support_eval
|
|
57
61
|
```
|
|
58
62
|
|
|
59
63
|
## Public API
|
|
@@ -92,6 +96,7 @@ Use a `Tool` for deterministic TypeScript logic.
|
|
|
92
96
|
export const lookupCustomer = new Tool({
|
|
93
97
|
name: "lookup_customer",
|
|
94
98
|
description: "Fetch a customer record by ID.",
|
|
99
|
+
key: "lookup-customer",
|
|
95
100
|
inputSchema: { type: "object", properties: {} },
|
|
96
101
|
fn: (kwargs: unknown) => {
|
|
97
102
|
const { customerId } = kwargs as { customerId: string };
|
|
@@ -122,6 +127,7 @@ Use a `Skill` for reusable instructions and tool access.
|
|
|
122
127
|
export const summarizeSkill = new Skill({
|
|
123
128
|
name: "summarize_skill",
|
|
124
129
|
description: "Reusable summarization instructions.",
|
|
130
|
+
key: "summarize-skill",
|
|
125
131
|
instructions: "Summarize the provided text in one short paragraph.",
|
|
126
132
|
tools: [lookupCustomer],
|
|
127
133
|
});
|
|
@@ -144,6 +150,7 @@ const runner = new Runner({
|
|
|
144
150
|
export const supportAgent = new Agent({
|
|
145
151
|
name: "support_agent",
|
|
146
152
|
description: "Respond to support requests.",
|
|
153
|
+
key: "support-agent",
|
|
147
154
|
instructions: 'Answer clearly. Return JSON: {"answer": "..."}',
|
|
148
155
|
model: "gpt-4.1-mini",
|
|
149
156
|
runner,
|
|
@@ -174,6 +181,7 @@ const runner = new Runner({
|
|
|
174
181
|
export const intentClassifier = new LLMProcessor({
|
|
175
182
|
name: "intent_classifier",
|
|
176
183
|
description: "Classify intent.",
|
|
184
|
+
key: "intent-classifier",
|
|
177
185
|
instructions: 'Return JSON: {"intent": "billing|technical|other"}',
|
|
178
186
|
model: "claude-haiku-4-5",
|
|
179
187
|
runner,
|
|
@@ -195,6 +203,7 @@ Use an `LLMEval` for LLM-backed evaluation logic.
|
|
|
195
203
|
export const toneEval = new LLMEval({
|
|
196
204
|
name: "tone_eval",
|
|
197
205
|
description: "Evaluate tone.",
|
|
206
|
+
key: "tone-eval",
|
|
198
207
|
instructions: 'Return JSON: {"score": 0.0, "reason": "..."}',
|
|
199
208
|
model: "gpt-4.1-mini",
|
|
200
209
|
runner,
|
|
@@ -217,8 +226,13 @@ Use an `Orchestration` to compose steps into a DAG.
|
|
|
217
226
|
export const supportPipeline = new Orchestration({
|
|
218
227
|
name: "support_pipeline",
|
|
219
228
|
description: "Classify intent, then draft a reply.",
|
|
229
|
+
key: "support-pipeline",
|
|
220
230
|
steps: [
|
|
221
|
-
new Step({
|
|
231
|
+
new Step({
|
|
232
|
+
name: "classify",
|
|
233
|
+
component: intentClassifier,
|
|
234
|
+
next: ["reply"],
|
|
235
|
+
}),
|
|
222
236
|
new Step({ name: "reply", component: supportAgent }),
|
|
223
237
|
],
|
|
224
238
|
});
|
|
@@ -260,7 +274,7 @@ const runner = new Runner({
|
|
|
260
274
|
|
|
261
275
|
- `constructor({ client })` wraps the client internally with `wrap(...)`
|
|
262
276
|
- `buildMessages(component, row)` defaults to `[system instructions, user JSON row]`
|
|
263
|
-
- `callLlm({ messages, model, tools, outputSchema })` supports Anthropic, OpenAI-compatible chat clients, and Gemini
|
|
277
|
+
- `callLlm({ messages, model, tools, outputSchema, temperature, topK })` supports Anthropic, OpenAI-compatible chat clients, and Gemini
|
|
264
278
|
|
|
265
279
|
Current local execution behavior:
|
|
266
280
|
|
|
@@ -268,7 +282,7 @@ Current local execution behavior:
|
|
|
268
282
|
- `model` must be set explicitly
|
|
269
283
|
- response text is parsed as JSON when possible, otherwise wrapped as `{ result: text }`
|
|
270
284
|
- `outputSchema` is used for validation
|
|
271
|
-
- returned tool calls
|
|
285
|
+
- returned tool calls are exposed as `_toolCalls` on the local execution output
|
|
272
286
|
|
|
273
287
|
## Observability
|
|
274
288
|
|
|
@@ -303,7 +317,7 @@ if (ctx) {
|
|
|
303
317
|
TypeScript discovery loads your module and collects exported component instances.
|
|
304
318
|
|
|
305
319
|
```bash
|
|
306
|
-
|
|
320
|
+
zhanla run workflow.ts:support_pipeline --dataset tickets.json --eval evals.ts:answer_quality
|
|
307
321
|
```
|
|
308
322
|
|
|
309
323
|
The package also ships a helper CLI:
|
package/bin/discover.js
CHANGED
|
@@ -1,16 +1,201 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* zhanla-sdk-ts discover <file.ts>
|
|
3
|
+
* zhanla-sdk-ts discover <file.ts[:ExportName]>
|
|
4
|
+
*
|
|
5
|
+
* Loads a TypeScript module via tsx, walks the transitive closure from a
|
|
6
|
+
* named root (or all exported roots if no name given), and emits the full
|
|
7
|
+
* closure as a JSON array to stdout (leaf-first order).
|
|
4
8
|
*
|
|
5
|
-
* Loads a TypeScript module via tsx, collects exported BaseComponent instances,
|
|
6
|
-
* emits their manifests as a JSON array to stdout.
|
|
7
9
|
* Exits non-zero if no components are found or the file fails to load.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
12
|
import { pathToFileURL } from "url";
|
|
11
13
|
import { resolve } from "path";
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
function isComponentLike(value) {
|
|
16
|
+
return (
|
|
17
|
+
value != null &&
|
|
18
|
+
typeof value === "object" &&
|
|
19
|
+
typeof value.componentType === "string" &&
|
|
20
|
+
typeof value.name === "string" &&
|
|
21
|
+
typeof value.key === "string"
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isConditionalLike(value) {
|
|
26
|
+
return (
|
|
27
|
+
value != null &&
|
|
28
|
+
typeof value === "object" &&
|
|
29
|
+
typeof value.condition === "function" &&
|
|
30
|
+
typeof value.ifTrue === "string" &&
|
|
31
|
+
typeof value.ifFalse === "string"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getBranchChildren(node) {
|
|
36
|
+
if (!node) return [];
|
|
37
|
+
const children = [];
|
|
38
|
+
if (node.eval && isComponentLike(node.eval)) children.push(node.eval);
|
|
39
|
+
for (const edge of [...(node.ifPass || []), ...(node.ifFail || [])]) {
|
|
40
|
+
if (edge && edge.node) children.push(...getBranchChildren(edge.node));
|
|
41
|
+
}
|
|
42
|
+
return children;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getChildren(comp) {
|
|
46
|
+
const children = [];
|
|
47
|
+
for (const attr of ["tools", "skills", "agents", "evals"]) {
|
|
48
|
+
if (Array.isArray(comp[attr])) {
|
|
49
|
+
children.push(...comp[attr].filter(isComponentLike));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (comp.componentType === "orchestration" && Array.isArray(comp.steps)) {
|
|
53
|
+
for (const step of comp.steps) {
|
|
54
|
+
if (step.component && !isConditionalLike(step.component) && isComponentLike(step.component)) {
|
|
55
|
+
children.push(step.component);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (comp.componentType === "eval_tree" && comp.root) {
|
|
60
|
+
children.push(...getBranchChildren(comp.root));
|
|
61
|
+
}
|
|
62
|
+
return children;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function stableSerialize(value) {
|
|
66
|
+
if (Array.isArray(value)) {
|
|
67
|
+
return `[${value.map((entry) => stableSerialize(entry)).join(",")}]`;
|
|
68
|
+
}
|
|
69
|
+
if (value != null && typeof value === "object") {
|
|
70
|
+
const entries = Object.entries(value)
|
|
71
|
+
.filter(([, entry]) => entry !== undefined)
|
|
72
|
+
.sort(([left], [right]) => left.localeCompare(right));
|
|
73
|
+
return `{${entries
|
|
74
|
+
.map(([key, entry]) => `${JSON.stringify(key)}:${stableSerialize(entry)}`)
|
|
75
|
+
.join(",")}}`;
|
|
76
|
+
}
|
|
77
|
+
return JSON.stringify(value);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function sortRefsByKey(refs) {
|
|
81
|
+
return [...refs].sort((left, right) => left.key.localeCompare(right.key));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function behaviorFields(manifest) {
|
|
85
|
+
const fields = {
|
|
86
|
+
component_type: manifest.component_type,
|
|
87
|
+
execution_mode: manifest.execution_mode,
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
if (manifest.instructions != null) fields.instructions = manifest.instructions;
|
|
91
|
+
if (manifest.model != null) fields.model = manifest.model;
|
|
92
|
+
if (manifest.temperature != null) fields.temperature = manifest.temperature;
|
|
93
|
+
if (manifest.output_schema != null) fields.output_schema = manifest.output_schema;
|
|
94
|
+
if (manifest.tool_refs != null) fields.tool_refs = sortRefsByKey(manifest.tool_refs);
|
|
95
|
+
if (manifest.skill_refs != null) fields.skill_refs = sortRefsByKey(manifest.skill_refs);
|
|
96
|
+
if (manifest.agent_refs != null) fields.agent_refs = sortRefsByKey(manifest.agent_refs);
|
|
97
|
+
if (manifest.steps != null) fields.steps = manifest.steps;
|
|
98
|
+
if (manifest.eval_refs != null) fields.eval_refs = sortRefsByKey(manifest.eval_refs);
|
|
99
|
+
if (manifest.weights != null) fields.weights = manifest.weights;
|
|
100
|
+
if (manifest.root != null) fields.root = manifest.root;
|
|
101
|
+
if (manifest.source_code != null) fields.source_code = manifest.source_code;
|
|
102
|
+
if (manifest.model_response_format != null) {
|
|
103
|
+
fields.model_response_format = manifest.model_response_format;
|
|
104
|
+
}
|
|
105
|
+
if (manifest.fn_present != null) fields.fn_present = manifest.fn_present;
|
|
106
|
+
if (manifest.is_async != null) fields.is_async = manifest.is_async;
|
|
107
|
+
|
|
108
|
+
return fields;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function manifestBehaviorSignature(manifest) {
|
|
112
|
+
return stableSerialize(behaviorFields(manifest));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function getManifestOptions(comp, filePath, symbolByComponent, fallbackToName = false) {
|
|
116
|
+
const symbolName = symbolByComponent.get(comp);
|
|
117
|
+
return {
|
|
118
|
+
filePath,
|
|
119
|
+
symbolName: symbolName ?? (fallbackToName ? comp.name : undefined),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function collectClosureManifests(roots, toManifest, filePath, symbolByComponent) {
|
|
124
|
+
const seen = new Map();
|
|
125
|
+
const signaturesByKey = new Map();
|
|
126
|
+
const order = [];
|
|
127
|
+
|
|
128
|
+
function visit(comp) {
|
|
129
|
+
const closureKey = `${comp.componentType}:${comp.key}`;
|
|
130
|
+
const existing = seen.get(closureKey);
|
|
131
|
+
if (existing) {
|
|
132
|
+
if (existing !== comp) {
|
|
133
|
+
const signature = manifestBehaviorSignature(
|
|
134
|
+
toManifest(comp, getManifestOptions(comp, filePath, symbolByComponent))
|
|
135
|
+
);
|
|
136
|
+
if (signaturesByKey.get(closureKey) !== signature) {
|
|
137
|
+
throw new Error(
|
|
138
|
+
`Conflict: two different ${comp.componentType} objects claim key '${comp.key}' but have different behavior.`
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
seen.set(closureKey, comp);
|
|
146
|
+
const manifest = toManifest(comp, getManifestOptions(comp, filePath, symbolByComponent));
|
|
147
|
+
signaturesByKey.set(closureKey, manifestBehaviorSignature(manifest));
|
|
148
|
+
|
|
149
|
+
for (const child of getChildren(comp)) {
|
|
150
|
+
visit(child);
|
|
151
|
+
}
|
|
152
|
+
order.push(comp);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const root of roots) {
|
|
156
|
+
visit(root);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return order.map((comp) =>
|
|
160
|
+
toManifest(comp, {
|
|
161
|
+
filePath,
|
|
162
|
+
symbolName: symbolByComponent.get(comp) ?? comp.name,
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function buildDiscoveredManifests({
|
|
168
|
+
allComponents,
|
|
169
|
+
symbolByComponent,
|
|
170
|
+
symbolName,
|
|
171
|
+
toManifest,
|
|
172
|
+
filePath,
|
|
173
|
+
}) {
|
|
174
|
+
if (symbolName) {
|
|
175
|
+
const root = allComponents.find(
|
|
176
|
+
(c) => symbolByComponent.get(c) === symbolName || c.name === symbolName
|
|
177
|
+
);
|
|
178
|
+
if (!root) {
|
|
179
|
+
const available = allComponents.map((c) => symbolByComponent.get(c) ?? c.name).join(", ");
|
|
180
|
+
throw new Error(`Component '${symbolName}' not found in ${filePath}. Available: ${available}`);
|
|
181
|
+
}
|
|
182
|
+
return collectClosureManifests([root], toManifest, filePath, symbolByComponent);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return collectClosureManifests(allComponents, toManifest, filePath, symbolByComponent);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function runDiscover(fileSpec) {
|
|
189
|
+
let filePath = fileSpec;
|
|
190
|
+
let symbolName = null;
|
|
191
|
+
|
|
192
|
+
const colonIndex = fileSpec.lastIndexOf(":");
|
|
193
|
+
// Handle Windows drive letters (e.g. C:\...) — only split if colon is not at position 1
|
|
194
|
+
if (colonIndex > 1) {
|
|
195
|
+
filePath = fileSpec.slice(0, colonIndex);
|
|
196
|
+
symbolName = fileSpec.slice(colonIndex + 1) || null;
|
|
197
|
+
}
|
|
198
|
+
|
|
14
199
|
const absolutePath = resolve(filePath);
|
|
15
200
|
const fileUrl = pathToFileURL(absolutePath).href;
|
|
16
201
|
|
|
@@ -22,26 +207,25 @@ export async function runDiscover(filePath) {
|
|
|
22
207
|
process.exit(1);
|
|
23
208
|
}
|
|
24
209
|
|
|
25
|
-
// Dynamically import from the built SDK (or tsx will resolve from node_modules)
|
|
26
210
|
let collectExportedComponents, toManifest;
|
|
27
211
|
try {
|
|
28
212
|
const sdk = await import("@zhanla/sdk-ts");
|
|
29
213
|
collectExportedComponents = sdk.collectExportedComponents;
|
|
30
214
|
toManifest = sdk.toManifest;
|
|
31
215
|
} catch {
|
|
32
|
-
// Fallback: try loading from relative path (dev mode)
|
|
33
216
|
const sdk = await import(new URL("../dist/index.js", import.meta.url).href);
|
|
34
217
|
collectExportedComponents = sdk.collectExportedComponents;
|
|
35
218
|
toManifest = sdk.toManifest;
|
|
36
219
|
}
|
|
37
220
|
|
|
38
|
-
const
|
|
221
|
+
const allComponents = collectExportedComponents(moduleExports);
|
|
39
222
|
|
|
40
|
-
if (
|
|
223
|
+
if (allComponents.length === 0) {
|
|
41
224
|
console.error(`No zhanla components found in ${filePath}`);
|
|
42
225
|
process.exit(1);
|
|
43
226
|
}
|
|
44
227
|
|
|
228
|
+
// Build symbol name map for exported components
|
|
45
229
|
const symbolByComponent = new Map();
|
|
46
230
|
const namespaces = [moduleExports];
|
|
47
231
|
if (
|
|
@@ -59,12 +243,19 @@ export async function runDiscover(filePath) {
|
|
|
59
243
|
}
|
|
60
244
|
}
|
|
61
245
|
|
|
62
|
-
|
|
63
|
-
|
|
246
|
+
let manifests;
|
|
247
|
+
try {
|
|
248
|
+
manifests = buildDiscoveredManifests({
|
|
249
|
+
allComponents,
|
|
250
|
+
symbolByComponent,
|
|
251
|
+
symbolName,
|
|
252
|
+
toManifest,
|
|
64
253
|
filePath: absolutePath,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
254
|
+
});
|
|
255
|
+
} catch (err) {
|
|
256
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
257
|
+
process.exit(1);
|
|
258
|
+
}
|
|
68
259
|
|
|
69
260
|
process.stdout.write(JSON.stringify(manifests) + "\n");
|
|
70
261
|
}
|
package/dist/executor.js
CHANGED
|
@@ -213,6 +213,8 @@ function validateSchemaValue(value, schema, path = "$") {
|
|
|
213
213
|
return typeof value === "string" ? [] : [`${path} must be a string`];
|
|
214
214
|
case "number":
|
|
215
215
|
return typeof value === "number" ? [] : [`${path} must be a number`];
|
|
216
|
+
case "integer":
|
|
217
|
+
return typeof value === "number" && Number.isInteger(value) ? [] : [`${path} must be an integer`];
|
|
216
218
|
case "boolean":
|
|
217
219
|
return typeof value === "boolean" ? [] : [`${path} must be a boolean`];
|
|
218
220
|
case "null":
|
|
@@ -241,6 +243,8 @@ async function runRunnerComponent(comp, kwargs) {
|
|
|
241
243
|
tools: "tools" in comp ? comp.tools : [],
|
|
242
244
|
outputSchema: comp.outputSchema,
|
|
243
245
|
jsonRepair: comp.jsonRepair,
|
|
246
|
+
temperature: "temperature" in comp ? comp.temperature : undefined,
|
|
247
|
+
topK: "topK" in comp ? comp.topK : undefined,
|
|
244
248
|
});
|
|
245
249
|
const hasTextOutput = response.text.trim() !== "";
|
|
246
250
|
const hasToolCalls = response.toolCalls.length > 0;
|
package/dist/manifest.d.ts
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Manifest emission — serialize SDK component instances into ComponentManifest objects.
|
|
3
3
|
* The manifest shape mirrors the Python CLI's ComponentManifest dataclass.
|
|
4
4
|
*/
|
|
5
|
-
import { BaseComponent, JsonSchema } from "./types.js";
|
|
5
|
+
import { BaseComponent, ComponentRef, JsonSchema } from "./types.js";
|
|
6
6
|
export interface StepManifest {
|
|
7
7
|
name: string;
|
|
8
|
-
|
|
8
|
+
component_ref?: ComponentRef;
|
|
9
9
|
next: string[];
|
|
10
10
|
is_conditional?: boolean;
|
|
11
11
|
if_true?: string;
|
|
@@ -17,11 +17,11 @@ export interface EdgeManifest {
|
|
|
17
17
|
}
|
|
18
18
|
export interface LeafManifest {
|
|
19
19
|
type: "leaf";
|
|
20
|
-
|
|
20
|
+
eval_ref: ComponentRef;
|
|
21
21
|
}
|
|
22
22
|
export interface BranchManifest {
|
|
23
23
|
type: "branch";
|
|
24
|
-
|
|
24
|
+
eval_ref: ComponentRef;
|
|
25
25
|
threshold: number;
|
|
26
26
|
if_pass: EdgeManifest[];
|
|
27
27
|
if_fail: EdgeManifest[];
|
|
@@ -30,19 +30,28 @@ export interface ComponentManifest {
|
|
|
30
30
|
name: string;
|
|
31
31
|
description: string;
|
|
32
32
|
component_type: string;
|
|
33
|
+
/** Stable component identity — explicit if dev provided key, otherwise slugified from name. */
|
|
34
|
+
key: string;
|
|
35
|
+
/** "explicit" | "implicit" */
|
|
36
|
+
key_source: string;
|
|
33
37
|
language: "typescript";
|
|
34
38
|
is_runnable: boolean;
|
|
35
39
|
is_eval: boolean;
|
|
36
|
-
|
|
40
|
+
execution_mode: string;
|
|
37
41
|
instructions?: string;
|
|
38
42
|
model?: string;
|
|
43
|
+
temperature?: number;
|
|
39
44
|
fn_present?: boolean;
|
|
40
45
|
is_async?: boolean;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
/** Typed tool references. */
|
|
47
|
+
tool_refs?: ComponentRef[];
|
|
48
|
+
/** Typed skill references. */
|
|
49
|
+
skill_refs?: ComponentRef[];
|
|
50
|
+
/** Typed agent references. */
|
|
51
|
+
agent_refs?: ComponentRef[];
|
|
44
52
|
steps?: StepManifest[];
|
|
45
|
-
|
|
53
|
+
/** Typed eval references for Checklist. */
|
|
54
|
+
eval_refs?: ComponentRef[];
|
|
46
55
|
weights?: number[];
|
|
47
56
|
root?: BranchManifest;
|
|
48
57
|
output_schema?: JsonSchema;
|
package/dist/manifest.js
CHANGED
|
@@ -12,7 +12,8 @@ function isComponentLike(value) {
|
|
|
12
12
|
typeof value.componentType === "string" &&
|
|
13
13
|
typeof value.name === "string" &&
|
|
14
14
|
typeof value.description === "string" &&
|
|
15
|
-
typeof value.
|
|
15
|
+
typeof value.isRunnable === "boolean" &&
|
|
16
|
+
typeof value.isEval === "boolean");
|
|
16
17
|
}
|
|
17
18
|
function isConditionalLike(value) {
|
|
18
19
|
return (value != null &&
|
|
@@ -27,18 +28,27 @@ function isLeafLike(value) {
|
|
|
27
28
|
"eval" in value &&
|
|
28
29
|
!("threshold" in value));
|
|
29
30
|
}
|
|
31
|
+
function resolveComponentRef(component) {
|
|
32
|
+
return {
|
|
33
|
+
key: component.key,
|
|
34
|
+
component_type: component.componentType,
|
|
35
|
+
name: component.name,
|
|
36
|
+
language: "typescript",
|
|
37
|
+
execution_mode: EXECUTION_MODES[component.componentType] ?? "unknown",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
30
40
|
function serializeEdge(edge) {
|
|
31
41
|
return {
|
|
32
42
|
weight: edge.weight,
|
|
33
43
|
node: isLeafLike(edge.node)
|
|
34
|
-
? { type: "leaf",
|
|
44
|
+
? { type: "leaf", eval_ref: resolveComponentRef(edge.node.eval) }
|
|
35
45
|
: serializeBranch(edge.node),
|
|
36
46
|
};
|
|
37
47
|
}
|
|
38
48
|
function serializeBranch(branch) {
|
|
39
49
|
return {
|
|
40
50
|
type: "branch",
|
|
41
|
-
|
|
51
|
+
eval_ref: resolveComponentRef(branch.eval),
|
|
42
52
|
threshold: branch.threshold,
|
|
43
53
|
if_pass: branch.ifPass.map(serializeEdge),
|
|
44
54
|
if_fail: branch.ifFail.map(serializeEdge),
|
|
@@ -128,16 +138,32 @@ function extractExportedComponentSource(filePath, symbolName) {
|
|
|
128
138
|
// ---------------------------------------------------------------------------
|
|
129
139
|
// to_manifest
|
|
130
140
|
// ---------------------------------------------------------------------------
|
|
141
|
+
const EXECUTION_MODES = {
|
|
142
|
+
tool: "code",
|
|
143
|
+
code_eval: "code",
|
|
144
|
+
skill: "prompt",
|
|
145
|
+
agent: "prompt",
|
|
146
|
+
llm_processor: "prompt",
|
|
147
|
+
llm_eval: "prompt",
|
|
148
|
+
orchestration: "dag",
|
|
149
|
+
checklist: "composite",
|
|
150
|
+
eval_tree: "composite",
|
|
151
|
+
};
|
|
131
152
|
export function toManifest(component, opts = {}) {
|
|
132
153
|
const componentSource = extractExportedComponentSource(opts.filePath, opts.symbolName);
|
|
154
|
+
const key = component.key;
|
|
155
|
+
const keySource = "explicit";
|
|
156
|
+
const executionMode = EXECUTION_MODES[component.componentType] ?? "unknown";
|
|
133
157
|
const base = {
|
|
134
158
|
name: component.name,
|
|
135
159
|
description: component.description,
|
|
136
160
|
component_type: component.componentType,
|
|
161
|
+
key,
|
|
162
|
+
key_source: keySource,
|
|
137
163
|
language: "typescript",
|
|
138
164
|
is_runnable: component.isRunnable,
|
|
139
165
|
is_eval: component.isEval,
|
|
140
|
-
|
|
166
|
+
execution_mode: executionMode,
|
|
141
167
|
file_path: opts.filePath,
|
|
142
168
|
symbol_name: opts.symbolName,
|
|
143
169
|
};
|
|
@@ -173,7 +199,7 @@ export function toManifest(component, opts = {}) {
|
|
|
173
199
|
instructions: skill.instructions,
|
|
174
200
|
fn_present: skill.fn != null,
|
|
175
201
|
is_async: skill.isAsync,
|
|
176
|
-
|
|
202
|
+
tool_refs: skill.tools.length > 0 ? skill.tools.map(resolveComponentRef) : undefined,
|
|
177
203
|
output_schema: skill.outputSchema,
|
|
178
204
|
source_code: componentSource || skill.fn?.toString(),
|
|
179
205
|
source_language: "typescript",
|
|
@@ -186,9 +212,10 @@ export function toManifest(component, opts = {}) {
|
|
|
186
212
|
...base,
|
|
187
213
|
instructions: agent.instructions,
|
|
188
214
|
model: agent.model,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
215
|
+
temperature: agent.temperature,
|
|
216
|
+
tool_refs: agent.tools.length > 0 ? agent.tools.map(resolveComponentRef) : undefined,
|
|
217
|
+
skill_refs: agent.skills.length > 0 ? agent.skills.map(resolveComponentRef) : undefined,
|
|
218
|
+
agent_refs: agent.agents.length > 0 ? agent.agents.map(resolveComponentRef) : undefined,
|
|
192
219
|
output_schema: agent.outputSchema,
|
|
193
220
|
};
|
|
194
221
|
}
|
|
@@ -198,6 +225,7 @@ export function toManifest(component, opts = {}) {
|
|
|
198
225
|
...base,
|
|
199
226
|
instructions: llmProcessor.instructions,
|
|
200
227
|
model: llmProcessor.model,
|
|
228
|
+
temperature: llmProcessor.temperature,
|
|
201
229
|
output_schema: llmProcessor.outputSchema,
|
|
202
230
|
};
|
|
203
231
|
}
|
|
@@ -207,6 +235,7 @@ export function toManifest(component, opts = {}) {
|
|
|
207
235
|
...base,
|
|
208
236
|
instructions: llmEval.instructions,
|
|
209
237
|
model: llmEval.model,
|
|
238
|
+
temperature: llmEval.temperature,
|
|
210
239
|
output_schema: llmEval.outputSchema,
|
|
211
240
|
};
|
|
212
241
|
}
|
|
@@ -216,16 +245,15 @@ export function toManifest(component, opts = {}) {
|
|
|
216
245
|
if (isConditionalLike(s.component)) {
|
|
217
246
|
return {
|
|
218
247
|
name: s.name,
|
|
219
|
-
component: "conditional",
|
|
220
|
-
next: s.next,
|
|
221
248
|
is_conditional: true,
|
|
222
249
|
if_true: s.component.ifTrue,
|
|
223
250
|
if_false: s.component.ifFalse,
|
|
251
|
+
next: s.next,
|
|
224
252
|
};
|
|
225
253
|
}
|
|
226
254
|
return {
|
|
227
255
|
name: s.name,
|
|
228
|
-
|
|
256
|
+
component_ref: resolveComponentRef(s.component),
|
|
229
257
|
next: s.next,
|
|
230
258
|
};
|
|
231
259
|
});
|
|
@@ -235,7 +263,7 @@ export function toManifest(component, opts = {}) {
|
|
|
235
263
|
const checklist = component;
|
|
236
264
|
return {
|
|
237
265
|
...base,
|
|
238
|
-
|
|
266
|
+
eval_refs: checklist.evals.length > 0 ? checklist.evals.map(resolveComponentRef) : undefined,
|
|
239
267
|
weights: checklist.weights,
|
|
240
268
|
};
|
|
241
269
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Mirrors the Python SDK's class-based component model.
|
|
4
4
|
*/
|
|
5
5
|
export type JsonSchemaScalar = {
|
|
6
|
-
type: "string" | "number" | "boolean" | "null";
|
|
6
|
+
type: "string" | "number" | "integer" | "boolean" | "null";
|
|
7
7
|
};
|
|
8
8
|
export type JsonSchemaObject = {
|
|
9
9
|
type: "object";
|
|
@@ -17,8 +17,19 @@ export type JsonSchemaArray = {
|
|
|
17
17
|
};
|
|
18
18
|
export type JsonSchema = JsonSchemaScalar | JsonSchemaObject | JsonSchemaArray | Record<string, unknown>;
|
|
19
19
|
export type ComponentType = "tool" | "code_eval" | "skill" | "agent" | "llm_processor" | "llm_eval" | "orchestration" | "checklist" | "eval_tree";
|
|
20
|
+
export interface ComponentRef {
|
|
21
|
+
key: string;
|
|
22
|
+
component_type: string;
|
|
23
|
+
name: string;
|
|
24
|
+
language: string;
|
|
25
|
+
execution_mode: string;
|
|
26
|
+
}
|
|
20
27
|
export declare const RUNNABLE_TYPES: Set<ComponentType>;
|
|
21
28
|
export declare const EVAL_TYPES: Set<ComponentType>;
|
|
29
|
+
/** Slugify a component name into a key-safe string (implicit key derivation). */
|
|
30
|
+
export declare function slugifyKey(name: string): string;
|
|
31
|
+
/** Throw if `key` does not meet the component key format requirements. */
|
|
32
|
+
export declare function validateKey(key: string, componentName: string): void;
|
|
22
33
|
export interface ToolCall {
|
|
23
34
|
name: string;
|
|
24
35
|
input: Record<string, unknown>;
|
|
@@ -40,6 +51,8 @@ export interface RunnerCallOptions {
|
|
|
40
51
|
tools?: Tool[];
|
|
41
52
|
outputSchema?: JsonSchema;
|
|
42
53
|
jsonRepair?: boolean;
|
|
54
|
+
temperature?: number;
|
|
55
|
+
topK?: number;
|
|
43
56
|
}
|
|
44
57
|
export interface RunnerOptions {
|
|
45
58
|
client: unknown;
|
|
@@ -65,9 +78,9 @@ export declare abstract class BaseComponent {
|
|
|
65
78
|
abstract readonly componentType: ComponentType;
|
|
66
79
|
abstract readonly name: string;
|
|
67
80
|
abstract readonly description: string;
|
|
81
|
+
abstract readonly key: string;
|
|
68
82
|
get isRunnable(): boolean;
|
|
69
83
|
get isEval(): boolean;
|
|
70
|
-
abstract versionHash(): string;
|
|
71
84
|
}
|
|
72
85
|
export interface ToolOptions {
|
|
73
86
|
name: string;
|
|
@@ -75,6 +88,7 @@ export interface ToolOptions {
|
|
|
75
88
|
fn: (...args: unknown[]) => unknown;
|
|
76
89
|
inputSchema: JsonSchema;
|
|
77
90
|
outputSchema?: JsonSchema;
|
|
91
|
+
key: string;
|
|
78
92
|
}
|
|
79
93
|
export declare class Tool extends BaseComponent {
|
|
80
94
|
readonly componentType: "tool";
|
|
@@ -84,14 +98,15 @@ export declare class Tool extends BaseComponent {
|
|
|
84
98
|
readonly inputSchema: JsonSchema;
|
|
85
99
|
readonly outputSchema?: JsonSchema;
|
|
86
100
|
readonly isAsync: boolean;
|
|
101
|
+
readonly key: string;
|
|
87
102
|
constructor(opts: ToolOptions);
|
|
88
|
-
versionHash(): string;
|
|
89
103
|
}
|
|
90
104
|
export interface CodeEvalOptions {
|
|
91
105
|
name: string;
|
|
92
106
|
description: string;
|
|
93
107
|
fn: (...args: unknown[]) => unknown;
|
|
94
108
|
modelResponseFormat?: "JSON" | "TEXT" | "YAML";
|
|
109
|
+
key: string;
|
|
95
110
|
}
|
|
96
111
|
export declare class CodeEval extends BaseComponent {
|
|
97
112
|
readonly componentType: "code_eval";
|
|
@@ -100,8 +115,8 @@ export declare class CodeEval extends BaseComponent {
|
|
|
100
115
|
readonly fn: (...args: unknown[]) => unknown;
|
|
101
116
|
readonly isAsync: boolean;
|
|
102
117
|
readonly modelResponseFormat: "JSON" | "TEXT" | "YAML";
|
|
118
|
+
readonly key: string;
|
|
103
119
|
constructor(opts: CodeEvalOptions);
|
|
104
|
-
versionHash(): string;
|
|
105
120
|
}
|
|
106
121
|
export interface SkillOptions {
|
|
107
122
|
name: string;
|
|
@@ -110,6 +125,7 @@ export interface SkillOptions {
|
|
|
110
125
|
tools?: Tool[];
|
|
111
126
|
fn?: (...args: unknown[]) => unknown;
|
|
112
127
|
outputSchema?: JsonSchema;
|
|
128
|
+
key: string;
|
|
113
129
|
}
|
|
114
130
|
export declare class Skill extends BaseComponent {
|
|
115
131
|
readonly componentType: "skill";
|
|
@@ -120,8 +136,8 @@ export declare class Skill extends BaseComponent {
|
|
|
120
136
|
readonly fn?: (...args: unknown[]) => unknown;
|
|
121
137
|
readonly outputSchema?: JsonSchema;
|
|
122
138
|
readonly isAsync: boolean;
|
|
139
|
+
readonly key: string;
|
|
123
140
|
constructor(opts: SkillOptions);
|
|
124
|
-
versionHash(): string;
|
|
125
141
|
}
|
|
126
142
|
export interface AgentOptions {
|
|
127
143
|
name: string;
|
|
@@ -134,6 +150,9 @@ export interface AgentOptions {
|
|
|
134
150
|
agents?: Agent[];
|
|
135
151
|
outputSchema?: JsonSchema;
|
|
136
152
|
jsonRepair?: boolean;
|
|
153
|
+
temperature?: number;
|
|
154
|
+
topK?: number;
|
|
155
|
+
key: string;
|
|
137
156
|
}
|
|
138
157
|
export declare class Agent extends BaseComponent {
|
|
139
158
|
readonly componentType: "agent";
|
|
@@ -147,8 +166,10 @@ export declare class Agent extends BaseComponent {
|
|
|
147
166
|
readonly agents: Agent[];
|
|
148
167
|
readonly outputSchema?: JsonSchema;
|
|
149
168
|
readonly jsonRepair: boolean;
|
|
169
|
+
readonly temperature?: number;
|
|
170
|
+
readonly topK?: number;
|
|
171
|
+
readonly key: string;
|
|
150
172
|
constructor(opts: AgentOptions);
|
|
151
|
-
versionHash(): string;
|
|
152
173
|
}
|
|
153
174
|
export interface LLMProcessorOptions {
|
|
154
175
|
name: string;
|
|
@@ -158,6 +179,9 @@ export interface LLMProcessorOptions {
|
|
|
158
179
|
runner?: Runner;
|
|
159
180
|
outputSchema?: JsonSchema;
|
|
160
181
|
jsonRepair?: boolean;
|
|
182
|
+
temperature?: number;
|
|
183
|
+
topK?: number;
|
|
184
|
+
key: string;
|
|
161
185
|
}
|
|
162
186
|
export declare class LLMProcessor extends BaseComponent {
|
|
163
187
|
readonly componentType: "llm_processor";
|
|
@@ -168,8 +192,10 @@ export declare class LLMProcessor extends BaseComponent {
|
|
|
168
192
|
readonly runner?: Runner;
|
|
169
193
|
readonly outputSchema?: JsonSchema;
|
|
170
194
|
readonly jsonRepair: boolean;
|
|
195
|
+
readonly temperature?: number;
|
|
196
|
+
readonly topK?: number;
|
|
197
|
+
readonly key: string;
|
|
171
198
|
constructor(opts: LLMProcessorOptions);
|
|
172
|
-
versionHash(): string;
|
|
173
199
|
}
|
|
174
200
|
export interface LLMEvalOptions {
|
|
175
201
|
name: string;
|
|
@@ -179,6 +205,9 @@ export interface LLMEvalOptions {
|
|
|
179
205
|
runner?: Runner;
|
|
180
206
|
outputSchema?: JsonSchema;
|
|
181
207
|
jsonRepair?: boolean;
|
|
208
|
+
temperature?: number;
|
|
209
|
+
topK?: number;
|
|
210
|
+
key: string;
|
|
182
211
|
}
|
|
183
212
|
export declare class LLMEval extends BaseComponent {
|
|
184
213
|
readonly componentType: "llm_eval";
|
|
@@ -189,8 +218,10 @@ export declare class LLMEval extends BaseComponent {
|
|
|
189
218
|
readonly runner?: Runner;
|
|
190
219
|
readonly outputSchema?: JsonSchema;
|
|
191
220
|
readonly jsonRepair: boolean;
|
|
221
|
+
readonly temperature?: number;
|
|
222
|
+
readonly topK?: number;
|
|
223
|
+
readonly key: string;
|
|
192
224
|
constructor(opts: LLMEvalOptions);
|
|
193
|
-
versionHash(): string;
|
|
194
225
|
}
|
|
195
226
|
export interface ConditionalOptions {
|
|
196
227
|
condition: (ctx: Record<string, unknown>) => boolean;
|
|
@@ -218,14 +249,15 @@ export interface OrchestrationOptions {
|
|
|
218
249
|
name: string;
|
|
219
250
|
description: string;
|
|
220
251
|
steps: Step[];
|
|
252
|
+
key: string;
|
|
221
253
|
}
|
|
222
254
|
export declare class Orchestration extends BaseComponent {
|
|
223
255
|
readonly componentType: "orchestration";
|
|
224
256
|
readonly name: string;
|
|
225
257
|
readonly description: string;
|
|
226
258
|
readonly steps: Step[];
|
|
259
|
+
readonly key: string;
|
|
227
260
|
constructor(opts: OrchestrationOptions);
|
|
228
|
-
versionHash(): string;
|
|
229
261
|
}
|
|
230
262
|
export declare class Leaf {
|
|
231
263
|
readonly eval: BaseComponent;
|
|
@@ -258,6 +290,7 @@ export interface ChecklistOptions {
|
|
|
258
290
|
description: string;
|
|
259
291
|
evals: BaseComponent[];
|
|
260
292
|
weights?: number[];
|
|
293
|
+
key: string;
|
|
261
294
|
}
|
|
262
295
|
export declare class Checklist extends BaseComponent {
|
|
263
296
|
readonly componentType: "checklist";
|
|
@@ -265,19 +298,20 @@ export declare class Checklist extends BaseComponent {
|
|
|
265
298
|
readonly description: string;
|
|
266
299
|
readonly evals: BaseComponent[];
|
|
267
300
|
readonly weights?: number[];
|
|
301
|
+
readonly key: string;
|
|
268
302
|
constructor(opts: ChecklistOptions);
|
|
269
|
-
versionHash(): string;
|
|
270
303
|
}
|
|
271
304
|
export interface EvalTreeOptions {
|
|
272
305
|
name: string;
|
|
273
306
|
description: string;
|
|
274
307
|
root: Branch;
|
|
308
|
+
key: string;
|
|
275
309
|
}
|
|
276
310
|
export declare class EvalTree extends BaseComponent {
|
|
277
311
|
readonly componentType: "eval_tree";
|
|
278
312
|
readonly name: string;
|
|
279
313
|
readonly description: string;
|
|
280
314
|
readonly root: Branch;
|
|
315
|
+
readonly key: string;
|
|
281
316
|
constructor(opts: EvalTreeOptions);
|
|
282
|
-
versionHash(): string;
|
|
283
317
|
}
|
package/dist/types.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Core types for the bench TypeScript SDK.
|
|
3
3
|
* Mirrors the Python SDK's class-based component model.
|
|
4
4
|
*/
|
|
5
|
-
import { createHash } from "crypto";
|
|
6
5
|
import { parseJsonResponse } from "./json.js";
|
|
7
6
|
import { isAnthropicClient, isGeminiClient, isOpenAIClient, wrap } from "./wrap.js";
|
|
8
7
|
export const RUNNABLE_TYPES = new Set([
|
|
@@ -18,30 +17,29 @@ export const EVAL_TYPES = new Set([
|
|
|
18
17
|
"eval_tree",
|
|
19
18
|
]);
|
|
20
19
|
// ---------------------------------------------------------------------------
|
|
21
|
-
//
|
|
20
|
+
// Key validation
|
|
22
21
|
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
const KEY_PATTERN = /^[a-z0-9-]+$/;
|
|
23
|
+
const KEY_MAX_LEN = 64;
|
|
24
|
+
/** Slugify a component name into a key-safe string (implicit key derivation). */
|
|
25
|
+
export function slugifyKey(name) {
|
|
26
|
+
let slug = name.toLowerCase().trim();
|
|
27
|
+
slug = slug.replace(/[^\w\s-]/g, "");
|
|
28
|
+
slug = slug.replace(/[\s_]+/g, "-");
|
|
29
|
+
slug = slug.replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
30
|
+
return slug.slice(0, KEY_MAX_LEN);
|
|
29
31
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
/** Throw if `key` does not meet the component key format requirements. */
|
|
33
|
+
export function validateKey(key, componentName) {
|
|
34
|
+
if (!key) {
|
|
35
|
+
throw new Error(`Component '${componentName}': key must not be empty`);
|
|
33
36
|
}
|
|
34
|
-
if (
|
|
35
|
-
|
|
37
|
+
if (!KEY_PATTERN.test(key)) {
|
|
38
|
+
throw new Error(`Component '${componentName}': key '${key}' must contain only lowercase letters, digits, and hyphens ([a-z0-9-])`);
|
|
39
|
+
}
|
|
40
|
+
if (key.length > KEY_MAX_LEN) {
|
|
41
|
+
throw new Error(`Component '${componentName}': key '${key}' is too long (max ${KEY_MAX_LEN} chars, got ${key.length})`);
|
|
36
42
|
}
|
|
37
|
-
const keys = Object.keys(value).sort();
|
|
38
|
-
const parts = keys.map((k) => `${JSON.stringify(k)}:${sortedStringify(value[k])}`);
|
|
39
|
-
return "{" + parts.join(",") + "}";
|
|
40
|
-
}
|
|
41
|
-
function normalizeSchema(schema) {
|
|
42
|
-
if (schema == null)
|
|
43
|
-
return "";
|
|
44
|
-
return sortedStringify(schema);
|
|
45
43
|
}
|
|
46
44
|
function isPlainRecord(value) {
|
|
47
45
|
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
@@ -84,11 +82,6 @@ function previewText(text, limit = 160) {
|
|
|
84
82
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
85
83
|
return normalized.length <= limit ? normalized : `${normalized.slice(0, limit)}...`;
|
|
86
84
|
}
|
|
87
|
-
function fnSource(fn) {
|
|
88
|
-
if (fn == null)
|
|
89
|
-
return "";
|
|
90
|
-
return fn.toString();
|
|
91
|
-
}
|
|
92
85
|
function contentPartToText(part) {
|
|
93
86
|
if (typeof part === "string") {
|
|
94
87
|
return part;
|
|
@@ -289,6 +282,8 @@ export class Runner {
|
|
|
289
282
|
description: tool.description,
|
|
290
283
|
input_schema: withClosedAdditionalProperties(tool.inputSchema),
|
|
291
284
|
})),
|
|
285
|
+
...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}),
|
|
286
|
+
...(opts.topK !== undefined ? { top_k: opts.topK } : {}),
|
|
292
287
|
});
|
|
293
288
|
const content = Array.isArray(response.content)
|
|
294
289
|
? response.content
|
|
@@ -335,6 +330,7 @@ export class Runner {
|
|
|
335
330
|
parameters: withClosedAdditionalProperties(tool.inputSchema),
|
|
336
331
|
},
|
|
337
332
|
})),
|
|
333
|
+
...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}),
|
|
338
334
|
});
|
|
339
335
|
const choice = Array.isArray(response.choices)
|
|
340
336
|
? response.choices[0]
|
|
@@ -385,6 +381,8 @@ export class Runner {
|
|
|
385
381
|
parameters: toGeminiSchema(tool.inputSchema),
|
|
386
382
|
}],
|
|
387
383
|
})),
|
|
384
|
+
...(opts.temperature !== undefined ? { temperature: opts.temperature } : {}),
|
|
385
|
+
...(opts.topK !== undefined ? { topK: opts.topK } : {}),
|
|
388
386
|
},
|
|
389
387
|
});
|
|
390
388
|
const candidates = Array.isArray(response.candidates)
|
|
@@ -444,6 +442,7 @@ export class Tool extends BaseComponent {
|
|
|
444
442
|
inputSchema;
|
|
445
443
|
outputSchema;
|
|
446
444
|
isAsync;
|
|
445
|
+
key;
|
|
447
446
|
constructor(opts) {
|
|
448
447
|
super();
|
|
449
448
|
this.name = opts.name;
|
|
@@ -452,9 +451,8 @@ export class Tool extends BaseComponent {
|
|
|
452
451
|
this.inputSchema = validateToolInputSchema(opts.inputSchema);
|
|
453
452
|
this.outputSchema = opts.outputSchema;
|
|
454
453
|
this.isAsync = opts.fn.constructor.name === "AsyncFunction";
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
return hashFields(this.componentType, fnSource(this.fn), normalizeSchema(this.inputSchema), normalizeSchema(this.outputSchema));
|
|
454
|
+
validateKey(opts.key, opts.name);
|
|
455
|
+
this.key = opts.key;
|
|
458
456
|
}
|
|
459
457
|
}
|
|
460
458
|
export class CodeEval extends BaseComponent {
|
|
@@ -464,6 +462,7 @@ export class CodeEval extends BaseComponent {
|
|
|
464
462
|
fn;
|
|
465
463
|
isAsync;
|
|
466
464
|
modelResponseFormat;
|
|
465
|
+
key;
|
|
467
466
|
constructor(opts) {
|
|
468
467
|
super();
|
|
469
468
|
this.name = opts.name;
|
|
@@ -471,9 +470,8 @@ export class CodeEval extends BaseComponent {
|
|
|
471
470
|
this.fn = opts.fn;
|
|
472
471
|
this.isAsync = opts.fn.constructor.name === "AsyncFunction";
|
|
473
472
|
this.modelResponseFormat = opts.modelResponseFormat ?? "JSON";
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
return hashFields(this.componentType, fnSource(this.fn), this.modelResponseFormat);
|
|
473
|
+
validateKey(opts.key, opts.name);
|
|
474
|
+
this.key = opts.key;
|
|
477
475
|
}
|
|
478
476
|
}
|
|
479
477
|
export class Skill extends BaseComponent {
|
|
@@ -485,6 +483,7 @@ export class Skill extends BaseComponent {
|
|
|
485
483
|
fn;
|
|
486
484
|
outputSchema;
|
|
487
485
|
isAsync;
|
|
486
|
+
key;
|
|
488
487
|
constructor(opts) {
|
|
489
488
|
super();
|
|
490
489
|
this.name = opts.name;
|
|
@@ -494,10 +493,8 @@ export class Skill extends BaseComponent {
|
|
|
494
493
|
this.fn = opts.fn;
|
|
495
494
|
this.outputSchema = opts.outputSchema;
|
|
496
495
|
this.isAsync = opts.fn?.constructor.name === "AsyncFunction";
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
const toolRefs = [...this.tools.map((t) => t.name)].sort().join(",");
|
|
500
|
-
return hashFields(this.componentType, this.instructions, toolRefs, fnSource(this.fn));
|
|
496
|
+
validateKey(opts.key, opts.name);
|
|
497
|
+
this.key = opts.key;
|
|
501
498
|
}
|
|
502
499
|
}
|
|
503
500
|
export class Agent extends BaseComponent {
|
|
@@ -512,6 +509,9 @@ export class Agent extends BaseComponent {
|
|
|
512
509
|
agents;
|
|
513
510
|
outputSchema;
|
|
514
511
|
jsonRepair;
|
|
512
|
+
temperature;
|
|
513
|
+
topK;
|
|
514
|
+
key;
|
|
515
515
|
constructor(opts) {
|
|
516
516
|
super();
|
|
517
517
|
this.name = opts.name;
|
|
@@ -524,12 +524,10 @@ export class Agent extends BaseComponent {
|
|
|
524
524
|
this.agents = opts.agents ?? [];
|
|
525
525
|
this.outputSchema = opts.outputSchema;
|
|
526
526
|
this.jsonRepair = opts.jsonRepair ?? false;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
const agentRefs = [...this.agents.map((a) => a.name)].sort().join(",");
|
|
532
|
-
return hashFields(this.componentType, this.instructions, this.model, toolRefs, skillRefs, agentRefs, normalizeSchema(this.outputSchema));
|
|
527
|
+
this.temperature = opts.temperature;
|
|
528
|
+
this.topK = opts.topK;
|
|
529
|
+
validateKey(opts.key, opts.name);
|
|
530
|
+
this.key = opts.key;
|
|
533
531
|
}
|
|
534
532
|
}
|
|
535
533
|
export class LLMProcessor extends BaseComponent {
|
|
@@ -541,6 +539,9 @@ export class LLMProcessor extends BaseComponent {
|
|
|
541
539
|
runner;
|
|
542
540
|
outputSchema;
|
|
543
541
|
jsonRepair;
|
|
542
|
+
temperature;
|
|
543
|
+
topK;
|
|
544
|
+
key;
|
|
544
545
|
constructor(opts) {
|
|
545
546
|
super();
|
|
546
547
|
this.name = opts.name;
|
|
@@ -550,9 +551,10 @@ export class LLMProcessor extends BaseComponent {
|
|
|
550
551
|
this.runner = opts.runner;
|
|
551
552
|
this.outputSchema = opts.outputSchema;
|
|
552
553
|
this.jsonRepair = opts.jsonRepair ?? false;
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
554
|
+
this.temperature = opts.temperature;
|
|
555
|
+
this.topK = opts.topK;
|
|
556
|
+
validateKey(opts.key, opts.name);
|
|
557
|
+
this.key = opts.key;
|
|
556
558
|
}
|
|
557
559
|
}
|
|
558
560
|
export class LLMEval extends BaseComponent {
|
|
@@ -564,6 +566,9 @@ export class LLMEval extends BaseComponent {
|
|
|
564
566
|
runner;
|
|
565
567
|
outputSchema;
|
|
566
568
|
jsonRepair;
|
|
569
|
+
temperature;
|
|
570
|
+
topK;
|
|
571
|
+
key;
|
|
567
572
|
constructor(opts) {
|
|
568
573
|
super();
|
|
569
574
|
this.name = opts.name;
|
|
@@ -573,9 +578,10 @@ export class LLMEval extends BaseComponent {
|
|
|
573
578
|
this.runner = opts.runner;
|
|
574
579
|
this.outputSchema = opts.outputSchema;
|
|
575
580
|
this.jsonRepair = opts.jsonRepair ?? false;
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
581
|
+
this.temperature = opts.temperature;
|
|
582
|
+
this.topK = opts.topK;
|
|
583
|
+
validateKey(opts.key, opts.name);
|
|
584
|
+
this.key = opts.key;
|
|
579
585
|
}
|
|
580
586
|
}
|
|
581
587
|
export class Conditional {
|
|
@@ -603,18 +609,14 @@ export class Orchestration extends BaseComponent {
|
|
|
603
609
|
name;
|
|
604
610
|
description;
|
|
605
611
|
steps;
|
|
612
|
+
key;
|
|
606
613
|
constructor(opts) {
|
|
607
614
|
super();
|
|
608
615
|
this.name = opts.name;
|
|
609
616
|
this.description = opts.description;
|
|
610
617
|
this.steps = opts.steps;
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const stepParts = this.steps.map((s) => {
|
|
614
|
-
const compRef = s.component instanceof Conditional ? "conditional" : s.component.name;
|
|
615
|
-
return `${s.name}:${compRef}:${s.next.join(",")}`;
|
|
616
|
-
});
|
|
617
|
-
return hashFields(this.componentType, stepParts.join("|"));
|
|
618
|
+
validateKey(opts.key, opts.name);
|
|
619
|
+
this.key = opts.key;
|
|
618
620
|
}
|
|
619
621
|
}
|
|
620
622
|
// ---------------------------------------------------------------------------
|
|
@@ -652,46 +654,29 @@ export class Checklist extends BaseComponent {
|
|
|
652
654
|
description;
|
|
653
655
|
evals;
|
|
654
656
|
weights;
|
|
657
|
+
key;
|
|
655
658
|
constructor(opts) {
|
|
656
659
|
super();
|
|
657
660
|
this.name = opts.name;
|
|
658
661
|
this.description = opts.description;
|
|
659
662
|
this.evals = opts.evals;
|
|
660
663
|
this.weights = opts.weights;
|
|
664
|
+
validateKey(opts.key, opts.name);
|
|
665
|
+
this.key = opts.key;
|
|
661
666
|
}
|
|
662
|
-
versionHash() {
|
|
663
|
-
const evalRefs = this.evals.map((e) => e.name).join(",");
|
|
664
|
-
const w = this.weights ? this.weights.join(",") : "";
|
|
665
|
-
return hashFields(this.componentType, evalRefs, w);
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
// ---------------------------------------------------------------------------
|
|
669
|
-
// EvalTree
|
|
670
|
-
// ---------------------------------------------------------------------------
|
|
671
|
-
function treeHashParts(node) {
|
|
672
|
-
if (node instanceof Leaf) {
|
|
673
|
-
return `leaf:${node.eval.name}`;
|
|
674
|
-
}
|
|
675
|
-
if (node instanceof Edge) {
|
|
676
|
-
return `edge:${node.weight}:${treeHashParts(node.node)}`;
|
|
677
|
-
}
|
|
678
|
-
// Branch
|
|
679
|
-
const passParts = node.ifPass.map(treeHashParts).join("|");
|
|
680
|
-
const failParts = node.ifFail.map(treeHashParts).join("|");
|
|
681
|
-
return `branch:${node.eval.name}:${node.threshold}:[${passParts}]:[${failParts}]`;
|
|
682
667
|
}
|
|
683
668
|
export class EvalTree extends BaseComponent {
|
|
684
669
|
componentType = "eval_tree";
|
|
685
670
|
name;
|
|
686
671
|
description;
|
|
687
672
|
root;
|
|
673
|
+
key;
|
|
688
674
|
constructor(opts) {
|
|
689
675
|
super();
|
|
690
676
|
this.name = opts.name;
|
|
691
677
|
this.description = opts.description;
|
|
692
678
|
this.root = opts.root;
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
return hashFields(this.componentType, treeHashParts(this.root));
|
|
679
|
+
validateKey(opts.key, opts.name);
|
|
680
|
+
this.key = opts.key;
|
|
696
681
|
}
|
|
697
682
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhanla/sdk-ts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "TypeScript SDK for the zhanla CLI — define and run AI components locally",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -21,7 +21,6 @@
|
|
|
21
21
|
"dist",
|
|
22
22
|
"bin"
|
|
23
23
|
],
|
|
24
|
-
|
|
25
24
|
"devDependencies": {
|
|
26
25
|
"typescript": "^5.4.0",
|
|
27
26
|
"vitest": "^1.4.0",
|