@orchagent/cli 0.3.41 → 0.3.43
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/adapters/agents-md.js +2 -2
- package/dist/adapters/claude-code.js +3 -3
- package/dist/adapters/cursor.js +2 -2
- package/dist/commands/agents.js +1 -1
- package/dist/commands/call.js +2 -2
- package/dist/commands/env.js +1 -1
- package/dist/commands/info.js +1 -1
- package/dist/commands/init.js +23 -24
- package/dist/commands/publish.js +46 -35
- package/dist/commands/run.js +24 -17
- package/dist/commands/test.js +2 -2
- package/dist/lib/api.js +5 -5
- package/dist/lib/bundle.js +11 -9
- package/dist/lib/output.js +1 -1
- package/package.json +1 -1
|
@@ -17,8 +17,8 @@ exports.agentsMdAdapter = {
|
|
|
17
17
|
canConvert(agent) {
|
|
18
18
|
const warnings = [];
|
|
19
19
|
const errors = [];
|
|
20
|
-
if (agent.type === '
|
|
21
|
-
errors.push('
|
|
20
|
+
if (agent.type === 'tool') {
|
|
21
|
+
errors.push('Tool agents cannot be converted to AGENTS.md');
|
|
22
22
|
return { canConvert: false, warnings, errors };
|
|
23
23
|
}
|
|
24
24
|
if (!agent.prompt) {
|
|
@@ -27,9 +27,9 @@ exports.claudeCodeAdapter = {
|
|
|
27
27
|
canConvert(agent) {
|
|
28
28
|
const warnings = [];
|
|
29
29
|
const errors = [];
|
|
30
|
-
//
|
|
31
|
-
if (agent.type === '
|
|
32
|
-
errors.push('
|
|
30
|
+
// Tool agents cannot be converted
|
|
31
|
+
if (agent.type === 'tool') {
|
|
32
|
+
errors.push('Tool agents cannot be converted to Claude Code sub-agents (they require execution)');
|
|
33
33
|
return { canConvert: false, warnings, errors };
|
|
34
34
|
}
|
|
35
35
|
// Check for prompt
|
package/dist/adapters/cursor.js
CHANGED
|
@@ -18,8 +18,8 @@ exports.cursorAdapter = {
|
|
|
18
18
|
canConvert(agent) {
|
|
19
19
|
const warnings = [];
|
|
20
20
|
const errors = [];
|
|
21
|
-
if (agent.type === '
|
|
22
|
-
errors.push('
|
|
21
|
+
if (agent.type === 'tool') {
|
|
22
|
+
errors.push('Tool agents cannot be converted to Cursor rules');
|
|
23
23
|
return { canConvert: false, warnings, errors };
|
|
24
24
|
}
|
|
25
25
|
if (!agent.prompt) {
|
package/dist/commands/agents.js
CHANGED
|
@@ -80,7 +80,7 @@ function registerAgentsCommand(program) {
|
|
|
80
80
|
filteredAgents.forEach((agent) => {
|
|
81
81
|
const name = agent.name;
|
|
82
82
|
const version = agent.version;
|
|
83
|
-
const type = agent.type || '
|
|
83
|
+
const type = agent.type || 'tool';
|
|
84
84
|
const stars = agent.stars_count ?? 0;
|
|
85
85
|
const price = (0, pricing_1.formatPrice)(agent);
|
|
86
86
|
const coloredPrice = (0, pricing_1.isPaidAgent)(agent) ? chalk_1.default.yellow(price) : chalk_1.default.green(price);
|
package/dist/commands/call.js
CHANGED
|
@@ -194,7 +194,7 @@ Note: Use 'call' for server-side execution (requires login), 'run' for local exe
|
|
|
194
194
|
File handling:
|
|
195
195
|
For prompt agents, file content is read and sent as JSON mapped to the agent's
|
|
196
196
|
input schema. Use --file-field to specify the field name (auto-detected by default).
|
|
197
|
-
For
|
|
197
|
+
For tools, files are uploaded as multipart form data.
|
|
198
198
|
|
|
199
199
|
Important: Remote agents cannot access your local filesystem. If your --data payload
|
|
200
200
|
contains keys like 'path', 'directory', 'file', etc., those values will be interpreted
|
|
@@ -438,7 +438,7 @@ Paid Agents:
|
|
|
438
438
|
headers['Content-Type'] = 'application/json';
|
|
439
439
|
}
|
|
440
440
|
else if (filePaths.length > 0 || options.metadata) {
|
|
441
|
-
//
|
|
441
|
+
// Tool: handle multipart file uploads
|
|
442
442
|
// Inject llm_credentials into metadata if available
|
|
443
443
|
let metadata = options.metadata;
|
|
444
444
|
if (llmCredentials) {
|
package/dist/commands/env.js
CHANGED
|
@@ -201,7 +201,7 @@ async function clearDefault(config, options) {
|
|
|
201
201
|
function registerEnvCommand(program) {
|
|
202
202
|
const env = program
|
|
203
203
|
.command('env')
|
|
204
|
-
.description('Manage custom Docker environments for
|
|
204
|
+
.description('Manage custom Docker environments for tools');
|
|
205
205
|
env
|
|
206
206
|
.command('list')
|
|
207
207
|
.description('List environments in workspace')
|
package/dist/commands/info.js
CHANGED
|
@@ -176,7 +176,7 @@ function registerInfoCommand(program) {
|
|
|
176
176
|
process.stdout.write(chalk_1.default.gray('Note: Paid agents run on server only (use orch call)\n'));
|
|
177
177
|
process.stdout.write(chalk_1.default.gray(' Owners can still download for development/testing\n'));
|
|
178
178
|
}
|
|
179
|
-
if (agentData.type === '
|
|
179
|
+
if (agentData.type === 'tool') {
|
|
180
180
|
// Don't show internal routing URLs - they confuse users
|
|
181
181
|
if (agentData.url && !agentData.url.includes('.internal')) {
|
|
182
182
|
process.stdout.write(`Server: ${agentData.url}\n`);
|
package/dist/commands/init.js
CHANGED
|
@@ -46,10 +46,10 @@ const SCHEMA_TEMPLATE = `{
|
|
|
46
46
|
}
|
|
47
47
|
`;
|
|
48
48
|
const CODE_TEMPLATE_PY = `"""
|
|
49
|
-
orchagent
|
|
49
|
+
orchagent tool entrypoint.
|
|
50
50
|
|
|
51
51
|
Reads JSON input from stdin, processes it, and writes JSON output to stdout.
|
|
52
|
-
This is the standard orchagent
|
|
52
|
+
This is the standard orchagent tool protocol.
|
|
53
53
|
|
|
54
54
|
Usage:
|
|
55
55
|
echo '{"input": "hello"}' | python main.py
|
|
@@ -82,12 +82,12 @@ if __name__ == "__main__":
|
|
|
82
82
|
main()
|
|
83
83
|
`;
|
|
84
84
|
function readmeTemplate(agentName, type) {
|
|
85
|
-
const callExample = type === '
|
|
85
|
+
const callExample = type === 'tool'
|
|
86
86
|
? `orchagent call ${agentName} input-file.txt`
|
|
87
|
-
: `orchagent call ${agentName} --data '{"${type === '
|
|
88
|
-
const runExample = type === '
|
|
87
|
+
: `orchagent call ${agentName} --data '{"${type === 'agent' ? 'task' : 'input'}": "Hello world"}'`;
|
|
88
|
+
const runExample = type === 'tool'
|
|
89
89
|
? `orchagent run ${agentName} --input '{"file_path": "src/app.py"}'`
|
|
90
|
-
: `orchagent run ${agentName} --input '{"${type === '
|
|
90
|
+
: `orchagent run ${agentName} --input '{"${type === 'agent' ? 'task' : 'input'}": "Hello world"}'`;
|
|
91
91
|
return `# ${agentName}
|
|
92
92
|
|
|
93
93
|
A brief description of what this agent does.
|
|
@@ -110,7 +110,7 @@ ${runExample}
|
|
|
110
110
|
|
|
111
111
|
| Field | Type | Description |
|
|
112
112
|
|-------|------|-------------|
|
|
113
|
-
|
|
|
113
|
+
| \`${type === 'agent' ? 'task' : 'input'}\` | string | ${type === 'agent' ? 'The task to perform' : 'The input to process'} |
|
|
114
114
|
|
|
115
115
|
## Output
|
|
116
116
|
|
|
@@ -119,13 +119,12 @@ ${runExample}
|
|
|
119
119
|
| \`result\` | string | The agent's response |
|
|
120
120
|
`;
|
|
121
121
|
}
|
|
122
|
-
const
|
|
122
|
+
const AGENT_MANIFEST_TEMPLATE = `{
|
|
123
123
|
"name": "my-agent",
|
|
124
|
-
"description": "An
|
|
125
|
-
"type": "
|
|
124
|
+
"description": "An AI agent with tool use",
|
|
125
|
+
"type": "agent",
|
|
126
126
|
"supported_providers": ["anthropic"],
|
|
127
127
|
"max_turns": 25,
|
|
128
|
-
"timeout_seconds": 300,
|
|
129
128
|
"custom_tools": [
|
|
130
129
|
{
|
|
131
130
|
"name": "run_tests",
|
|
@@ -135,7 +134,7 @@ const AGENTIC_MANIFEST_TEMPLATE = `{
|
|
|
135
134
|
]
|
|
136
135
|
}
|
|
137
136
|
`;
|
|
138
|
-
const
|
|
137
|
+
const AGENT_PROMPT_TEMPLATE = `You are a helpful AI agent with access to a sandboxed environment.
|
|
139
138
|
|
|
140
139
|
Given the input, complete the task using the available tools:
|
|
141
140
|
- Use bash to run commands
|
|
@@ -147,7 +146,7 @@ Input: The caller's input will be provided as JSON.
|
|
|
147
146
|
|
|
148
147
|
Work step by step, verify your results, and submit the final output.
|
|
149
148
|
`;
|
|
150
|
-
const
|
|
149
|
+
const AGENT_SCHEMA_TEMPLATE = `{
|
|
151
150
|
"input": {
|
|
152
151
|
"type": "object",
|
|
153
152
|
"properties": {
|
|
@@ -189,7 +188,7 @@ function registerInitCommand(program) {
|
|
|
189
188
|
.command('init')
|
|
190
189
|
.description('Initialize a new agent project')
|
|
191
190
|
.argument('[name]', 'Agent name (default: current directory name)')
|
|
192
|
-
.option('--type <type>', 'Type: prompt,
|
|
191
|
+
.option('--type <type>', 'Type: prompt, tool, agent, or skill (default: prompt)', 'prompt')
|
|
193
192
|
.action(async (name, options) => {
|
|
194
193
|
const cwd = process.cwd();
|
|
195
194
|
// When a name is provided, create a subdirectory for the project
|
|
@@ -243,20 +242,20 @@ function registerInitCommand(program) {
|
|
|
243
242
|
}
|
|
244
243
|
}
|
|
245
244
|
// Create manifest and type-specific files
|
|
246
|
-
if (options.type === '
|
|
247
|
-
const manifest = JSON.parse(
|
|
245
|
+
if (options.type === 'agent') {
|
|
246
|
+
const manifest = JSON.parse(AGENT_MANIFEST_TEMPLATE);
|
|
248
247
|
manifest.name = agentName;
|
|
249
248
|
await promises_1.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
250
|
-
await promises_1.default.writeFile(promptPath,
|
|
251
|
-
await promises_1.default.writeFile(schemaPath,
|
|
249
|
+
await promises_1.default.writeFile(promptPath, AGENT_PROMPT_TEMPLATE);
|
|
250
|
+
await promises_1.default.writeFile(schemaPath, AGENT_SCHEMA_TEMPLATE);
|
|
252
251
|
}
|
|
253
252
|
else {
|
|
254
253
|
const manifest = JSON.parse(MANIFEST_TEMPLATE);
|
|
255
254
|
manifest.name = agentName;
|
|
256
|
-
manifest.type = ['
|
|
255
|
+
manifest.type = ['tool', 'skill'].includes(options.type) ? options.type : 'prompt';
|
|
257
256
|
await promises_1.default.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
258
|
-
// Create prompt template (for prompt-based agents) or entrypoint (for
|
|
259
|
-
if (options.type === '
|
|
257
|
+
// Create prompt template (for prompt-based agents) or entrypoint (for tool agents)
|
|
258
|
+
if (options.type === 'tool') {
|
|
260
259
|
const entrypointPath = path_1.default.join(targetDir, 'main.py');
|
|
261
260
|
await promises_1.default.writeFile(entrypointPath, CODE_TEMPLATE_PY);
|
|
262
261
|
}
|
|
@@ -273,7 +272,7 @@ function registerInitCommand(program) {
|
|
|
273
272
|
process.stdout.write(`\nFiles created:\n`);
|
|
274
273
|
const prefix = name ? name + '/' : '';
|
|
275
274
|
process.stdout.write(` ${prefix}orchagent.json - Agent configuration\n`);
|
|
276
|
-
if (options.type === '
|
|
275
|
+
if (options.type === 'tool') {
|
|
277
276
|
process.stdout.write(` ${prefix}main.py - Agent entrypoint (stdin/stdout JSON)\n`);
|
|
278
277
|
}
|
|
279
278
|
else {
|
|
@@ -282,7 +281,7 @@ function registerInitCommand(program) {
|
|
|
282
281
|
process.stdout.write(` ${prefix}schema.json - Input/output schemas\n`);
|
|
283
282
|
process.stdout.write(` ${prefix}README.md - Agent documentation\n`);
|
|
284
283
|
process.stdout.write(`\nNext steps:\n`);
|
|
285
|
-
if (options.type === '
|
|
284
|
+
if (options.type === 'agent') {
|
|
286
285
|
const stepNum = name ? 2 : 1;
|
|
287
286
|
if (name) {
|
|
288
287
|
process.stdout.write(` 1. cd ${name}\n`);
|
|
@@ -292,7 +291,7 @@ function registerInitCommand(program) {
|
|
|
292
291
|
process.stdout.write(` ${stepNum + 2}. Edit schema.json with your input/output schemas\n`);
|
|
293
292
|
process.stdout.write(` ${stepNum + 3}. Run: orchagent publish\n`);
|
|
294
293
|
}
|
|
295
|
-
else if (options.type !== '
|
|
294
|
+
else if (options.type !== 'tool') {
|
|
296
295
|
const stepNum = name ? 2 : 1;
|
|
297
296
|
if (name) {
|
|
298
297
|
process.stdout.write(` 1. cd ${name}\n`);
|
package/dist/commands/publish.js
CHANGED
|
@@ -317,7 +317,7 @@ function registerPublishCommand(program) {
|
|
|
317
317
|
`These must be nested under a "manifest" key. Example:\n\n` +
|
|
318
318
|
` {\n` +
|
|
319
319
|
` "name": "${manifest.name}",\n` +
|
|
320
|
-
` "type": "${manifest.type || '
|
|
320
|
+
` "type": "${manifest.type || 'tool'}",\n` +
|
|
321
321
|
` "manifest": {\n` +
|
|
322
322
|
` "manifest_version": 1,\n` +
|
|
323
323
|
` "dependencies": [...],\n` +
|
|
@@ -328,16 +328,16 @@ function registerPublishCommand(program) {
|
|
|
328
328
|
` }\n\n` +
|
|
329
329
|
`See docs/manifest.md for details.`);
|
|
330
330
|
}
|
|
331
|
-
// Read prompt (for prompt-based,
|
|
331
|
+
// Read prompt (for prompt-based, agent, and skill agents)
|
|
332
332
|
let prompt;
|
|
333
|
-
if (manifest.type === 'prompt' || manifest.type === 'skill' || manifest.type === '
|
|
333
|
+
if (manifest.type === 'prompt' || manifest.type === 'skill' || manifest.type === 'agent') {
|
|
334
334
|
const promptPath = path_1.default.join(cwd, 'prompt.md');
|
|
335
335
|
try {
|
|
336
336
|
prompt = await promises_1.default.readFile(promptPath, 'utf-8');
|
|
337
337
|
}
|
|
338
338
|
catch (err) {
|
|
339
339
|
if (err.code === 'ENOENT') {
|
|
340
|
-
const agentTypeName = manifest.type === 'skill' ? 'skill' : manifest.type === '
|
|
340
|
+
const agentTypeName = manifest.type === 'skill' ? 'skill' : manifest.type === 'agent' ? 'agent' : 'prompt-based agent';
|
|
341
341
|
throw new errors_1.CliError(`No prompt.md found for ${agentTypeName}.\n\n` +
|
|
342
342
|
'Create a prompt.md file in the current directory with your prompt template.\n' +
|
|
343
343
|
'See: https://orchagent.io/docs/publishing');
|
|
@@ -345,15 +345,25 @@ function registerPublishCommand(program) {
|
|
|
345
345
|
throw err;
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
|
-
// For
|
|
349
|
-
if (manifest.type === '
|
|
348
|
+
// For agent type, validate custom_tools and build manifest
|
|
349
|
+
if (manifest.type === 'agent') {
|
|
350
350
|
// Validate custom_tools format
|
|
351
351
|
if (manifest.custom_tools) {
|
|
352
|
+
const reservedNames = new Set(['bash', 'read_file', 'write_file', 'list_files', 'submit_result']);
|
|
353
|
+
const seenNames = new Set();
|
|
352
354
|
for (const tool of manifest.custom_tools) {
|
|
353
355
|
if (!tool.name || !tool.command) {
|
|
354
356
|
throw new errors_1.CliError(`Invalid custom_tool: each tool must have 'name' and 'command' fields.\n` +
|
|
355
357
|
`Found: ${JSON.stringify(tool)}`);
|
|
356
358
|
}
|
|
359
|
+
if (reservedNames.has(tool.name)) {
|
|
360
|
+
throw new errors_1.CliError(`Custom tool '${tool.name}' conflicts with a built-in tool name.\n` +
|
|
361
|
+
`Reserved names: ${[...reservedNames].join(', ')}`);
|
|
362
|
+
}
|
|
363
|
+
if (seenNames.has(tool.name)) {
|
|
364
|
+
throw new errors_1.CliError(`Duplicate custom tool name: '${tool.name}'`);
|
|
365
|
+
}
|
|
366
|
+
seenNames.add(tool.name);
|
|
357
367
|
}
|
|
358
368
|
}
|
|
359
369
|
// Validate max_turns
|
|
@@ -362,18 +372,18 @@ function registerPublishCommand(program) {
|
|
|
362
372
|
throw new errors_1.CliError('max_turns must be a number between 1 and 50');
|
|
363
373
|
}
|
|
364
374
|
}
|
|
365
|
-
// Store
|
|
366
|
-
const
|
|
375
|
+
// Store agent config in manifest field
|
|
376
|
+
const agentManifest = {
|
|
367
377
|
...(manifest.manifest || {}),
|
|
368
378
|
};
|
|
369
379
|
if (manifest.custom_tools) {
|
|
370
|
-
|
|
380
|
+
agentManifest.custom_tools = manifest.custom_tools;
|
|
371
381
|
}
|
|
372
382
|
if (manifest.max_turns) {
|
|
373
|
-
|
|
383
|
+
agentManifest.max_turns = manifest.max_turns;
|
|
374
384
|
}
|
|
375
|
-
manifest.manifest =
|
|
376
|
-
//
|
|
385
|
+
manifest.manifest = agentManifest;
|
|
386
|
+
// Agent type defaults to anthropic provider
|
|
377
387
|
if (!manifest.supported_providers) {
|
|
378
388
|
manifest.supported_providers = ['anthropic'];
|
|
379
389
|
}
|
|
@@ -397,7 +407,7 @@ function registerPublishCommand(program) {
|
|
|
397
407
|
}
|
|
398
408
|
}
|
|
399
409
|
// For prompt/skill agents, derive input schema from template variables if needed
|
|
400
|
-
// (
|
|
410
|
+
// (Agent type uses schema.json directly — no template variable derivation)
|
|
401
411
|
if (prompt && (manifest.type === 'prompt' || manifest.type === 'skill')) {
|
|
402
412
|
const templateVars = extractTemplateVariables(prompt);
|
|
403
413
|
if (templateVars.length > 0) {
|
|
@@ -424,13 +434,13 @@ function registerPublishCommand(program) {
|
|
|
424
434
|
}
|
|
425
435
|
}
|
|
426
436
|
}
|
|
427
|
-
// For
|
|
428
|
-
// For
|
|
437
|
+
// For tool-based agents, either --url is required OR we bundle the code
|
|
438
|
+
// For agent type, use internal placeholder (no user code, platform handles execution)
|
|
429
439
|
let agentUrl = options.url;
|
|
430
440
|
let shouldUploadBundle = false;
|
|
431
|
-
if (manifest.type === '
|
|
432
|
-
//
|
|
433
|
-
agentUrl = agentUrl || 'https://
|
|
441
|
+
if (manifest.type === 'agent') {
|
|
442
|
+
// Agent type doesn't need a URL or code bundle
|
|
443
|
+
agentUrl = agentUrl || 'https://agent.internal';
|
|
434
444
|
// But they can include a Dockerfile for custom environments
|
|
435
445
|
if (options.docker) {
|
|
436
446
|
const dockerfilePath = path_1.default.join(cwd, 'Dockerfile');
|
|
@@ -444,27 +454,27 @@ function registerPublishCommand(program) {
|
|
|
444
454
|
}
|
|
445
455
|
}
|
|
446
456
|
}
|
|
447
|
-
else if (manifest.type === '
|
|
457
|
+
else if (manifest.type === 'tool' && !options.url) {
|
|
448
458
|
// Check if this looks like a Python or JS project that can be bundled
|
|
449
459
|
const entrypoint = manifest.entrypoint || await (0, bundle_1.detectEntrypoint)(cwd);
|
|
450
460
|
if (entrypoint) {
|
|
451
|
-
// This is a hosted
|
|
461
|
+
// This is a hosted tool - we'll bundle and upload
|
|
452
462
|
shouldUploadBundle = true;
|
|
453
463
|
// Set a placeholder URL that tells the gateway to use sandbox execution
|
|
454
|
-
agentUrl = 'https://
|
|
455
|
-
process.stdout.write(`Detected
|
|
464
|
+
agentUrl = 'https://tool.internal';
|
|
465
|
+
process.stdout.write(`Detected tool project with entrypoint: ${entrypoint}\n`);
|
|
456
466
|
}
|
|
457
467
|
else {
|
|
458
|
-
throw new errors_1.CliError('
|
|
468
|
+
throw new errors_1.CliError('Tool requires either --url <url> or an entry point file (main.py, app.py, index.js, etc.)');
|
|
459
469
|
}
|
|
460
470
|
}
|
|
461
471
|
// Get org info
|
|
462
472
|
const org = await (0, api_1.getOrg)(config);
|
|
463
473
|
// Default to 'any' provider if not specified
|
|
464
474
|
const supportedProviders = manifest.supported_providers || ['any'];
|
|
465
|
-
// Detect SDK compatibility for
|
|
475
|
+
// Detect SDK compatibility for tool agents
|
|
466
476
|
let sdkCompatible = false;
|
|
467
|
-
if (manifest.type === '
|
|
477
|
+
if (manifest.type === 'tool') {
|
|
468
478
|
sdkCompatible = await detectSdkCompatible(cwd);
|
|
469
479
|
if (sdkCompatible && !options.dryRun) {
|
|
470
480
|
process.stdout.write(`SDK detected - agent will be marked as Local Ready\n`);
|
|
@@ -492,8 +502,8 @@ function registerPublishCommand(program) {
|
|
|
492
502
|
process.stderr.write(` ✓ Input schema derived from template variables: ${vars.join(', ')}\n`);
|
|
493
503
|
}
|
|
494
504
|
}
|
|
495
|
-
else if (manifest.type === '
|
|
496
|
-
//
|
|
505
|
+
else if (manifest.type === 'agent') {
|
|
506
|
+
// Agent type validations
|
|
497
507
|
const promptBytes = prompt ? Buffer.byteLength(prompt, 'utf-8') : 0;
|
|
498
508
|
process.stderr.write(` ✓ prompt.md found (${promptBytes.toLocaleString()} bytes)\n`);
|
|
499
509
|
if (schemaFromFile) {
|
|
@@ -504,8 +514,8 @@ function registerPublishCommand(program) {
|
|
|
504
514
|
process.stderr.write(` ✓ Custom tools: ${customToolCount}\n`);
|
|
505
515
|
process.stderr.write(` ✓ Max turns: ${manifest.max_turns || 25}\n`);
|
|
506
516
|
}
|
|
507
|
-
else if (manifest.type === '
|
|
508
|
-
//
|
|
517
|
+
else if (manifest.type === 'tool') {
|
|
518
|
+
// Tool agent validations
|
|
509
519
|
const entrypoint = manifest.entrypoint || await (0, bundle_1.detectEntrypoint)(cwd);
|
|
510
520
|
process.stderr.write(` ✓ Entrypoint: ${entrypoint}\n`);
|
|
511
521
|
if (sdkCompatible) {
|
|
@@ -513,7 +523,7 @@ function registerPublishCommand(program) {
|
|
|
513
523
|
}
|
|
514
524
|
}
|
|
515
525
|
process.stderr.write(` ✓ Authentication valid (org: ${org.slug})\n`);
|
|
516
|
-
// For
|
|
526
|
+
// For tools with bundles, show bundle preview
|
|
517
527
|
if (shouldUploadBundle) {
|
|
518
528
|
const bundlePreview = await (0, bundle_1.previewBundle)(cwd, {
|
|
519
529
|
entrypoint: manifest.entrypoint,
|
|
@@ -567,7 +577,7 @@ function registerPublishCommand(program) {
|
|
|
567
577
|
is_public: options.public ? true : false,
|
|
568
578
|
supported_providers: supportedProviders,
|
|
569
579
|
default_models: manifest.default_models,
|
|
570
|
-
// Local run fields for
|
|
580
|
+
// Local run fields for tool agents
|
|
571
581
|
source_url: manifest.source_url,
|
|
572
582
|
pip_package: manifest.pip_package,
|
|
573
583
|
run_command: manifest.run_command,
|
|
@@ -585,7 +595,7 @@ function registerPublishCommand(program) {
|
|
|
585
595
|
}
|
|
586
596
|
const assignedVersion = result.agent?.version || 'v1';
|
|
587
597
|
const agentId = result.agent?.id;
|
|
588
|
-
// Upload code bundle if this is a hosted
|
|
598
|
+
// Upload code bundle if this is a hosted tool agent or agent type with --docker
|
|
589
599
|
if (shouldUploadBundle && agentId) {
|
|
590
600
|
process.stdout.write(`\nBundling code...\n`);
|
|
591
601
|
const tempDir = await promises_1.default.mkdtemp(path_1.default.join(os_1.default.tmpdir(), 'orchagent-bundle-'));
|
|
@@ -604,8 +614,8 @@ function registerPublishCommand(program) {
|
|
|
604
614
|
throw new errors_1.CliError('--docker flag specified but no Dockerfile found in project directory');
|
|
605
615
|
}
|
|
606
616
|
}
|
|
607
|
-
// For
|
|
608
|
-
if (manifest.type === '
|
|
617
|
+
// For agent type, also include requirements.txt if present
|
|
618
|
+
if (manifest.type === 'agent') {
|
|
609
619
|
const reqPath = path_1.default.join(cwd, 'requirements.txt');
|
|
610
620
|
try {
|
|
611
621
|
await promises_1.default.access(reqPath);
|
|
@@ -617,9 +627,10 @@ function registerPublishCommand(program) {
|
|
|
617
627
|
}
|
|
618
628
|
}
|
|
619
629
|
const bundleResult = await (0, bundle_1.createCodeBundle)(cwd, bundlePath, {
|
|
620
|
-
entrypoint: manifest.type === '
|
|
630
|
+
entrypoint: manifest.type === 'agent' ? undefined : manifest.entrypoint,
|
|
621
631
|
exclude: manifest.bundle?.exclude,
|
|
622
632
|
include: includePatterns.length > 0 ? includePatterns : undefined,
|
|
633
|
+
skipEntrypointCheck: manifest.type === 'agent',
|
|
623
634
|
});
|
|
624
635
|
process.stdout.write(` Created bundle: ${bundleResult.fileCount} files, ${(bundleResult.sizeBytes / 1024).toFixed(1)}KB\n`);
|
|
625
636
|
// Validate bundle size
|
package/dist/commands/run.js
CHANGED
|
@@ -269,9 +269,9 @@ async function downloadDependenciesRecursively(config, depStatuses, visited = ne
|
|
|
269
269
|
if (status.agentData.has_bundle) {
|
|
270
270
|
await saveBundleLocally(config, org, agent, status.dep.version, status.agentData.id);
|
|
271
271
|
}
|
|
272
|
-
// Install if it's a pip/source
|
|
273
|
-
if (status.agentData.type === '
|
|
274
|
-
await
|
|
272
|
+
// Install if it's a pip/source tool agent
|
|
273
|
+
if (status.agentData.type === 'tool' && (status.agentData.source_url || status.agentData.pip_package)) {
|
|
274
|
+
await installTool(status.agentData);
|
|
275
275
|
}
|
|
276
276
|
}, { successText: `Downloaded ${depRef}` });
|
|
277
277
|
// Download default skills
|
|
@@ -476,10 +476,10 @@ async function checkPackageInstalled(packageName) {
|
|
|
476
476
|
return false;
|
|
477
477
|
}
|
|
478
478
|
}
|
|
479
|
-
async function
|
|
479
|
+
async function installTool(agentData) {
|
|
480
480
|
const installSource = agentData.pip_package || agentData.source_url;
|
|
481
481
|
if (!installSource) {
|
|
482
|
-
throw new errors_1.CliError('This
|
|
482
|
+
throw new errors_1.CliError('This tool does not support local execution.\n' +
|
|
483
483
|
'Use `orch call` to run it on the server instead.');
|
|
484
484
|
}
|
|
485
485
|
// Check if already installed (for pip packages)
|
|
@@ -503,13 +503,13 @@ async function installCodeAgent(agentData) {
|
|
|
503
503
|
}
|
|
504
504
|
}, { successText: 'Installation complete' });
|
|
505
505
|
}
|
|
506
|
-
async function
|
|
506
|
+
async function executeTool(agentData, args) {
|
|
507
507
|
if (!agentData.run_command) {
|
|
508
|
-
throw new errors_1.CliError('This
|
|
508
|
+
throw new errors_1.CliError('This tool does not have a run command defined.\n' +
|
|
509
509
|
'Use `orch call` to run it on the server instead.');
|
|
510
510
|
}
|
|
511
511
|
// Install the agent if needed
|
|
512
|
-
await
|
|
512
|
+
await installTool(agentData);
|
|
513
513
|
// Parse the run command and append user args
|
|
514
514
|
const [cmd, ...cmdArgs] = agentData.run_command.split(' ');
|
|
515
515
|
const fullArgs = [...cmdArgs, ...args];
|
|
@@ -760,7 +760,7 @@ async function saveAgentLocally(org, agent, agentData) {
|
|
|
760
760
|
if (agentData.type === 'prompt' && agentData.prompt) {
|
|
761
761
|
await promises_1.default.writeFile(path_1.default.join(agentDir, 'prompt.md'), agentData.prompt);
|
|
762
762
|
}
|
|
763
|
-
// For
|
|
763
|
+
// For tools, save files if provided
|
|
764
764
|
if (agentData.files) {
|
|
765
765
|
for (const file of agentData.files) {
|
|
766
766
|
const filePath = path_1.default.join(agentDir, file.path);
|
|
@@ -887,7 +887,7 @@ Paid Agents:
|
|
|
887
887
|
// Fall back to getting public agent info if download endpoint not available
|
|
888
888
|
const agentMeta = await (0, api_1.getPublicAgent)(resolved, org, parsed.agent, parsed.version);
|
|
889
889
|
return {
|
|
890
|
-
type: agentMeta.type || '
|
|
890
|
+
type: agentMeta.type || 'tool',
|
|
891
891
|
name: agentMeta.name,
|
|
892
892
|
version: agentMeta.version,
|
|
893
893
|
description: agentMeta.description || undefined,
|
|
@@ -903,6 +903,13 @@ Paid Agents:
|
|
|
903
903
|
` Install for AI tools: orchagent skill install ${org}/${parsed.agent}\n` +
|
|
904
904
|
` Use with an agent: orchagent run <agent> --skills ${org}/${parsed.agent}`);
|
|
905
905
|
}
|
|
906
|
+
// Agent type requires a sandbox with tool use — cannot run locally
|
|
907
|
+
if (agentData.type === 'agent') {
|
|
908
|
+
throw new errors_1.CliError('Agent type cannot be run locally.\n\n' +
|
|
909
|
+
'Agent type requires a sandbox environment with tool use capabilities.\n\n' +
|
|
910
|
+
'Use server execution instead:\n' +
|
|
911
|
+
` orchagent call ${org}/${parsed.agent}@${parsed.version} --data '{"task": "..."}'`);
|
|
912
|
+
}
|
|
906
913
|
// Check for dependencies (orchestrator agents)
|
|
907
914
|
if (agentData.dependencies && agentData.dependencies.length > 0) {
|
|
908
915
|
const depStatuses = await (0, spinner_1.withSpinner)('Checking dependencies...', async () => checkDependencies(resolved, agentData.dependencies), { successText: `Found ${agentData.dependencies.length} dependencies` });
|
|
@@ -946,31 +953,31 @@ Paid Agents:
|
|
|
946
953
|
// Save locally
|
|
947
954
|
const agentDir = await saveAgentLocally(org, parsed.agent, agentData);
|
|
948
955
|
process.stderr.write(`\nAgent saved to: ${agentDir}\n`);
|
|
949
|
-
if (agentData.type === '
|
|
956
|
+
if (agentData.type === 'tool') {
|
|
950
957
|
// Check if this agent has a bundle available for local execution
|
|
951
958
|
if (agentData.has_bundle) {
|
|
952
959
|
if (options.downloadOnly) {
|
|
953
|
-
process.stdout.write(`\
|
|
960
|
+
process.stdout.write(`\nTool has bundle available for local execution.\n`);
|
|
954
961
|
process.stdout.write(`Run with: orch run ${org}/${parsed.agent} [args...]\n`);
|
|
955
962
|
return;
|
|
956
963
|
}
|
|
957
|
-
// Execute the bundle-based
|
|
964
|
+
// Execute the bundle-based tool locally
|
|
958
965
|
await executeBundleAgent(resolved, org, parsed.agent, parsed.version, agentData, args, options.input);
|
|
959
966
|
return;
|
|
960
967
|
}
|
|
961
968
|
// Check for pip/source-based local execution (legacy)
|
|
962
969
|
if (agentData.run_command && (agentData.source_url || agentData.pip_package)) {
|
|
963
970
|
if (options.downloadOnly) {
|
|
964
|
-
process.stdout.write(`\
|
|
971
|
+
process.stdout.write(`\nTool ready for local execution.\n`);
|
|
965
972
|
process.stdout.write(`Run with: orch run ${org}/${parsed.agent} [args...]\n`);
|
|
966
973
|
return;
|
|
967
974
|
}
|
|
968
|
-
// Execute the
|
|
969
|
-
await
|
|
975
|
+
// Execute the tool locally
|
|
976
|
+
await executeTool(agentData, args);
|
|
970
977
|
return;
|
|
971
978
|
}
|
|
972
979
|
// Fallback: agent doesn't support local execution
|
|
973
|
-
process.stdout.write(`\nThis is a
|
|
980
|
+
process.stdout.write(`\nThis is a tool-based agent that runs on the server.\n`);
|
|
974
981
|
process.stdout.write(`\nUse: orch call ${org}/${parsed.agent}@${parsed.version} --input '{...}'\n`);
|
|
975
982
|
return;
|
|
976
983
|
}
|
package/dist/commands/test.js
CHANGED
|
@@ -138,7 +138,7 @@ async function detectAgentType(agentDir) {
|
|
|
138
138
|
return 'prompt';
|
|
139
139
|
if (manifest.type === 'skill')
|
|
140
140
|
return 'skill';
|
|
141
|
-
if (manifest.type === '
|
|
141
|
+
if (manifest.type === 'tool') {
|
|
142
142
|
// Detect language
|
|
143
143
|
if (await fileExists(path_1.default.join(agentDir, 'requirements.txt')))
|
|
144
144
|
return 'code-python';
|
|
@@ -146,7 +146,7 @@ async function detectAgentType(agentDir) {
|
|
|
146
146
|
return 'code-python';
|
|
147
147
|
if (await fileExists(path_1.default.join(agentDir, 'package.json')))
|
|
148
148
|
return 'code-js';
|
|
149
|
-
// Default to Python for
|
|
149
|
+
// Default to Python for tool agents
|
|
150
150
|
return 'code-python';
|
|
151
151
|
}
|
|
152
152
|
}
|
package/dist/lib/api.js
CHANGED
|
@@ -299,12 +299,12 @@ async function searchMyAgents(config, query, options) {
|
|
|
299
299
|
if (options?.type) {
|
|
300
300
|
const typeFilter = options.type;
|
|
301
301
|
if (typeFilter === 'agents') {
|
|
302
|
-
agents = agents.filter(a => a.type === 'prompt' || a.type === '
|
|
302
|
+
agents = agents.filter(a => a.type === 'prompt' || a.type === 'tool');
|
|
303
303
|
}
|
|
304
304
|
else if (typeFilter === 'skills' || typeFilter === 'skill') {
|
|
305
305
|
agents = agents.filter(a => a.type === 'skill');
|
|
306
306
|
}
|
|
307
|
-
else if (typeFilter === '
|
|
307
|
+
else if (typeFilter === 'tool' || typeFilter === 'prompt') {
|
|
308
308
|
agents = agents.filter(a => a.type === typeFilter);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
@@ -342,7 +342,7 @@ async function fetchLlmKeys(config) {
|
|
|
342
342
|
return result.keys;
|
|
343
343
|
}
|
|
344
344
|
/**
|
|
345
|
-
* Download a
|
|
345
|
+
* Download a tool bundle for local execution.
|
|
346
346
|
*/
|
|
347
347
|
async function downloadCodeBundle(config, org, agent, version) {
|
|
348
348
|
const response = await safeFetch(`${config.apiUrl.replace(/\/$/, '')}/public/agents/${org}/${agent}/${version}/bundle`);
|
|
@@ -353,7 +353,7 @@ async function downloadCodeBundle(config, org, agent, version) {
|
|
|
353
353
|
return Buffer.from(arrayBuffer);
|
|
354
354
|
}
|
|
355
355
|
/**
|
|
356
|
-
* Upload a code bundle for a hosted
|
|
356
|
+
* Upload a code bundle for a hosted tool agent.
|
|
357
357
|
*/
|
|
358
358
|
async function uploadCodeBundle(config, agentId, bundlePath, entrypoint) {
|
|
359
359
|
if (!config.apiKey) {
|
|
@@ -421,7 +421,7 @@ async function getAgentWithFallback(config, org, agentName, version) {
|
|
|
421
421
|
return myAgent;
|
|
422
422
|
}
|
|
423
423
|
/**
|
|
424
|
-
* Download a
|
|
424
|
+
* Download a tool bundle for a private agent using authenticated endpoint.
|
|
425
425
|
*/
|
|
426
426
|
async function downloadCodeBundleAuthenticated(config, agentId) {
|
|
427
427
|
if (!config.apiKey) {
|
package/dist/lib/bundle.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Code bundling utilities for hosted
|
|
3
|
+
* Code bundling utilities for hosted tools.
|
|
4
4
|
*
|
|
5
5
|
* Creates zip bundles from project directories for upload to orchagent.
|
|
6
6
|
*/
|
|
@@ -119,14 +119,16 @@ async function createCodeBundle(sourceDir, outputPath, options = {}) {
|
|
|
119
119
|
if (!stat.isDirectory()) {
|
|
120
120
|
throw new Error(`Source path is not a directory: ${sourceDir}`);
|
|
121
121
|
}
|
|
122
|
-
// Verify entrypoint exists if specified
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
122
|
+
// Verify entrypoint exists if specified (skip for agent type that has no code)
|
|
123
|
+
if (!options.skipEntrypointCheck) {
|
|
124
|
+
const entrypoint = options.entrypoint || 'main.py';
|
|
125
|
+
const entrypointPath = path_1.default.join(sourceDir, entrypoint);
|
|
126
|
+
try {
|
|
127
|
+
await promises_1.default.access(entrypointPath);
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
throw new Error(`Entrypoint file not found: ${entrypoint}`);
|
|
131
|
+
}
|
|
130
132
|
}
|
|
131
133
|
// Create output directory if needed
|
|
132
134
|
const outputDir = path_1.default.dirname(outputPath);
|
package/dist/lib/output.js
CHANGED
|
@@ -24,7 +24,7 @@ function printAgentsTable(agents, options) {
|
|
|
24
24
|
const table = new cli_table3_1.default({ head });
|
|
25
25
|
agents.forEach((agent) => {
|
|
26
26
|
const fullName = `${agent.org_slug}/${agent.name}`;
|
|
27
|
-
const type = agent.type || '
|
|
27
|
+
const type = agent.type || 'tool';
|
|
28
28
|
const providers = formatProviders(agent.supported_providers);
|
|
29
29
|
const stars = agent.stars_count ?? 0;
|
|
30
30
|
const price = (0, pricing_1.formatPrice)(agent);
|