@slashfi/agents-sdk 0.67.2 → 0.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adk-tools.d.ts.map +1 -1
- package/dist/adk-tools.js +3 -0
- package/dist/adk-tools.js.map +1 -1
- package/dist/adk.js +24 -1
- package/dist/adk.js.map +1 -1
- package/dist/cjs/adk-tools.js +3 -0
- package/dist/cjs/adk-tools.js.map +1 -1
- package/dist/cjs/config-store.js +111 -14
- package/dist/cjs/config-store.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/materialize.js +208 -17
- package/dist/cjs/materialize.js.map +1 -1
- package/dist/cjs/types.js.map +1 -1
- package/dist/config-store.d.ts +24 -1
- package/dist/config-store.d.ts.map +1 -1
- package/dist/config-store.js +111 -14
- package/dist/config-store.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/materialize.d.ts +28 -5
- package/dist/materialize.d.ts.map +1 -1
- package/dist/materialize.js +207 -17
- package/dist/materialize.js.map +1 -1
- package/dist/types.d.ts +26 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/adk-tools.ts +3 -1
- package/src/adk.ts +23 -1
- package/src/config-store.ts +148 -14
- package/src/index.ts +1 -0
- package/src/materialize.ts +242 -32
- package/src/types.ts +24 -6
package/src/materialize.ts
CHANGED
|
@@ -1,16 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Ref Materialization — Download agent docs to local filesystem.
|
|
3
3
|
*
|
|
4
|
-
* When `adk ref add`
|
|
5
|
-
* resources (skills), and generate
|
|
4
|
+
* When `adk ref add` or `adk sync` runs, materialize the agent's tool schemas,
|
|
5
|
+
* resources (skills), and generate readable markdown docs locally.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Output format:
|
|
8
|
+
* refs/<name>/
|
|
9
|
+
* agent.json — metadata (name, description, tool list)
|
|
10
|
+
* entrypoint.md — agent overview with tool summary
|
|
11
|
+
* tools/<tool>.tool.md — per-tool docs with parameter tables
|
|
12
|
+
* tools/<tool>.tool.json — raw JSON schemas
|
|
13
|
+
* types/<name>.d.ts — TypeScript type stubs
|
|
14
|
+
* skills/ — resources from the agent
|
|
15
|
+
*
|
|
16
|
+
* The .tool.md files are the primary output — designed for LLMs to read.
|
|
8
17
|
*/
|
|
9
18
|
|
|
10
19
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
11
20
|
import { dirname, join } from "node:path";
|
|
12
21
|
import type { Adk } from "./config-store.js";
|
|
13
|
-
|
|
22
|
+
import type { JsonSchema } from "./types.js";
|
|
14
23
|
|
|
15
24
|
// ============================================
|
|
16
25
|
// Types
|
|
@@ -19,18 +28,25 @@ import type { Adk } from "./config-store.js";
|
|
|
19
28
|
interface ToolSchema {
|
|
20
29
|
name: string;
|
|
21
30
|
description?: string;
|
|
22
|
-
inputSchema?:
|
|
31
|
+
inputSchema?: JsonSchema;
|
|
23
32
|
outputSchema?: Record<string, unknown>;
|
|
24
33
|
}
|
|
25
34
|
|
|
26
|
-
interface MaterializeResult {
|
|
35
|
+
export interface MaterializeResult {
|
|
27
36
|
toolCount: number;
|
|
28
37
|
skillCount: number;
|
|
29
38
|
typesGenerated: boolean;
|
|
39
|
+
docsGenerated: boolean;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export interface SyncResult {
|
|
43
|
+
refs: Array<{ name: string; result: MaterializeResult; error?: string }>;
|
|
44
|
+
totalTools: number;
|
|
45
|
+
totalSkills: number;
|
|
30
46
|
}
|
|
31
47
|
|
|
32
48
|
// ============================================
|
|
33
|
-
// Helpers
|
|
49
|
+
// File Helpers
|
|
34
50
|
// ============================================
|
|
35
51
|
|
|
36
52
|
function ensureWrite(path: string, content: string): void {
|
|
@@ -41,27 +57,163 @@ function ensureWrite(path: string, content: string): void {
|
|
|
41
57
|
writeFileSync(path, content, "utf-8");
|
|
42
58
|
}
|
|
43
59
|
|
|
60
|
+
function toKebabCase(name: string): string {
|
|
61
|
+
return name
|
|
62
|
+
.replace(/[^a-zA-Z0-9]+/g, "-")
|
|
63
|
+
.replace(/^-|-$/g, "")
|
|
64
|
+
.toLowerCase();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pascalCase(s: string): string {
|
|
68
|
+
return s
|
|
69
|
+
.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase())
|
|
70
|
+
.replace(/^./, (c) => c.toUpperCase());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ============================================
|
|
74
|
+
// JSON Schema → TypeScript type string
|
|
75
|
+
// ============================================
|
|
76
|
+
|
|
77
|
+
function jsonSchemaToTsType(schema: JsonSchema): string {
|
|
78
|
+
if (!schema) return "unknown";
|
|
79
|
+
|
|
80
|
+
const s = schema as any;
|
|
81
|
+
|
|
82
|
+
// const literal
|
|
83
|
+
if (s.const !== undefined) return JSON.stringify(s.const);
|
|
84
|
+
|
|
85
|
+
// enum
|
|
86
|
+
if (schema.enum) return schema.enum.map((v) => JSON.stringify(v)).join(" | ");
|
|
87
|
+
|
|
88
|
+
// oneOf / anyOf → union
|
|
89
|
+
if (s.oneOf) return (s.oneOf as JsonSchema[]).map(jsonSchemaToTsType).join(" | ");
|
|
90
|
+
if (s.anyOf) return (s.anyOf as JsonSchema[]).map(jsonSchemaToTsType).join(" | ");
|
|
91
|
+
|
|
92
|
+
// allOf → intersection
|
|
93
|
+
if (s.allOf) return (s.allOf as JsonSchema[]).map(jsonSchemaToTsType).join(" & ");
|
|
94
|
+
|
|
95
|
+
// $ref
|
|
96
|
+
if (s.$ref) {
|
|
97
|
+
const match = (s.$ref as string).match(/\/([^/]+)$/);
|
|
98
|
+
return match ? match[1] : "unknown";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
switch (schema.type) {
|
|
102
|
+
case "string":
|
|
103
|
+
return s.format ? `string /* ${s.format} */` : "string";
|
|
104
|
+
case "integer":
|
|
105
|
+
return "number /* integer */";
|
|
106
|
+
case "number":
|
|
107
|
+
return "number";
|
|
108
|
+
case "boolean":
|
|
109
|
+
return "boolean";
|
|
110
|
+
case "null":
|
|
111
|
+
return "null";
|
|
112
|
+
case "array":
|
|
113
|
+
return schema.items ? `${jsonSchemaToTsType(schema.items as JsonSchema)}[]` : "unknown[]";
|
|
114
|
+
case "object": {
|
|
115
|
+
if (schema.properties) {
|
|
116
|
+
const required = new Set((schema.required as string[]) ?? []);
|
|
117
|
+
const props = Object.entries(schema.properties)
|
|
118
|
+
.map(([k, v]) => `${k}${required.has(k) ? "" : "?"}: ${jsonSchemaToTsType(v as JsonSchema)}`)
|
|
119
|
+
.join("; ");
|
|
120
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
121
|
+
const addlType = jsonSchemaToTsType(schema.additionalProperties as JsonSchema);
|
|
122
|
+
return props ? `{ ${props}; [key: string]: ${addlType} }` : `Record<string, ${addlType}>`;
|
|
123
|
+
}
|
|
124
|
+
return `{ ${props} }`;
|
|
125
|
+
}
|
|
126
|
+
if (schema.additionalProperties && typeof schema.additionalProperties === "object") {
|
|
127
|
+
return `Record<string, ${jsonSchemaToTsType(schema.additionalProperties as JsonSchema)}>`;
|
|
128
|
+
}
|
|
129
|
+
return "Record<string, unknown>";
|
|
130
|
+
}
|
|
131
|
+
default:
|
|
132
|
+
if (Array.isArray(schema.type)) {
|
|
133
|
+
return (schema.type as string[]).map((t) => (t === "null" ? "null" : t === "integer" ? "number" : t)).join(" | ");
|
|
134
|
+
}
|
|
135
|
+
return "unknown";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ============================================
|
|
140
|
+
// Markdown Generation
|
|
141
|
+
// ============================================
|
|
142
|
+
|
|
143
|
+
/** Generate a .tool.md file — readable tool docs with parameter tables. */
|
|
144
|
+
function generateToolMd(tool: ToolSchema): string {
|
|
145
|
+
const schema = tool.inputSchema ?? ({ type: "object", properties: {} } as JsonSchema);
|
|
146
|
+
const lines: string[] = [];
|
|
147
|
+
|
|
148
|
+
lines.push(`# ${tool.name}`);
|
|
149
|
+
lines.push("");
|
|
150
|
+
if (tool.description) {
|
|
151
|
+
lines.push(tool.description);
|
|
152
|
+
lines.push("");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const props = (schema.properties ?? {}) as Record<string, JsonSchema>;
|
|
156
|
+
const required = new Set((schema.required as string[]) ?? []);
|
|
157
|
+
const paramNames = Object.keys(props);
|
|
158
|
+
|
|
159
|
+
if (paramNames.length > 0) {
|
|
160
|
+
lines.push("## Parameters");
|
|
161
|
+
lines.push("");
|
|
162
|
+
lines.push("| Name | Type | Required | Description |");
|
|
163
|
+
lines.push("|------|------|----------|-------------|");
|
|
164
|
+
for (const name of paramNames) {
|
|
165
|
+
const prop = props[name];
|
|
166
|
+
const type = jsonSchemaToTsType(prop);
|
|
167
|
+
const req = required.has(name) ? "✓" : "";
|
|
168
|
+
const desc = (prop.description ?? "").replace(/\|/g, "\\|");
|
|
169
|
+
lines.push(`| ${name} | \`${type}\` | ${req} | ${desc} |`);
|
|
170
|
+
}
|
|
171
|
+
lines.push("");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return lines.join("\n");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** Generate entrypoint.md — agent overview with tool listing. */
|
|
178
|
+
function generateEntrypoint(refName: string, description: string | undefined, tools: ToolSchema[]): string {
|
|
179
|
+
const lines: string[] = [];
|
|
180
|
+
lines.push(`# ${refName}`);
|
|
181
|
+
lines.push("");
|
|
182
|
+
if (description) {
|
|
183
|
+
lines.push(description);
|
|
184
|
+
lines.push("");
|
|
185
|
+
}
|
|
186
|
+
lines.push(`## Available Tools (${tools.length})`);
|
|
187
|
+
lines.push("");
|
|
188
|
+
for (const tool of tools) {
|
|
189
|
+
lines.push(`- **${tool.name}**: ${tool.description ?? "No description"}`);
|
|
190
|
+
}
|
|
191
|
+
lines.push("");
|
|
192
|
+
lines.push(`> Auto-generated by \`adk sync\` at ${new Date().toISOString()}`);
|
|
193
|
+
lines.push("");
|
|
194
|
+
return lines.join("\n");
|
|
195
|
+
}
|
|
196
|
+
|
|
44
197
|
/** Generate a .d.ts file from tool schemas. */
|
|
45
198
|
function generateTypes(refName: string, tools: ToolSchema[]): string {
|
|
46
199
|
const lines: string[] = [
|
|
47
|
-
`// Auto-generated by adk
|
|
200
|
+
`// Auto-generated by adk sync`,
|
|
48
201
|
`// Agent: ${refName}`,
|
|
49
202
|
`// Tools: ${tools.length}`,
|
|
50
203
|
``,
|
|
51
204
|
`export interface ${pascalCase(refName)}Tools {`,
|
|
52
205
|
];
|
|
53
|
-
|
|
54
206
|
for (const tool of tools) {
|
|
207
|
+
const paramsType = tool.inputSchema
|
|
208
|
+
? jsonSchemaToTsType(tool.inputSchema)
|
|
209
|
+
: "Record<string, unknown>";
|
|
55
210
|
lines.push(` /** ${tool.description ?? tool.name} */`);
|
|
56
211
|
lines.push(` ${JSON.stringify(tool.name)}: {`);
|
|
57
212
|
lines.push(` name: ${JSON.stringify(tool.name)};`);
|
|
58
|
-
if (tool.description) {
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
lines.push(` params: Record<string, unknown>;`);
|
|
213
|
+
if (tool.description) lines.push(` description: ${JSON.stringify(tool.description)};`);
|
|
214
|
+
lines.push(` params: ${paramsType};`);
|
|
62
215
|
lines.push(` };`);
|
|
63
216
|
}
|
|
64
|
-
|
|
65
217
|
lines.push(`}`);
|
|
66
218
|
lines.push(``);
|
|
67
219
|
lines.push(`export declare const tools: (keyof ${pascalCase(refName)}Tools)[];`);
|
|
@@ -69,14 +221,8 @@ function generateTypes(refName: string, tools: ToolSchema[]): string {
|
|
|
69
221
|
return lines.join("\n");
|
|
70
222
|
}
|
|
71
223
|
|
|
72
|
-
function pascalCase(s: string): string {
|
|
73
|
-
return s
|
|
74
|
-
.replace(/[^a-zA-Z0-9]+(.)/g, (_, c) => c.toUpperCase())
|
|
75
|
-
.replace(/^./, (c) => c.toUpperCase());
|
|
76
|
-
}
|
|
77
|
-
|
|
78
224
|
// ============================================
|
|
79
|
-
// Materialize
|
|
225
|
+
// Materialize a single ref
|
|
80
226
|
// ============================================
|
|
81
227
|
|
|
82
228
|
export async function materializeRef(
|
|
@@ -92,8 +238,9 @@ export async function materializeRef(
|
|
|
92
238
|
let toolCount = 0;
|
|
93
239
|
let skillCount = 0;
|
|
94
240
|
let typesGenerated = false;
|
|
241
|
+
let docsGenerated = false;
|
|
95
242
|
|
|
96
|
-
// 1. Fetch and
|
|
243
|
+
// 1. Fetch tool schemas and generate docs
|
|
97
244
|
try {
|
|
98
245
|
const info = await adk.ref.inspect(refName, { full: true });
|
|
99
246
|
if (info?.tools && info.tools.length > 0) {
|
|
@@ -104,15 +251,18 @@ export async function materializeRef(
|
|
|
104
251
|
outputSchema: t.outputSchema,
|
|
105
252
|
}));
|
|
106
253
|
|
|
254
|
+
// Write .tool.md files (primary output — readable by LLMs)
|
|
107
255
|
for (const tool of tools) {
|
|
108
|
-
const safeName = tool.name
|
|
109
|
-
ensureWrite(
|
|
110
|
-
|
|
111
|
-
JSON.stringify(tool, null, 2),
|
|
112
|
-
);
|
|
256
|
+
const safeName = toKebabCase(tool.name);
|
|
257
|
+
ensureWrite(join(toolsDir, `${safeName}.tool.md`), generateToolMd(tool));
|
|
258
|
+
ensureWrite(join(toolsDir, `${safeName}.tool.json`), JSON.stringify(tool, null, 2));
|
|
113
259
|
}
|
|
114
260
|
toolCount = tools.length;
|
|
115
261
|
|
|
262
|
+
// Write entrypoint.md
|
|
263
|
+
ensureWrite(join(refDir, "entrypoint.md"), generateEntrypoint(refName, info.description, tools));
|
|
264
|
+
docsGenerated = true;
|
|
265
|
+
|
|
116
266
|
// Write agent.json metadata
|
|
117
267
|
ensureWrite(
|
|
118
268
|
join(refDir, "agent.json"),
|
|
@@ -126,10 +276,7 @@ export async function materializeRef(
|
|
|
126
276
|
);
|
|
127
277
|
|
|
128
278
|
// Generate .d.ts
|
|
129
|
-
ensureWrite(
|
|
130
|
-
join(typesDir, `${refName}.d.ts`),
|
|
131
|
-
generateTypes(refName, tools),
|
|
132
|
-
);
|
|
279
|
+
ensureWrite(join(typesDir, `${refName}.d.ts`), generateTypes(refName, tools));
|
|
133
280
|
typesGenerated = true;
|
|
134
281
|
}
|
|
135
282
|
} catch {
|
|
@@ -153,6 +300,69 @@ export async function materializeRef(
|
|
|
153
300
|
// resources fetch failed — might not be supported
|
|
154
301
|
}
|
|
155
302
|
|
|
156
|
-
return { toolCount, skillCount, typesGenerated };
|
|
303
|
+
return { toolCount, skillCount, typesGenerated, docsGenerated };
|
|
157
304
|
}
|
|
158
305
|
|
|
306
|
+
// ============================================
|
|
307
|
+
// Sync all refs from consumer config
|
|
308
|
+
// ============================================
|
|
309
|
+
|
|
310
|
+
const DEFAULT_CONCURRENCY = 3;
|
|
311
|
+
|
|
312
|
+
export async function syncAllRefs(
|
|
313
|
+
adk: Adk,
|
|
314
|
+
configDir: string,
|
|
315
|
+
opts?: { filter?: string; concurrency?: number; onProgress?: (name: string, status: string) => void },
|
|
316
|
+
): Promise<SyncResult> {
|
|
317
|
+
const config = await adk.readConfig();
|
|
318
|
+
const refs = config.refs ?? [];
|
|
319
|
+
|
|
320
|
+
// Resolve ref names and filter
|
|
321
|
+
const names: string[] = [];
|
|
322
|
+
for (const refEntry of refs) {
|
|
323
|
+
const name = typeof refEntry === "string"
|
|
324
|
+
? refEntry
|
|
325
|
+
: (refEntry as any).as ?? (refEntry as any).ref ?? (refEntry as any).name;
|
|
326
|
+
if (!name) continue;
|
|
327
|
+
if (opts?.filter && name !== opts.filter) continue;
|
|
328
|
+
names.push(name);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
const results: SyncResult["refs"] = [];
|
|
332
|
+
let totalTools = 0;
|
|
333
|
+
let totalSkills = 0;
|
|
334
|
+
const concurrency = opts?.concurrency ?? DEFAULT_CONCURRENCY;
|
|
335
|
+
|
|
336
|
+
// Process in batches of `concurrency`
|
|
337
|
+
for (let i = 0; i < names.length; i += concurrency) {
|
|
338
|
+
const batch = names.slice(i, i + concurrency);
|
|
339
|
+
const batchResults = await Promise.allSettled(
|
|
340
|
+
batch.map(async (name) => {
|
|
341
|
+
opts?.onProgress?.(name, "syncing");
|
|
342
|
+
try {
|
|
343
|
+
const result = await materializeRef(adk, name, configDir);
|
|
344
|
+
opts?.onProgress?.(name, `done (${result.toolCount} tools)`);
|
|
345
|
+
return { name, result };
|
|
346
|
+
} catch (err: any) {
|
|
347
|
+
const error = err?.message ?? String(err);
|
|
348
|
+
opts?.onProgress?.(name, `error: ${error}`);
|
|
349
|
+
return {
|
|
350
|
+
name,
|
|
351
|
+
result: { toolCount: 0, skillCount: 0, typesGenerated: false, docsGenerated: false } as MaterializeResult,
|
|
352
|
+
error,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
}),
|
|
356
|
+
);
|
|
357
|
+
|
|
358
|
+
for (const settled of batchResults) {
|
|
359
|
+
if (settled.status === "fulfilled") {
|
|
360
|
+
results.push(settled.value);
|
|
361
|
+
totalTools += settled.value.result.toolCount;
|
|
362
|
+
totalSkills += settled.value.result.skillCount;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return { refs: results, totalTools, totalSkills };
|
|
368
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -204,17 +204,35 @@ export interface OAuth2SecurityScheme {
|
|
|
204
204
|
|
|
205
205
|
/**
|
|
206
206
|
* API key authentication.
|
|
207
|
-
* Used by agents that wrap APIs using
|
|
207
|
+
* Used by agents that wrap APIs using one or more keys
|
|
208
208
|
* (e.g. OpenAI, Anthropic, Stripe, Datadog).
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* // Single key (backwards-compatible)
|
|
212
|
+
* security: { type: 'apiKey', in: 'header', name: 'Authorization', prefix: 'Bearer' }
|
|
213
|
+
*
|
|
214
|
+
* // Multiple keys (e.g. Datadog)
|
|
215
|
+
* security: {
|
|
216
|
+
* type: 'apiKey',
|
|
217
|
+
* headers: {
|
|
218
|
+
* 'DD-API-KEY': { description: 'Your Datadog API key' },
|
|
219
|
+
* 'DD-APPLICATION-KEY': { description: 'Your Datadog application key' },
|
|
220
|
+
* }
|
|
221
|
+
* }
|
|
209
222
|
*/
|
|
210
223
|
export interface ApiKeySecurityScheme {
|
|
211
224
|
type: "apiKey";
|
|
212
|
-
/** Where the key is sent */
|
|
213
|
-
in
|
|
214
|
-
/** Header or query parameter name (e.g. "X-API-Key"
|
|
215
|
-
name
|
|
216
|
-
/** Optional prefix (e.g. "Bearer"
|
|
225
|
+
/** Where the key is sent (single-key mode) */
|
|
226
|
+
in?: "header" | "query";
|
|
227
|
+
/** Header or query parameter name (single-key mode, e.g. "X-API-Key") */
|
|
228
|
+
name?: string;
|
|
229
|
+
/** Optional prefix (single-key mode, e.g. "Bearer") */
|
|
217
230
|
prefix?: string;
|
|
231
|
+
/**
|
|
232
|
+
* Named headers the user must provide values for (multi-key mode).
|
|
233
|
+
* When present, this is the source of truth — `in`/`name`/`prefix` are ignored.
|
|
234
|
+
*/
|
|
235
|
+
headers?: Record<string, { description?: string }>;
|
|
218
236
|
}
|
|
219
237
|
|
|
220
238
|
/**
|