subharness 0.0.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/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/adapters/claude-auth.d.ts +7 -0
- package/dist/adapters/claude-auth.js +87 -0
- package/dist/adapters/claude-auth.js.map +1 -0
- package/dist/adapters/claude-config.d.ts +6 -0
- package/dist/adapters/claude-config.js +37 -0
- package/dist/adapters/claude-config.js.map +1 -0
- package/dist/adapters/claude-input.d.ts +9 -0
- package/dist/adapters/claude-input.js +32 -0
- package/dist/adapters/claude-input.js.map +1 -0
- package/dist/adapters/claude-permissions.d.ts +3 -0
- package/dist/adapters/claude-permissions.js +24 -0
- package/dist/adapters/claude-permissions.js.map +1 -0
- package/dist/adapters/claude-settings.d.ts +14 -0
- package/dist/adapters/claude-settings.js +43 -0
- package/dist/adapters/claude-settings.js.map +1 -0
- package/dist/adapters/claude-tools.d.ts +9 -0
- package/dist/adapters/claude-tools.js +47 -0
- package/dist/adapters/claude-tools.js.map +1 -0
- package/dist/adapters/claude.d.ts +22 -0
- package/dist/adapters/claude.js +295 -0
- package/dist/adapters/claude.js.map +1 -0
- package/dist/adapters/codex-config.d.ts +25 -0
- package/dist/adapters/codex-config.js +66 -0
- package/dist/adapters/codex-config.js.map +1 -0
- package/dist/adapters/codex.d.ts +2 -0
- package/dist/adapters/codex.js +238 -0
- package/dist/adapters/codex.js.map +1 -0
- package/dist/adapters/fx-auth.d.ts +4 -0
- package/dist/adapters/fx-auth.js +116 -0
- package/dist/adapters/fx-auth.js.map +1 -0
- package/dist/adapters/fx-rpc.d.ts +29 -0
- package/dist/adapters/fx-rpc.js +124 -0
- package/dist/adapters/fx-rpc.js.map +1 -0
- package/dist/adapters/fx-tools.d.ts +19 -0
- package/dist/adapters/fx-tools.js +119 -0
- package/dist/adapters/fx-tools.js.map +1 -0
- package/dist/adapters/fx.d.ts +3 -0
- package/dist/adapters/fx.js +302 -0
- package/dist/adapters/fx.js.map +1 -0
- package/dist/adapters/mcp-tool-content.d.ts +12 -0
- package/dist/adapters/mcp-tool-content.js +8 -0
- package/dist/adapters/mcp-tool-content.js.map +1 -0
- package/dist/adapters/rpc.d.ts +28 -0
- package/dist/adapters/rpc.js +101 -0
- package/dist/adapters/rpc.js.map +1 -0
- package/dist/adapters/types.d.ts +28 -0
- package/dist/adapters/types.js +2 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/args.d.ts +18 -0
- package/dist/cli/args.js +118 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/catalog-worker.d.ts +1 -0
- package/dist/cli/catalog-worker.js +22 -0
- package/dist/cli/catalog-worker.js.map +1 -0
- package/dist/cli/catalog.d.ts +26 -0
- package/dist/cli/catalog.js +41 -0
- package/dist/cli/catalog.js.map +1 -0
- package/dist/cli/help.d.ts +3 -0
- package/dist/cli/help.js +68 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/input.d.ts +5 -0
- package/dist/cli/input.js +69 -0
- package/dist/cli/input.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.js +105 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +7 -0
- package/dist/cli/output.js +43 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/config/access.d.ts +21 -0
- package/dist/config/access.js +97 -0
- package/dist/config/access.js.map +1 -0
- package/dist/config/loader.d.ts +13 -0
- package/dist/config/loader.js +80 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/config/oidc.d.ts +1 -0
- package/dist/config/oidc.js +53 -0
- package/dist/config/oidc.js.map +1 -0
- package/dist/config/project.d.ts +5 -0
- package/dist/config/project.js +56 -0
- package/dist/config/project.js.map +1 -0
- package/dist/config/resolve-access.d.ts +4 -0
- package/dist/config/resolve-access.js +42 -0
- package/dist/config/resolve-access.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime/client.d.ts +9 -0
- package/dist/runtime/client.js +91 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/coordinator.d.ts +61 -0
- package/dist/runtime/coordinator.js +296 -0
- package/dist/runtime/coordinator.js.map +1 -0
- package/dist/runtime/daemon.d.ts +1 -0
- package/dist/runtime/daemon.js +28 -0
- package/dist/runtime/daemon.js.map +1 -0
- package/dist/runtime/definition.d.ts +6 -0
- package/dist/runtime/definition.js +19 -0
- package/dist/runtime/definition.js.map +1 -0
- package/dist/runtime/native-owner.d.ts +8 -0
- package/dist/runtime/native-owner.js +25 -0
- package/dist/runtime/native-owner.js.map +1 -0
- package/dist/runtime/observation.d.ts +1 -0
- package/dist/runtime/observation.js +15 -0
- package/dist/runtime/observation.js.map +1 -0
- package/dist/runtime/select-native.d.ts +3 -0
- package/dist/runtime/select-native.js +34 -0
- package/dist/runtime/select-native.js.map +1 -0
- package/dist/runtime/service.d.ts +5 -0
- package/dist/runtime/service.js +90 -0
- package/dist/runtime/service.js.map +1 -0
- package/dist/runtime/session-launcher.d.ts +6 -0
- package/dist/runtime/session-launcher.js +29 -0
- package/dist/runtime/session-launcher.js.map +1 -0
- package/dist/runtime/state.d.ts +14 -0
- package/dist/runtime/state.js +69 -0
- package/dist/runtime/state.js.map +1 -0
- package/dist/runtime/types.d.ts +81 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/dist/runtime/worker-client.d.ts +3 -0
- package/dist/runtime/worker-client.js +81 -0
- package/dist/runtime/worker-client.js.map +1 -0
- package/dist/runtime/worker.d.ts +1 -0
- package/dist/runtime/worker.js +67 -0
- package/dist/runtime/worker.js.map +1 -0
- package/dist/sdk/definitions.d.ts +6 -0
- package/dist/sdk/definitions.js +72 -0
- package/dist/sdk/definitions.js.map +1 -0
- package/dist/sdk/tool-result.d.ts +23 -0
- package/dist/sdk/tool-result.js +95 -0
- package/dist/sdk/tool-result.js.map +1 -0
- package/dist/sdk/tools.d.ts +9 -0
- package/dist/sdk/tools.js +73 -0
- package/dist/sdk/tools.js.map +1 -0
- package/dist/sdk/types.d.ts +49 -0
- package/dist/sdk/types.js +2 -0
- package/dist/sdk/types.js.map +1 -0
- package/dist/sdk/validation.d.ts +5 -0
- package/dist/sdk/validation.js +20 -0
- package/dist/sdk/validation.js.map +1 -0
- package/dist/shell.d.ts +2 -0
- package/dist/shell.js +5 -0
- package/dist/shell.js.map +1 -0
- package/package.json +61 -0
- package/sdk/access-config.md +52 -0
- package/sdk/adapter-contract.md +33 -0
- package/sdk/agent.md +52 -0
- package/sdk/authentication.md +11 -0
- package/sdk/cli/index.md +67 -0
- package/sdk/cli/output.md +28 -0
- package/sdk/completion-notifications.md +29 -0
- package/sdk/config.md +41 -0
- package/sdk/distribution.md +31 -0
- package/sdk/fx.md +71 -0
- package/sdk/harnesses.md +32 -0
- package/sdk/index.md +22 -0
- package/sdk/message-delivery.md +39 -0
- package/sdk/plugins/sub-agents.md +57 -0
- package/sdk/project-team.md +57 -0
- package/sdk/sessions.md +31 -0
- package/sdk/tools.md +73 -0
- package/sdk/v1-runtime.md +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAyBA,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAgB,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC","sourcesContent":["import type { ErrorInfo } from '../errors.js';\nimport type { HarnessRequest, NativeSession } from '../adapters/types.js';\n\nexport type TaskState = 'queued' | 'running' | 'waiting' | 'completed' | 'failed' | 'cancelled' | 'interrupted';\nexport type Delivery = 'queue' | 'steer' | 'interrupt';\nexport interface AgentReference { file: string; subagents: string[] }\nexport interface HarnessReference { kind: 'harness'; harness: HarnessRequest }\nexport type ExecutionReference = AgentReference | HarnessReference;\nexport interface SessionInput { reference: ExecutionReference; cwd: string; env: NodeJS.ProcessEnv; prompt: string; parentToken?: string }\nexport interface DriverInput extends Omit<SessionInput, 'prompt' | 'parentToken'> { token: string; sessionId: string }\nexport type DriverFactory = (input: DriverInput) => Promise<NativeSession>;\nexport interface RecordBase { version: 1; type: string; sessionId: string; taskId: string; state?: TaskState }\nexport interface Observation extends RecordBase { state: TaskState; responseId?: string; text?: string; error?: ErrorInfo }\nexport interface Receipt extends RecordBase { delivery?: Delivery; requestedDelivery?: Delivery; resumed?: boolean }\nexport interface Response extends Observation { type: 'response'; responseId: string; text: string }\nexport interface ChildResult { taskId: string; state: TaskState; text: string }\nexport interface Task {\n id: string; sessionId: string; prompt: string; parentId?: string; state: TaskState;\n responses: Response[]; children: Set<string>; inbox: ChildResult[]; nativeActive: boolean;\n stopping: boolean; stopPromise?: Promise<void>; stopUnconfirmed?: boolean; error?: ErrorInfo; changed: Set<() => void>;\n}\nexport interface Session {\n id: string; token: string; input: SessionInput; driver?: Promise<NativeSession>;\n tasks: string[]; active?: string; paused: boolean; commands: Promise<unknown>; controls: number;\n}\nexport const terminal = (state: TaskState) => ['completed', 'failed', 'cancelled', 'interrupted'].includes(state);\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { fork } from 'node:child_process';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { delimiter } from 'node:path';
|
|
4
|
+
import { AgentError } from '../errors.js';
|
|
5
|
+
import { createSessionLauncher } from './session-launcher.js';
|
|
6
|
+
export async function createWorker(input) {
|
|
7
|
+
const launcher = await createSessionLauncher(input.env.AGENT_STATE_DIR, input.token);
|
|
8
|
+
const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'js';
|
|
9
|
+
let child;
|
|
10
|
+
try {
|
|
11
|
+
child = fork(fileURLToPath(new URL(`./worker.${extension}`, import.meta.url)), [], {
|
|
12
|
+
cwd: input.cwd, env: { ...input.env, AGENT_PARENT_TOKEN: input.token, AGENT_CLI_PATH: launcher.path,
|
|
13
|
+
PATH: launcher.directory + delimiter + (input.env.PATH ?? '') },
|
|
14
|
+
execArgv: extension === 'ts' ? ['--import', import.meta.resolve('tsx')] : [],
|
|
15
|
+
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
await launcher.close();
|
|
20
|
+
throw error;
|
|
21
|
+
}
|
|
22
|
+
let nextId = 1;
|
|
23
|
+
const pending = new Map();
|
|
24
|
+
let exited = false;
|
|
25
|
+
const exit = () => {
|
|
26
|
+
if (exited)
|
|
27
|
+
return;
|
|
28
|
+
exited = true;
|
|
29
|
+
void launcher.close().catch(() => { }).then(() => {
|
|
30
|
+
for (const waiting of pending.values())
|
|
31
|
+
waiting.reject(new AgentError('HARNESS_FAILED', 'The session worker exited.'));
|
|
32
|
+
pending.clear();
|
|
33
|
+
});
|
|
34
|
+
};
|
|
35
|
+
child.once('error', exit);
|
|
36
|
+
child.once('exit', exit);
|
|
37
|
+
child.on('message', (message) => {
|
|
38
|
+
const request = pending.get(message.id);
|
|
39
|
+
if (!request)
|
|
40
|
+
return;
|
|
41
|
+
pending.delete(message.id);
|
|
42
|
+
if (message.error)
|
|
43
|
+
request.reject(new AgentError(message.error.code, message.error.message));
|
|
44
|
+
else
|
|
45
|
+
request.resolve(message.result);
|
|
46
|
+
});
|
|
47
|
+
const request = (method, extra = {}) => new Promise((resolve, reject) => {
|
|
48
|
+
if (exited) {
|
|
49
|
+
reject(new AgentError('HARNESS_FAILED', 'The session worker is unavailable.'));
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const id = nextId++;
|
|
53
|
+
pending.set(id, { resolve, reject });
|
|
54
|
+
child.send({ id, method, ...extra }, error => { if (error) {
|
|
55
|
+
pending.delete(id);
|
|
56
|
+
reject(new AgentError('HARNESS_FAILED', 'Cannot reach the session worker.'));
|
|
57
|
+
} });
|
|
58
|
+
});
|
|
59
|
+
try {
|
|
60
|
+
await request('open', { input });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
child.kill();
|
|
64
|
+
await launcher.close();
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
turn: prompt => request('turn', { prompt }),
|
|
69
|
+
steer: async (prompt) => { await request('steer', { prompt }); },
|
|
70
|
+
interrupt: async () => { await request('interrupt'); },
|
|
71
|
+
resume: () => request('resume'),
|
|
72
|
+
close: async () => { try {
|
|
73
|
+
if (!exited)
|
|
74
|
+
await request('close');
|
|
75
|
+
}
|
|
76
|
+
finally {
|
|
77
|
+
await launcher.close();
|
|
78
|
+
} },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=worker-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker-client.js","sourceRoot":"","sources":["../../src/runtime/worker-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { fork, type ChildProcess } from 'node:child_process';\nimport { fileURLToPath } from 'node:url';\nimport { delimiter } from 'node:path';\nimport { AgentError, type ErrorInfo } from '../errors.js';\nimport type { NativeSession } from '../adapters/types.js';\nimport type { DriverInput } from './types.js';\nimport { createSessionLauncher } from './session-launcher.js';\n\nexport async function createWorker(input: DriverInput): Promise<NativeSession> {\n const launcher = await createSessionLauncher(input.env.AGENT_STATE_DIR!,input.token);\n const extension = import.meta.url.endsWith('.ts') ? 'ts' : 'js';\n let child: ChildProcess;\n try {\n child = fork(fileURLToPath(new URL(`./worker.${extension}`, import.meta.url)), [], {\n cwd: input.cwd, env: {...input.env,AGENT_PARENT_TOKEN:input.token,AGENT_CLI_PATH:launcher.path,\n PATH:launcher.directory + delimiter + (input.env.PATH ?? '')},\n execArgv: extension === 'ts' ? ['--import', import.meta.resolve('tsx')] : [],\n stdio: ['ignore','ignore','ignore','ipc'],\n });\n } catch (error) { await launcher.close(); throw error; }\n let nextId = 1;\n const pending = new Map<number, {resolve(value:unknown):void;reject(error:Error):void}>();\n let exited = false;\n const exit = () => {\n if (exited) return;\n exited = true;\n void launcher.close().catch(() => {}).then(() => {\n for (const waiting of pending.values()) waiting.reject(new AgentError('HARNESS_FAILED','The session worker exited.'));\n pending.clear();\n });\n };\n child.once('error', exit); child.once('exit', exit);\n child.on('message', (message: {id:number;result?:unknown;error?:ErrorInfo}) => {\n const request = pending.get(message.id);\n if (!request) return;\n pending.delete(message.id);\n if (message.error) request.reject(new AgentError(message.error.code, message.error.message));\n else request.resolve(message.result);\n });\n const request = (method:string, extra:Record<string,unknown> = {}) => new Promise<unknown>((resolve,reject) => {\n if (exited) { reject(new AgentError('HARNESS_FAILED','The session worker is unavailable.')); return; }\n const id = nextId++;\n pending.set(id,{resolve,reject});\n child.send({id,method,...extra}, error => { if (error) { pending.delete(id); reject(new AgentError('HARNESS_FAILED','Cannot reach the session worker.')); } });\n });\n try { await request('open',{input}); } catch (error) { child.kill(); await launcher.close(); throw error; }\n return {\n turn: prompt => request('turn',{prompt}) as Promise<string>,\n steer: async prompt => { await request('steer',{prompt}); },\n interrupt: async () => { await request('interrupt'); },\n resume: () => request('resume') as Promise<string>,\n close: async () => { try { if (!exited) await request('close'); } finally { await launcher.close(); } },\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { loadExecutionDefinition } from './definition.js';
|
|
2
|
+
import { loadAccess } from '../config/access.js';
|
|
3
|
+
import { errorInfo } from '../errors.js';
|
|
4
|
+
import { selectNative } from './select-native.js';
|
|
5
|
+
import { NativeOwner } from './native-owner.js';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
import { rm } from 'node:fs/promises';
|
|
8
|
+
import { shellQuote } from '../shell.js';
|
|
9
|
+
let native;
|
|
10
|
+
const owner = new NativeOwner();
|
|
11
|
+
const launcherDirectory = dirname(process.env.AGENT_CLI_PATH);
|
|
12
|
+
let closing;
|
|
13
|
+
const close = () => closing ??= (async () => {
|
|
14
|
+
try {
|
|
15
|
+
await owner.close();
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
await rm(launcherDirectory, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
})();
|
|
21
|
+
const reply = (message) => { if (process.connected)
|
|
22
|
+
process.send?.(message, () => { }); };
|
|
23
|
+
process.on('message', async (message) => {
|
|
24
|
+
try {
|
|
25
|
+
let result;
|
|
26
|
+
if (message.method === 'open') {
|
|
27
|
+
native = await owner.open(async () => {
|
|
28
|
+
const input = message.input;
|
|
29
|
+
const definition = await loadExecutionDefinition(input.reference);
|
|
30
|
+
const children = Object.entries(definition.subagents ?? {});
|
|
31
|
+
const launcher = children.length ? shellQuote(process.env.AGENT_CLI_PATH) : '';
|
|
32
|
+
const instructions = children.length ? definition.instructions + '\n\nAvailable delegated agents:\n' +
|
|
33
|
+
children.map(([name, child]) => `- subagent:${name}: ${child.description}`).join('\n') +
|
|
34
|
+
'\nCopy the launcher path and its quoting exactly from the command below. Do not shorten or replace the path. ' +
|
|
35
|
+
'Replace only the angle-bracket arguments. Use --prompt-file instead of --prompt when needed.\n' +
|
|
36
|
+
`\n\`\`\`sh\n${launcher} run subagent:<name> --cwd <existing-directory> --prompt <task>\n\`\`\`\n` +
|
|
37
|
+
'For follow-ups, queue, steer, interrupt, wait, and cancellation, read the help:\n' +
|
|
38
|
+
`\n\`\`\`sh\n${launcher} --help\n\`\`\`\n` +
|
|
39
|
+
'Include needed task context; child sessions do not inherit your conversation.' : definition.instructions;
|
|
40
|
+
return selectNative({ ...definition, instructions }, input.cwd, process.env, await loadAccess(input.cwd));
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
else if (message.method === 'turn')
|
|
44
|
+
result = await native.turn(message.prompt);
|
|
45
|
+
else if (message.method === 'steer')
|
|
46
|
+
result = await native.steer(message.prompt);
|
|
47
|
+
else if (message.method === 'interrupt')
|
|
48
|
+
result = await native.interrupt();
|
|
49
|
+
else if (message.method === 'resume')
|
|
50
|
+
result = await native.resume();
|
|
51
|
+
else if (message.method === 'close') {
|
|
52
|
+
await close();
|
|
53
|
+
reply({ id: message.id, result: null });
|
|
54
|
+
if (process.connected)
|
|
55
|
+
process.disconnect();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
throw new Error('Unknown worker operation');
|
|
60
|
+
reply({ id: message.id, result: result ?? null });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
reply({ id: message.id, error: errorInfo(error) });
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
process.on('disconnect', () => { void close().catch(() => { }).finally(() => process.exit()); });
|
|
67
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../src/runtime/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import { loadExecutionDefinition } from './definition.js';\nimport { loadAccess } from '../config/access.js';\nimport { errorInfo } from '../errors.js';\nimport { selectNative } from './select-native.js';\nimport { NativeOwner } from './native-owner.js';\nimport type { DriverInput } from './types.js';\nimport type { NativeSession } from '../adapters/types.js';\nimport { dirname } from 'node:path';\nimport { rm } from 'node:fs/promises';\nimport { shellQuote } from '../shell.js';\n\nlet native: NativeSession | undefined;\nconst owner = new NativeOwner();\nconst launcherDirectory = dirname(process.env.AGENT_CLI_PATH!);\nlet closing: Promise<void> | undefined;\nconst close = () => closing ??= (async () => {\n try { await owner.close(); }\n finally { await rm(launcherDirectory,{recursive:true,force:true}); }\n})();\nconst reply = (message: unknown) => { if (process.connected) process.send?.(message as object, () => {}); };\nprocess.on('message', async (message: {id:number;method:string;input?:DriverInput;prompt?:string}) => {\n try {\n let result: unknown;\n if (message.method === 'open') {\n native = await owner.open(async () => {\n const input = message.input!;\n const definition = await loadExecutionDefinition(input.reference);\n const children = Object.entries(definition.subagents ?? {});\n const launcher = children.length ? shellQuote(process.env.AGENT_CLI_PATH!) : '';\n const instructions = children.length ? definition.instructions + '\\n\\nAvailable delegated agents:\\n' +\n children.map(([name, child]) => `- subagent:${name}: ${child.description}`).join('\\n') +\n '\\nCopy the launcher path and its quoting exactly from the command below. Do not shorten or replace the path. ' +\n 'Replace only the angle-bracket arguments. Use --prompt-file instead of --prompt when needed.\\n' +\n `\\n\\`\\`\\`sh\\n${launcher} run subagent:<name> --cwd <existing-directory> --prompt <task>\\n\\`\\`\\`\\n` +\n 'For follow-ups, queue, steer, interrupt, wait, and cancellation, read the help:\\n' +\n `\\n\\`\\`\\`sh\\n${launcher} --help\\n\\`\\`\\`\\n` +\n 'Include needed task context; child sessions do not inherit your conversation.' : definition.instructions;\n return selectNative({...definition,instructions}, input.cwd, process.env, await loadAccess(input.cwd));\n });\n } else if (message.method === 'turn') result = await native!.turn(message.prompt!);\n else if (message.method === 'steer') result = await native!.steer(message.prompt!);\n else if (message.method === 'interrupt') result = await native!.interrupt();\n else if (message.method === 'resume') result = await native!.resume();\n else if (message.method === 'close') { await close(); reply({id:message.id,result:null}); if (process.connected) process.disconnect(); return; }\n else throw new Error('Unknown worker operation');\n reply({id:message.id,result:result ?? null});\n } catch (error) { reply({id:message.id,error:errorInfo(error)}); }\n});\nprocess.on('disconnect', () => { void close().catch(() => {}).finally(() => process.exit()); });\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { AgentDefinition, ClaudeCodeConfig, ClaudeCodeOptions, CodexConfig, CodexOptions, FxConfig, FxOptions } from "./types.js";
|
|
2
|
+
export declare function codex(options: CodexOptions): CodexConfig;
|
|
3
|
+
export declare function claudeCode(options: ClaudeCodeOptions): ClaudeCodeConfig;
|
|
4
|
+
export declare function fx(options: FxOptions): FxConfig;
|
|
5
|
+
export declare function agent(definition: AgentDefinition): AgentDefinition;
|
|
6
|
+
export declare function validateAgent(value: unknown, ancestors?: Set<unknown>): asserts value is AgentDefinition;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { invalid, nonempty, object, validName } from "./validation.js";
|
|
2
|
+
import { validateTool } from "./tools.js";
|
|
3
|
+
function validateHarness(value, configured = false) {
|
|
4
|
+
object(value, configured ? ["kind", "model", "effort", "fast"] : ["model", "effort", "fast"]);
|
|
5
|
+
nonempty(value.model, "Model");
|
|
6
|
+
if (value.effort !== undefined)
|
|
7
|
+
nonempty(value.effort, "Effort");
|
|
8
|
+
if (value.fast !== undefined && typeof value.fast !== "boolean")
|
|
9
|
+
invalid("fast must be a boolean.");
|
|
10
|
+
if (configured && value.kind !== "codex" && value.kind !== "claudeCode" && value.kind !== "fx")
|
|
11
|
+
invalid("Unsupported harness kind.");
|
|
12
|
+
if (configured && value.kind === "fx" && "fast" in value)
|
|
13
|
+
invalid("Unknown configuration field.");
|
|
14
|
+
if (configured && value.kind === "claudeCode")
|
|
15
|
+
validateClaudeEffort(value.effort);
|
|
16
|
+
}
|
|
17
|
+
function validateClaudeEffort(effort) {
|
|
18
|
+
if (effort !== undefined && !["low", "medium", "high", "xhigh", "max"].includes(effort)) {
|
|
19
|
+
invalid("Claude effort must be low, medium, high, xhigh, or max.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function codex(options) {
|
|
23
|
+
validateHarness(options);
|
|
24
|
+
return Object.freeze({ ...options, kind: "codex", fast: options.fast ?? false });
|
|
25
|
+
}
|
|
26
|
+
export function claudeCode(options) {
|
|
27
|
+
validateHarness(options);
|
|
28
|
+
validateClaudeEffort(options.effort);
|
|
29
|
+
return Object.freeze({ ...options, kind: "claudeCode", fast: options.fast ?? false });
|
|
30
|
+
}
|
|
31
|
+
export function fx(options) {
|
|
32
|
+
object(options, ["model", "effort"]);
|
|
33
|
+
nonempty(options.model, "Model");
|
|
34
|
+
if (options.effort !== undefined)
|
|
35
|
+
nonempty(options.effort, "Effort");
|
|
36
|
+
return Object.freeze({ ...options, kind: "fx" });
|
|
37
|
+
}
|
|
38
|
+
export function agent(definition) {
|
|
39
|
+
validateAgent(definition);
|
|
40
|
+
return Object.freeze({
|
|
41
|
+
...definition,
|
|
42
|
+
...(Array.isArray(definition.harness) ? { harness: Object.freeze([...definition.harness]) } : {}),
|
|
43
|
+
...(definition.tools ? { tools: Object.freeze({ ...definition.tools }) } : {}),
|
|
44
|
+
...(definition.subagents ? { subagents: Object.freeze({ ...definition.subagents }) } : {}),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function validateAgent(value, ancestors = new Set()) {
|
|
48
|
+
object(value, ["name", "description", "instructions", "harness", "tools", "subagents"]);
|
|
49
|
+
if (ancestors.has(value))
|
|
50
|
+
invalid("Subagent definitions cannot contain recursive references.");
|
|
51
|
+
validName(value.name);
|
|
52
|
+
nonempty(value.description, "Description");
|
|
53
|
+
nonempty(value.instructions, "Instructions");
|
|
54
|
+
const harnesses = Array.isArray(value.harness) ? value.harness : [value.harness];
|
|
55
|
+
if (!harnesses.length)
|
|
56
|
+
invalid("At least one harness is required.");
|
|
57
|
+
harnesses.forEach((harness) => validateHarness(harness, true));
|
|
58
|
+
if (value.tools !== undefined) {
|
|
59
|
+
object(value.tools);
|
|
60
|
+
Object.keys(value.tools).forEach(validName);
|
|
61
|
+
Object.values(value.tools).forEach(validateTool);
|
|
62
|
+
}
|
|
63
|
+
if (value.subagents !== undefined) {
|
|
64
|
+
object(value.subagents);
|
|
65
|
+
const next = new Set(ancestors).add(value);
|
|
66
|
+
for (const [name, child] of Object.entries(value.subagents)) {
|
|
67
|
+
validName(name);
|
|
68
|
+
validateAgent(child, next);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=definitions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/sdk/definitions.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n AgentDefinition,\n ClaudeCodeConfig,\n ClaudeCodeOptions,\n CodexConfig,\n CodexOptions,\n FxConfig,\n FxOptions,\n HarnessConfig,\n} from \"./types.js\";\nimport { invalid, nonempty, object, validName } from \"./validation.js\";\nimport { validateTool } from \"./tools.js\";\n\nfunction validateHarness(value: unknown, configured = false): void {\n object(value, configured ? [\"kind\", \"model\", \"effort\", \"fast\"] : [\"model\", \"effort\", \"fast\"]);\n nonempty(value.model, \"Model\");\n if (value.effort !== undefined) nonempty(value.effort, \"Effort\");\n if (value.fast !== undefined && typeof value.fast !== \"boolean\") invalid(\"fast must be a boolean.\");\n if (configured && value.kind !== \"codex\" && value.kind !== \"claudeCode\" && value.kind !== \"fx\") invalid(\"Unsupported harness kind.\");\n if (configured && value.kind === \"fx\" && \"fast\" in value) invalid(\"Unknown configuration field.\");\n if (configured && value.kind === \"claudeCode\") validateClaudeEffort(value.effort);\n}\n\nfunction validateClaudeEffort(effort: unknown): void {\n if (effort !== undefined && ![\"low\", \"medium\", \"high\", \"xhigh\", \"max\"].includes(effort as string)) {\n invalid(\"Claude effort must be low, medium, high, xhigh, or max.\");\n }\n}\n\nexport function codex(options: CodexOptions): CodexConfig {\n validateHarness(options);\n return Object.freeze({ ...options, kind: \"codex\", fast: options.fast ?? false });\n}\n\nexport function claudeCode(options: ClaudeCodeOptions): ClaudeCodeConfig {\n validateHarness(options);\n validateClaudeEffort(options.effort);\n return Object.freeze({ ...options, kind: \"claudeCode\", fast: options.fast ?? false });\n}\n\nexport function fx(options: FxOptions): FxConfig {\n object(options, [\"model\", \"effort\"]);\n nonempty(options.model, \"Model\");\n if (options.effort !== undefined) nonempty(options.effort, \"Effort\");\n return Object.freeze({ ...options, kind: \"fx\" });\n}\n\nexport function agent(definition: AgentDefinition): AgentDefinition {\n validateAgent(definition);\n return Object.freeze({\n ...definition,\n ...(Array.isArray(definition.harness) ? { harness: Object.freeze([...definition.harness]) } : {}),\n ...(definition.tools ? { tools: Object.freeze({ ...definition.tools }) } : {}),\n ...(definition.subagents ? { subagents: Object.freeze({ ...definition.subagents }) } : {}),\n });\n}\n\nexport function validateAgent(value: unknown, ancestors = new Set<unknown>()): asserts value is AgentDefinition {\n object(value, [\"name\", \"description\", \"instructions\", \"harness\", \"tools\", \"subagents\"]);\n if (ancestors.has(value)) invalid(\"Subagent definitions cannot contain recursive references.\");\n validName(value.name);\n nonempty(value.description, \"Description\");\n nonempty(value.instructions, \"Instructions\");\n const harnesses = Array.isArray(value.harness) ? value.harness : [value.harness];\n if (!harnesses.length) invalid(\"At least one harness is required.\");\n harnesses.forEach((harness) => validateHarness(harness, true));\n if (value.tools !== undefined) {\n object(value.tools);\n Object.keys(value.tools).forEach(validName);\n Object.values(value.tools).forEach(validateTool);\n }\n if (value.subagents !== undefined) {\n object(value.subagents);\n const next = new Set(ancestors).add(value);\n for (const [name, child] of Object.entries(value.subagents)) {\n validName(name);\n validateAgent(child, next);\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type ToolContent = {
|
|
2
|
+
readonly type: "text";
|
|
3
|
+
readonly text: string;
|
|
4
|
+
} | {
|
|
5
|
+
readonly type: "image";
|
|
6
|
+
readonly data: string;
|
|
7
|
+
readonly mimeType: "image/png" | "image/jpeg" | "image/webp" | "image/gif";
|
|
8
|
+
};
|
|
9
|
+
declare const toolResultBrand: unique symbol;
|
|
10
|
+
export interface ToolResult {
|
|
11
|
+
readonly [toolResultBrand]: true;
|
|
12
|
+
}
|
|
13
|
+
export type ExecutedToolResult = string | {
|
|
14
|
+
readonly kind: "content";
|
|
15
|
+
readonly content: readonly ToolContent[];
|
|
16
|
+
};
|
|
17
|
+
export declare function toolResult(result: {
|
|
18
|
+
readonly content: readonly ToolContent[];
|
|
19
|
+
}): ToolResult;
|
|
20
|
+
export declare function richToolResult(value: unknown): {
|
|
21
|
+
readonly content: readonly ToolContent[];
|
|
22
|
+
} | undefined;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { AgentError } from "../errors.js";
|
|
2
|
+
const registryKey = Symbol.for("subharness.tool-results.v1");
|
|
3
|
+
const results = sharedRegistry();
|
|
4
|
+
export function toolResult(result) {
|
|
5
|
+
const token = Object.freeze({});
|
|
6
|
+
results.set(token, result);
|
|
7
|
+
return token;
|
|
8
|
+
}
|
|
9
|
+
export function richToolResult(value) {
|
|
10
|
+
if ((typeof value !== "object" || value === null) || !results.has(value))
|
|
11
|
+
return undefined;
|
|
12
|
+
return validateRichResult(results.get(value));
|
|
13
|
+
}
|
|
14
|
+
function sharedRegistry() {
|
|
15
|
+
const host = globalThis;
|
|
16
|
+
const existing = host[registryKey];
|
|
17
|
+
if (existing instanceof WeakMap)
|
|
18
|
+
return existing;
|
|
19
|
+
const registry = new WeakMap();
|
|
20
|
+
Object.defineProperty(host, registryKey, { value: registry, enumerable: false, configurable: false, writable: false });
|
|
21
|
+
return registry;
|
|
22
|
+
}
|
|
23
|
+
function validateRichResult(value) {
|
|
24
|
+
if (!plainObject(value) || !hasOnlyKeys(value, ["content"]) || !Array.isArray(value.content) || value.content.length === 0) {
|
|
25
|
+
throw invalidResult();
|
|
26
|
+
}
|
|
27
|
+
let images = 0;
|
|
28
|
+
let textBytes = 0;
|
|
29
|
+
const content = [];
|
|
30
|
+
for (const block of value.content) {
|
|
31
|
+
if (!plainObject(block) || typeof block.type !== "string")
|
|
32
|
+
throw invalidResult();
|
|
33
|
+
if (block.type === "text") {
|
|
34
|
+
if (!hasOnlyKeys(block, ["type", "text"]) || typeof block.text !== "string")
|
|
35
|
+
throw invalidResult();
|
|
36
|
+
textBytes += Buffer.byteLength(block.text, "utf8");
|
|
37
|
+
content.push(Object.freeze({ type: "text", text: block.text }));
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (block.type !== "image" || !hasOnlyKeys(block, ["type", "data", "mimeType"])
|
|
41
|
+
|| typeof block.data !== "string" || !isMimeType(block.mimeType))
|
|
42
|
+
throw invalidResult();
|
|
43
|
+
images++;
|
|
44
|
+
if (images > 8)
|
|
45
|
+
throw tooLargeResult();
|
|
46
|
+
if (Buffer.byteLength(block.data, "utf8") > 5 * 1024 * 1024)
|
|
47
|
+
throw tooLargeResult();
|
|
48
|
+
const bytes = decodeCanonicalBase64(block.data);
|
|
49
|
+
if (!matchesMimeType(bytes, block.mimeType))
|
|
50
|
+
throw invalidResult();
|
|
51
|
+
content.push(Object.freeze({ type: "image", data: block.data, mimeType: block.mimeType }));
|
|
52
|
+
}
|
|
53
|
+
if (textBytes > 1024 * 1024)
|
|
54
|
+
throw tooLargeResult();
|
|
55
|
+
if (Buffer.byteLength(JSON.stringify(content), "utf8") > 8 * 1024 * 1024)
|
|
56
|
+
throw tooLargeResult();
|
|
57
|
+
return Object.freeze({ content: Object.freeze(content) });
|
|
58
|
+
}
|
|
59
|
+
function plainObject(value) {
|
|
60
|
+
if (typeof value !== "object" || value === null)
|
|
61
|
+
return false;
|
|
62
|
+
const prototype = Object.getPrototypeOf(value);
|
|
63
|
+
return prototype === Object.prototype || prototype === null;
|
|
64
|
+
}
|
|
65
|
+
function hasOnlyKeys(value, expected) {
|
|
66
|
+
const keys = Object.keys(value);
|
|
67
|
+
return keys.length === expected.length && expected.every(key => Object.hasOwn(value, key));
|
|
68
|
+
}
|
|
69
|
+
function isMimeType(value) {
|
|
70
|
+
return value === "image/png" || value === "image/jpeg" || value === "image/webp" || value === "image/gif";
|
|
71
|
+
}
|
|
72
|
+
function decodeCanonicalBase64(data) {
|
|
73
|
+
if (data.length === 0 || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*(?:={1,2})?$/u.test(data))
|
|
74
|
+
throw invalidResult();
|
|
75
|
+
const decoded = Buffer.from(data, "base64");
|
|
76
|
+
if (decoded.toString("base64") !== data)
|
|
77
|
+
throw invalidResult();
|
|
78
|
+
return decoded;
|
|
79
|
+
}
|
|
80
|
+
function matchesMimeType(data, mimeType) {
|
|
81
|
+
if (mimeType === "image/png")
|
|
82
|
+
return data.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));
|
|
83
|
+
if (mimeType === "image/jpeg")
|
|
84
|
+
return data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff;
|
|
85
|
+
if (mimeType === "image/gif")
|
|
86
|
+
return data.subarray(0, 6).toString("ascii") === "GIF87a" || data.subarray(0, 6).toString("ascii") === "GIF89a";
|
|
87
|
+
return data.subarray(0, 4).toString("ascii") === "RIFF" && data.subarray(8, 12).toString("ascii") === "WEBP";
|
|
88
|
+
}
|
|
89
|
+
function invalidResult() {
|
|
90
|
+
return new AgentError("TOOL_RESULT_INVALID", "Tool returned invalid rich content.");
|
|
91
|
+
}
|
|
92
|
+
function tooLargeResult() {
|
|
93
|
+
return new AgentError("TOOL_RESULT_TOO_LARGE", "Tool result exceeds the documented size limits.");
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=tool-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-result.js","sourceRoot":"","sources":["../../src/sdk/tool-result.ts"],"names":[],"mappings":"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","sourcesContent":["import { AgentError } from \"../errors.js\";\n\nexport type ToolContent =\n | { readonly type: \"text\"; readonly text: string }\n | {\n readonly type: \"image\";\n readonly data: string;\n readonly mimeType: \"image/png\" | \"image/jpeg\" | \"image/webp\" | \"image/gif\";\n };\n\ndeclare const toolResultBrand: unique symbol;\n\nexport interface ToolResult {\n readonly [toolResultBrand]: true;\n}\n\nexport type ExecutedToolResult =\n | string\n | { readonly kind: \"content\"; readonly content: readonly ToolContent[] };\n\nconst registryKey = Symbol.for(\"subharness.tool-results.v1\");\nconst results = sharedRegistry();\n\nexport function toolResult(result: { readonly content: readonly ToolContent[] }): ToolResult {\n const token = Object.freeze({});\n results.set(token, result);\n return token as ToolResult;\n}\n\nexport function richToolResult(value: unknown): { readonly content: readonly ToolContent[] } | undefined {\n if ((typeof value !== \"object\" || value === null) || !results.has(value)) return undefined;\n return validateRichResult(results.get(value));\n}\n\nfunction sharedRegistry(): WeakMap<object, unknown> {\n const host = globalThis as unknown as Record<PropertyKey, unknown>;\n const existing = host[registryKey];\n if (existing instanceof WeakMap) return existing;\n const registry = new WeakMap<object, unknown>();\n Object.defineProperty(host, registryKey, { value: registry, enumerable: false, configurable: false, writable: false });\n return registry;\n}\n\nfunction validateRichResult(value: unknown): { readonly content: readonly ToolContent[] } {\n if (!plainObject(value) || !hasOnlyKeys(value, [\"content\"]) || !Array.isArray(value.content) || value.content.length === 0) {\n throw invalidResult();\n }\n\n let images = 0;\n let textBytes = 0;\n const content: ToolContent[] = [];\n for (const block of value.content) {\n if (!plainObject(block) || typeof block.type !== \"string\") throw invalidResult();\n if (block.type === \"text\") {\n if (!hasOnlyKeys(block, [\"type\", \"text\"]) || typeof block.text !== \"string\") throw invalidResult();\n textBytes += Buffer.byteLength(block.text, \"utf8\");\n content.push(Object.freeze({ type: \"text\", text: block.text }));\n continue;\n }\n if (block.type !== \"image\" || !hasOnlyKeys(block, [\"type\", \"data\", \"mimeType\"])\n || typeof block.data !== \"string\" || !isMimeType(block.mimeType)) throw invalidResult();\n images++;\n if (images > 8) throw tooLargeResult();\n if (Buffer.byteLength(block.data, \"utf8\") > 5 * 1024 * 1024) throw tooLargeResult();\n const bytes = decodeCanonicalBase64(block.data);\n if (!matchesMimeType(bytes, block.mimeType)) throw invalidResult();\n content.push(Object.freeze({ type: \"image\", data: block.data, mimeType: block.mimeType }));\n }\n\n if (textBytes > 1024 * 1024) throw tooLargeResult();\n if (Buffer.byteLength(JSON.stringify(content), \"utf8\") > 8 * 1024 * 1024) throw tooLargeResult();\n return Object.freeze({ content: Object.freeze(content) });\n}\n\nfunction plainObject(value: unknown): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n}\n\nfunction hasOnlyKeys(value: Record<string, unknown>, expected: readonly string[]): boolean {\n const keys = Object.keys(value);\n return keys.length === expected.length && expected.every(key => Object.hasOwn(value, key));\n}\n\nfunction isMimeType(value: unknown): value is Extract<ToolContent, { type: \"image\" }>[\"mimeType\"] {\n return value === \"image/png\" || value === \"image/jpeg\" || value === \"image/webp\" || value === \"image/gif\";\n}\n\nfunction decodeCanonicalBase64(data: string): Buffer {\n if (data.length === 0 || data.length % 4 !== 0 || !/^[A-Za-z0-9+/]*(?:={1,2})?$/u.test(data)) throw invalidResult();\n const decoded = Buffer.from(data, \"base64\");\n if (decoded.toString(\"base64\") !== data) throw invalidResult();\n return decoded;\n}\n\nfunction matchesMimeType(data: Buffer, mimeType: Extract<ToolContent, { type: \"image\" }>[\"mimeType\"]): boolean {\n if (mimeType === \"image/png\") return data.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]));\n if (mimeType === \"image/jpeg\") return data.length >= 3 && data[0] === 0xff && data[1] === 0xd8 && data[2] === 0xff;\n if (mimeType === \"image/gif\") return data.subarray(0, 6).toString(\"ascii\") === \"GIF87a\" || data.subarray(0, 6).toString(\"ascii\") === \"GIF89a\";\n return data.subarray(0, 4).toString(\"ascii\") === \"RIFF\" && data.subarray(8, 12).toString(\"ascii\") === \"WEBP\";\n}\n\nfunction invalidResult(): AgentError {\n return new AgentError(\"TOOL_RESULT_INVALID\", \"Tool returned invalid rich content.\");\n}\n\nfunction tooLargeResult(): AgentError {\n return new AgentError(\"TOOL_RESULT_TOO_LARGE\", \"Tool result exceeds the documented size limits.\");\n}\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "./types.js";
|
|
3
|
+
import { type ExecutedToolResult } from "./tool-result.js";
|
|
4
|
+
export { toolResult } from "./tool-result.js";
|
|
5
|
+
export type { ToolContent, ToolResult } from "./tool-result.js";
|
|
6
|
+
export declare function tool<S extends z.ZodObject>(definition: ToolDefinition<S>): ToolDefinition<S>;
|
|
7
|
+
export declare function validateTool(definition: unknown): asserts definition is ToolDefinition<any>;
|
|
8
|
+
export declare function toolJsonSchema(definition: ToolDefinition<any>): Record<string, unknown>;
|
|
9
|
+
export declare function executeTool(definition: ToolDefinition<any>, input: unknown): Promise<ExecutedToolResult>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { AgentError } from "../errors.js";
|
|
3
|
+
import { richToolResult } from "./tool-result.js";
|
|
4
|
+
import { invalid, nonempty, object } from "./validation.js";
|
|
5
|
+
export { toolResult } from "./tool-result.js";
|
|
6
|
+
export function tool(definition) {
|
|
7
|
+
validateTool(definition);
|
|
8
|
+
return Object.freeze({ ...definition });
|
|
9
|
+
}
|
|
10
|
+
export function validateTool(definition) {
|
|
11
|
+
object(definition, ["description", "inputSchema", "execute"]);
|
|
12
|
+
nonempty(definition.description, "Tool description");
|
|
13
|
+
if (!(definition.inputSchema instanceof z.ZodObject))
|
|
14
|
+
invalid("Tools require a Zod 4 object schema.");
|
|
15
|
+
if (typeof definition.execute !== "function")
|
|
16
|
+
invalid("Tool execute must be a function.");
|
|
17
|
+
toolJsonSchema(definition);
|
|
18
|
+
}
|
|
19
|
+
export function toolJsonSchema(definition) {
|
|
20
|
+
try {
|
|
21
|
+
return z.toJSONSchema(definition.inputSchema, { io: "input" });
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return invalid("Tool input schema cannot be represented as JSON Schema.");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function executeTool(definition, input) {
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = await definition.inputSchema.safeParseAsync(input);
|
|
31
|
+
if (!parsed.success)
|
|
32
|
+
throw new Error();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new AgentError("TOOL_INPUT_INVALID", "Tool arguments do not match the declared schema.");
|
|
36
|
+
}
|
|
37
|
+
let result;
|
|
38
|
+
try {
|
|
39
|
+
result = await definition.execute(parsed.data);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
throw new AgentError("TOOL_EXECUTION_FAILED", "The custom tool failed during execution.");
|
|
43
|
+
}
|
|
44
|
+
let rich;
|
|
45
|
+
try {
|
|
46
|
+
rich = richToolResult(result);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
if (error instanceof AgentError)
|
|
50
|
+
throw error;
|
|
51
|
+
throw new AgentError("TOOL_RESULT_INVALID", "Tool returned invalid rich content.");
|
|
52
|
+
}
|
|
53
|
+
if (rich)
|
|
54
|
+
return { kind: "content", content: rich.content };
|
|
55
|
+
let text;
|
|
56
|
+
try {
|
|
57
|
+
text = typeof result === "string" ? result : JSON.stringify(result, (_key, value) => {
|
|
58
|
+
if (["undefined", "function", "symbol", "bigint"].includes(typeof value)
|
|
59
|
+
|| (typeof value === "number" && !Number.isFinite(value)))
|
|
60
|
+
throw new Error();
|
|
61
|
+
return value;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new AgentError("TOOL_RESULT_INVALID", "Tool result must be a string or JSON-serializable value.");
|
|
66
|
+
}
|
|
67
|
+
if (text === undefined)
|
|
68
|
+
throw new AgentError("TOOL_RESULT_INVALID", "Tool result must be a string or JSON-serializable value.");
|
|
69
|
+
if (Buffer.byteLength(text, "utf8") > 1024 * 1024)
|
|
70
|
+
throw new AgentError("TOOL_RESULT_TOO_LARGE", "Tool result exceeds 1 MiB.");
|
|
71
|
+
return text;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/sdk/tools.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport { AgentError } from \"../errors.js\";\nimport type { ToolDefinition } from \"./types.js\";\nimport { richToolResult, type ExecutedToolResult } from \"./tool-result.js\";\nimport { invalid, nonempty, object } from \"./validation.js\";\n\nexport { toolResult } from \"./tool-result.js\";\nexport type { ToolContent, ToolResult } from \"./tool-result.js\";\n\nexport function tool<S extends z.ZodObject>(definition: ToolDefinition<S>): ToolDefinition<S> {\n validateTool(definition);\n return Object.freeze({ ...definition });\n}\n\nexport function validateTool(definition: unknown): asserts definition is ToolDefinition<any> {\n object(definition, [\"description\", \"inputSchema\", \"execute\"]);\n nonempty(definition.description, \"Tool description\");\n if (!(definition.inputSchema instanceof z.ZodObject)) invalid(\"Tools require a Zod 4 object schema.\");\n if (typeof definition.execute !== \"function\") invalid(\"Tool execute must be a function.\");\n toolJsonSchema(definition as unknown as ToolDefinition);\n}\n\nexport function toolJsonSchema(definition: ToolDefinition<any>): Record<string, unknown> {\n try {\n return z.toJSONSchema(definition.inputSchema, { io: \"input\" });\n } catch {\n return invalid(\"Tool input schema cannot be represented as JSON Schema.\");\n }\n}\n\nexport async function executeTool(definition: ToolDefinition<any>, input: unknown): Promise<ExecutedToolResult> {\n let parsed;\n try {\n parsed = await definition.inputSchema.safeParseAsync(input);\n if (!parsed.success) throw new Error();\n } catch {\n throw new AgentError(\"TOOL_INPUT_INVALID\", \"Tool arguments do not match the declared schema.\");\n }\n let result: unknown;\n try {\n result = await definition.execute(parsed.data);\n } catch {\n throw new AgentError(\"TOOL_EXECUTION_FAILED\", \"The custom tool failed during execution.\");\n }\n let rich;\n try {\n rich = richToolResult(result);\n } catch (error) {\n if (error instanceof AgentError) throw error;\n throw new AgentError(\"TOOL_RESULT_INVALID\", \"Tool returned invalid rich content.\");\n }\n if (rich) return { kind: \"content\", content: rich.content };\n let text: string | undefined;\n try {\n text = typeof result === \"string\" ? result : JSON.stringify(result, (_key, value: unknown) => {\n if ([\"undefined\", \"function\", \"symbol\", \"bigint\"].includes(typeof value)\n || (typeof value === \"number\" && !Number.isFinite(value))) throw new Error();\n return value;\n });\n } catch {\n throw new AgentError(\"TOOL_RESULT_INVALID\", \"Tool result must be a string or JSON-serializable value.\");\n }\n if (text === undefined) throw new AgentError(\"TOOL_RESULT_INVALID\", \"Tool result must be a string or JSON-serializable value.\");\n if (Buffer.byteLength(text, \"utf8\") > 1024 * 1024) throw new AgentError(\"TOOL_RESULT_TOO_LARGE\", \"Tool result exceeds 1 MiB.\");\n return text;\n}\n"]}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
export type HarnessKind = "codex" | "claudeCode" | "fx";
|
|
3
|
+
export interface CodexConfig {
|
|
4
|
+
readonly kind: "codex";
|
|
5
|
+
readonly model: string;
|
|
6
|
+
readonly effort?: string;
|
|
7
|
+
readonly fast: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface ClaudeCodeConfig {
|
|
10
|
+
readonly kind: "claudeCode";
|
|
11
|
+
readonly model: string;
|
|
12
|
+
readonly effort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
13
|
+
readonly fast: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface FxConfig {
|
|
16
|
+
readonly kind: "fx";
|
|
17
|
+
readonly model: string;
|
|
18
|
+
readonly effort?: string;
|
|
19
|
+
}
|
|
20
|
+
export type HarnessConfig = CodexConfig | ClaudeCodeConfig | (FxConfig & {
|
|
21
|
+
readonly fast?: never;
|
|
22
|
+
});
|
|
23
|
+
export interface CodexOptions {
|
|
24
|
+
readonly model: string;
|
|
25
|
+
readonly effort?: string;
|
|
26
|
+
readonly fast?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface ClaudeCodeOptions {
|
|
29
|
+
readonly model: string;
|
|
30
|
+
readonly effort?: "low" | "medium" | "high" | "xhigh" | "max";
|
|
31
|
+
readonly fast?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export interface FxOptions {
|
|
34
|
+
readonly model: string;
|
|
35
|
+
readonly effort?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ToolDefinition<S extends z.ZodObject = z.ZodObject> {
|
|
38
|
+
readonly description: string;
|
|
39
|
+
readonly inputSchema: S;
|
|
40
|
+
readonly execute: (input: z.output<S>) => unknown | Promise<unknown>;
|
|
41
|
+
}
|
|
42
|
+
export interface AgentDefinition {
|
|
43
|
+
readonly name: string;
|
|
44
|
+
readonly description: string;
|
|
45
|
+
readonly instructions: string;
|
|
46
|
+
readonly harness: HarnessConfig | readonly HarnessConfig[];
|
|
47
|
+
readonly tools?: Readonly<Record<string, ToolDefinition<any>>>;
|
|
48
|
+
readonly subagents?: Readonly<Record<string, AgentDefinition>>;
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/sdk/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { z } from \"zod\";\n\nexport type HarnessKind = \"codex\" | \"claudeCode\" | \"fx\";\n\nexport interface CodexConfig {\n readonly kind: \"codex\";\n readonly model: string;\n readonly effort?: string;\n readonly fast: boolean;\n}\n\nexport interface ClaudeCodeConfig {\n readonly kind: \"claudeCode\";\n readonly model: string;\n readonly effort?: \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n readonly fast: boolean;\n}\n\nexport interface FxConfig {\n readonly kind: \"fx\";\n readonly model: string;\n readonly effort?: string;\n}\n\nexport type HarnessConfig = CodexConfig | ClaudeCodeConfig | (FxConfig & { readonly fast?: never });\n\nexport interface CodexOptions {\n readonly model: string;\n readonly effort?: string;\n readonly fast?: boolean;\n}\n\nexport interface ClaudeCodeOptions {\n readonly model: string;\n readonly effort?: \"low\" | \"medium\" | \"high\" | \"xhigh\" | \"max\";\n readonly fast?: boolean;\n}\n\nexport interface FxOptions {\n readonly model: string;\n readonly effort?: string;\n}\n\nexport interface ToolDefinition<S extends z.ZodObject = z.ZodObject> {\n readonly description: string;\n readonly inputSchema: S;\n readonly execute: (input: z.output<S>) => unknown | Promise<unknown>;\n}\n\nexport interface AgentDefinition {\n readonly name: string;\n readonly description: string;\n readonly instructions: string;\n readonly harness: HarnessConfig | readonly HarnessConfig[];\n readonly tools?: Readonly<Record<string, ToolDefinition<any>>>;\n readonly subagents?: Readonly<Record<string, AgentDefinition>>;\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare const namePattern: RegExp;
|
|
2
|
+
export declare function invalid(message: string): never;
|
|
3
|
+
export declare function object(value: unknown, fields?: readonly string[]): asserts value is Record<string, unknown>;
|
|
4
|
+
export declare function nonempty(value: unknown, label: string): asserts value is string;
|
|
5
|
+
export declare function validName(value: unknown): asserts value is string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { AgentError } from "../errors.js";
|
|
2
|
+
export const namePattern = /^[a-zA-Z][a-zA-Z0-9_-]{0,63}$/;
|
|
3
|
+
export function invalid(message) {
|
|
4
|
+
throw new AgentError("INVALID_DEFINITION", message);
|
|
5
|
+
}
|
|
6
|
+
export function object(value, fields) {
|
|
7
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
8
|
+
invalid("Expected a configuration object.");
|
|
9
|
+
if (fields && Object.keys(value).some((key) => !fields.includes(key)))
|
|
10
|
+
invalid("Unknown configuration field.");
|
|
11
|
+
}
|
|
12
|
+
export function nonempty(value, label) {
|
|
13
|
+
if (typeof value !== "string" || !value.trim())
|
|
14
|
+
invalid(`${label} must be a nonempty string.`);
|
|
15
|
+
}
|
|
16
|
+
export function validName(value) {
|
|
17
|
+
if (typeof value !== "string" || !namePattern.test(value))
|
|
18
|
+
invalid("Names must start with a letter and contain at most 64 letters, digits, underscores, or hyphens.");
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=validation.js.map
|