@orchagent/cli 0.3.100 → 0.3.102
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/commands/agent-keys.js +5 -9
- package/dist/commands/diff.js +4 -2
- package/dist/commands/docs.js +6 -1
- package/dist/commands/fork.js +2 -1
- package/dist/commands/init.js +28 -25
- package/dist/commands/install.js +18 -30
- package/dist/commands/logs.js +3 -1
- package/dist/commands/publish.js +117 -4
- package/dist/commands/pull.js +27 -39
- package/dist/commands/replay.js +40 -7
- package/dist/commands/run.js +60 -96
- package/dist/commands/schedule.js +39 -5
- package/dist/commands/security.js +9 -25
- package/dist/commands/templates/cron-job.js +1 -1
- package/dist/commands/templates/github-weekly-summary.js +1 -1
- package/dist/commands/test.js +2 -2
- package/dist/commands/transfer.js +15 -5
- package/dist/commands/tree.js +15 -3
- package/dist/commands/validate.js +9 -0
- package/dist/lib/bundle.js +7 -1
- package/dist/lib/llm.js +37 -1
- package/dist/lib/resolve-agent.js +62 -0
- package/package.json +1 -1
package/dist/commands/pull.js
CHANGED
|
@@ -12,21 +12,10 @@ const child_process_1 = require("child_process");
|
|
|
12
12
|
const config_1 = require("../lib/config");
|
|
13
13
|
const api_1 = require("../lib/api");
|
|
14
14
|
const errors_1 = require("../lib/errors");
|
|
15
|
+
const resolve_agent_1 = require("../lib/resolve-agent");
|
|
15
16
|
const analytics_1 = require("../lib/analytics");
|
|
16
17
|
const output_1 = require("../lib/output");
|
|
17
18
|
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
18
|
-
function parsePullRef(value) {
|
|
19
|
-
const [ref, versionPart] = value.split('@');
|
|
20
|
-
const version = versionPart?.trim() || 'latest';
|
|
21
|
-
const segments = ref.split('/');
|
|
22
|
-
if (segments.length === 1) {
|
|
23
|
-
return { agent: segments[0], version };
|
|
24
|
-
}
|
|
25
|
-
if (segments.length === 2) {
|
|
26
|
-
return { org: segments[0], agent: segments[1], version };
|
|
27
|
-
}
|
|
28
|
-
throw new errors_1.CliError('Invalid agent reference. Use org/agent[@version] or agent[@version] format.');
|
|
29
|
-
}
|
|
30
19
|
function canonicalType(typeValue) {
|
|
31
20
|
const normalized = (typeValue || 'agent').toLowerCase();
|
|
32
21
|
if (['prompt', 'tool', 'agent', 'skill'].includes(normalized))
|
|
@@ -123,11 +112,14 @@ async function resolveAgent(config, org, agent, version, workspaceId) {
|
|
|
123
112
|
if (!config.apiKey) {
|
|
124
113
|
throw new api_1.ApiError(`Agent '${org}/${agent}@${version}' not found`, 404);
|
|
125
114
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
115
|
+
// Try workspace-scoped search first, then fall back to personal org.
|
|
116
|
+
// This handles the case where the user is in a team workspace but the
|
|
117
|
+
// agent lives in their personal org (or vice versa). The org_slug
|
|
118
|
+
// filter inside resolveFromMyAgents prevents cross-org contamination.
|
|
119
|
+
let data = await resolveFromMyAgents(config, agent, version, org, workspaceId);
|
|
120
|
+
if (!data && workspaceId) {
|
|
121
|
+
data = await resolveFromMyAgents(config, agent, version, org, undefined);
|
|
129
122
|
}
|
|
130
|
-
const data = await resolveFromMyAgents(config, agent, version, org, workspaceId);
|
|
131
123
|
if (!data) {
|
|
132
124
|
throw new api_1.ApiError(`Agent '${org}/${agent}@${version}' not found`, 404);
|
|
133
125
|
}
|
|
@@ -135,15 +127,10 @@ async function resolveAgent(config, org, agent, version, workspaceId) {
|
|
|
135
127
|
}
|
|
136
128
|
async function tryOwnerFallback(config, org, agent, version, workspaceId) {
|
|
137
129
|
try {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
match =
|
|
142
|
-
.filter(a => a.name === agent && a.org_slug === org)
|
|
143
|
-
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
match = myAgents.find(a => a.name === agent && a.version === version && a.org_slug === org);
|
|
130
|
+
let match = findOwnerMatch(await (0, api_1.listMyAgents)(config, workspaceId), agent, version, org);
|
|
131
|
+
// Retry without workspace restriction to find agents in personal org
|
|
132
|
+
if (!match && workspaceId) {
|
|
133
|
+
match = findOwnerMatch(await (0, api_1.listMyAgents)(config, undefined), agent, version, org);
|
|
147
134
|
}
|
|
148
135
|
if (!match)
|
|
149
136
|
return null;
|
|
@@ -154,6 +141,14 @@ async function tryOwnerFallback(config, org, agent, version, workspaceId) {
|
|
|
154
141
|
return null;
|
|
155
142
|
}
|
|
156
143
|
}
|
|
144
|
+
function findOwnerMatch(agents, agent, version, org) {
|
|
145
|
+
if (version === 'latest') {
|
|
146
|
+
return agents
|
|
147
|
+
.filter(a => a.name === agent && a.org_slug === org)
|
|
148
|
+
.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())[0];
|
|
149
|
+
}
|
|
150
|
+
return agents.find(a => a.name === agent && a.version === version && a.org_slug === org);
|
|
151
|
+
}
|
|
157
152
|
async function resolveFromMyAgents(config, agent, version, org, workspaceId) {
|
|
158
153
|
const agents = await (0, api_1.listMyAgents)(config, workspaceId);
|
|
159
154
|
const matching = agents.filter(a => a.name === agent && a.org_slug === org);
|
|
@@ -359,19 +354,12 @@ Examples:
|
|
|
359
354
|
process.stdout.write(message);
|
|
360
355
|
};
|
|
361
356
|
const config = await (0, config_1.getResolvedConfig)();
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if (!org) {
|
|
367
|
-
throw new errors_1.CliError('Missing org. Use org/agent[@version] format, or set a default org with:\n' +
|
|
368
|
-
' orch config set default-org <org>');
|
|
369
|
-
}
|
|
370
|
-
// Resolve workspace context for the target org
|
|
371
|
-
const workspaceId = await (0, api_1.resolveWorkspaceIdForOrg)(config, org);
|
|
372
|
-
write(`Resolving ${org}/${parsed.agent}@${parsed.version}...\n`);
|
|
357
|
+
const { org, agent: agentName, version, workspaceId } = await (0, resolve_agent_1.resolveAgentContext)(agentRef, config, {
|
|
358
|
+
missingOrgMessage: 'Missing org. Use org/agent[@version] format, or set a default org with:\n orch config set default-org <org>',
|
|
359
|
+
});
|
|
360
|
+
write(`Resolving ${org}/${agentName}@${version}...\n`);
|
|
373
361
|
// Resolve agent data
|
|
374
|
-
const data = await resolveAgent(config, org,
|
|
362
|
+
const data = await resolveAgent(config, org, agentName, version, workspaceId);
|
|
375
363
|
// Reject skills
|
|
376
364
|
if (canonicalType(data.type) === 'skill') {
|
|
377
365
|
throw new errors_1.CliError("This is a skill. Use 'orch skill install <ref>' instead.");
|
|
@@ -455,7 +443,7 @@ Examples:
|
|
|
455
443
|
// Track analytics
|
|
456
444
|
await (0, analytics_1.track)('cli_pull', {
|
|
457
445
|
org,
|
|
458
|
-
agent:
|
|
446
|
+
agent: agentName,
|
|
459
447
|
version: data.version,
|
|
460
448
|
engine,
|
|
461
449
|
source: data.source,
|
|
@@ -465,7 +453,7 @@ Examples:
|
|
|
465
453
|
if (options.json) {
|
|
466
454
|
const result = {
|
|
467
455
|
success: true,
|
|
468
|
-
requested_ref: `${org}/${
|
|
456
|
+
requested_ref: `${org}/${agentName}@${version}`,
|
|
469
457
|
resolved_ref: resolvedRef,
|
|
470
458
|
output_dir: outputDir,
|
|
471
459
|
engine,
|
package/dist/commands/replay.js
CHANGED
|
@@ -91,6 +91,21 @@ function registerReplayCommand(program) {
|
|
|
91
91
|
.option('--override-policy <id>', 'Override provider policy ID for this replay')
|
|
92
92
|
.option('--no-wait', 'Queue the replay and return immediately without waiting for results')
|
|
93
93
|
.option('--json', 'Output as JSON')
|
|
94
|
+
.addHelpText('after', `
|
|
95
|
+
How snapshots work:
|
|
96
|
+
Every cloud run automatically captures a snapshot of its input, config,
|
|
97
|
+
secrets, and agent version before execution. This snapshot enables
|
|
98
|
+
deterministic replay — even if the agent has been updated since.
|
|
99
|
+
|
|
100
|
+
Local runs (--local) do not create snapshots and cannot be replayed.
|
|
101
|
+
Runs created before snapshot support was added also cannot be replayed.
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
orch replay a1b2c3d4 Replay and wait for results
|
|
105
|
+
orch replay a1b2c3d4 --no-wait Queue and return immediately
|
|
106
|
+
orch replay a1b2c3d4 --reason "debug" Replay with audit reason
|
|
107
|
+
orch replay a1b2c3d4 --json Output as JSON
|
|
108
|
+
`)
|
|
94
109
|
.action(async (runId, options) => {
|
|
95
110
|
const config = await (0, config_1.getResolvedConfig)();
|
|
96
111
|
if (!config.apiKey) {
|
|
@@ -109,15 +124,33 @@ function registerReplayCommand(program) {
|
|
|
109
124
|
throw new errors_1.CliError(`Invalid run ID '${runId}'. Provide a full UUID or a short hex prefix (7+ characters).`);
|
|
110
125
|
}
|
|
111
126
|
// Submit replay request
|
|
112
|
-
const
|
|
127
|
+
const reqBody = {};
|
|
113
128
|
if (options.reason)
|
|
114
|
-
|
|
129
|
+
reqBody.reason = options.reason;
|
|
115
130
|
if (options.overridePolicy)
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
131
|
+
reqBody.override_provider_policy_id = options.overridePolicy;
|
|
132
|
+
let replay;
|
|
133
|
+
try {
|
|
134
|
+
replay = await (0, api_1.request)(config, 'POST', `/workspaces/${workspaceId}/runs/${resolvedRunId}/replay`, {
|
|
135
|
+
body: JSON.stringify(reqBody),
|
|
136
|
+
headers: { 'Content-Type': 'application/json' },
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
if (err instanceof api_1.ApiError && err.status === 404) {
|
|
141
|
+
const isSnapshotMissing = err.message.toLowerCase().includes('snapshot');
|
|
142
|
+
if (isSnapshotMissing) {
|
|
143
|
+
throw new errors_1.CliError(`No snapshot available for run ${resolvedRunId.slice(0, 8)}.\n\n` +
|
|
144
|
+
`Snapshots are captured automatically for cloud runs. This run may have been:\n` +
|
|
145
|
+
` - A local run (--local), which does not create snapshots\n` +
|
|
146
|
+
` - Created before snapshot support was added\n\n` +
|
|
147
|
+
`Run \`orch logs ${resolvedRunId.slice(0, 8)}\` to inspect the original run.`);
|
|
148
|
+
}
|
|
149
|
+
throw new errors_1.CliError(`Run ${resolvedRunId.slice(0, 8)} not found. ` +
|
|
150
|
+
`Check the run ID and workspace, or run \`orch logs\` to list recent runs.`);
|
|
151
|
+
}
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
121
154
|
if (options.json && options.wait === false) {
|
|
122
155
|
(0, output_1.printJson)(replay);
|
|
123
156
|
return;
|
package/dist/commands/run.js
CHANGED
|
@@ -54,6 +54,7 @@ const child_process_1 = require("child_process");
|
|
|
54
54
|
const chalk_1 = __importDefault(require("chalk"));
|
|
55
55
|
const dotenv_1 = require("../lib/dotenv");
|
|
56
56
|
const config_1 = require("../lib/config");
|
|
57
|
+
const resolve_agent_1 = require("../lib/resolve-agent");
|
|
57
58
|
const api_1 = require("../lib/api");
|
|
58
59
|
const errors_1 = require("../lib/errors");
|
|
59
60
|
const output_1 = require("../lib/output");
|
|
@@ -84,18 +85,6 @@ function localCommandForEntrypoint(entrypoint) {
|
|
|
84
85
|
}
|
|
85
86
|
return 'python3';
|
|
86
87
|
}
|
|
87
|
-
function parseAgentRef(value) {
|
|
88
|
-
const [ref, versionPart] = value.split('@');
|
|
89
|
-
const version = versionPart?.trim() || DEFAULT_VERSION;
|
|
90
|
-
const segments = ref.split('/');
|
|
91
|
-
if (segments.length === 1) {
|
|
92
|
-
return { agent: segments[0], version };
|
|
93
|
-
}
|
|
94
|
-
if (segments.length === 2) {
|
|
95
|
-
return { org: segments[0], agent: segments[1], version };
|
|
96
|
-
}
|
|
97
|
-
throw new errors_1.CliError('Invalid agent reference. Use org/agent or agent format.');
|
|
98
|
-
}
|
|
99
88
|
function canonicalAgentType(typeValue) {
|
|
100
89
|
const normalized = (typeValue || 'agent').toLowerCase();
|
|
101
90
|
// Handle legacy type names: agentic → agent, code → tool
|
|
@@ -798,6 +787,13 @@ async function detectAllLlmKeys(supportedProviders, config) {
|
|
|
798
787
|
return providers;
|
|
799
788
|
}
|
|
800
789
|
async function executePromptLocally(agentData, inputData, skillPrompts = [], config, providerOverride, modelOverride) {
|
|
790
|
+
// Auto-detect provider from model name if not explicitly specified
|
|
791
|
+
if (!providerOverride && modelOverride) {
|
|
792
|
+
const detected = (0, llm_1.detectProviderFromModel)(modelOverride);
|
|
793
|
+
if (detected) {
|
|
794
|
+
providerOverride = detected;
|
|
795
|
+
}
|
|
796
|
+
}
|
|
801
797
|
if (providerOverride) {
|
|
802
798
|
(0, llm_1.validateProvider)(providerOverride);
|
|
803
799
|
}
|
|
@@ -816,7 +812,7 @@ async function executePromptLocally(agentData, inputData, skillPrompts = [], con
|
|
|
816
812
|
throw new errors_1.CliError(`No LLM key found for: ${providers}\n` +
|
|
817
813
|
`Set an environment variable (e.g., OPENAI_API_KEY), run 'orch secrets set <PROVIDER>_API_KEY <key>', or configure in web dashboard`);
|
|
818
814
|
}
|
|
819
|
-
if (modelOverride &&
|
|
815
|
+
if (modelOverride && allProviders.length > 1) {
|
|
820
816
|
process.stderr.write(`Warning: --model specified without --provider. The model '${modelOverride}' will be used for all ${allProviders.length} fallback providers, which may cause errors if the model is incompatible.\n` +
|
|
821
817
|
`Consider specifying --provider to ensure correct model/provider pairing.\n\n`);
|
|
822
818
|
}
|
|
@@ -866,6 +862,13 @@ async function executeAgentLocally(agentDir, prompt, inputData, outputSchema, cu
|
|
|
866
862
|
throw new errors_1.CliError('Python 3 is required for local agent execution.\n' +
|
|
867
863
|
'Install Python 3: https://python.org/downloads');
|
|
868
864
|
}
|
|
865
|
+
// Auto-detect provider from model name if not explicitly specified
|
|
866
|
+
if (!providerOverride && modelOverride) {
|
|
867
|
+
const detected = (0, llm_1.detectProviderFromModel)(modelOverride);
|
|
868
|
+
if (detected) {
|
|
869
|
+
providerOverride = detected;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
869
872
|
// 2. Detect LLM provider + key
|
|
870
873
|
const supportedProviders = manifest?.supported_providers || ['any'];
|
|
871
874
|
const providersToCheck = providerOverride
|
|
@@ -1869,15 +1872,8 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1869
1872
|
if (!resolved.apiKey) {
|
|
1870
1873
|
throw new errors_1.CliError('Missing API key. Run `orchagent login` first.');
|
|
1871
1874
|
}
|
|
1872
|
-
const
|
|
1873
|
-
const
|
|
1874
|
-
const org = parsed.org ?? configFile.workspace ?? resolved.defaultOrg;
|
|
1875
|
-
if (!org) {
|
|
1876
|
-
throw new errors_1.CliError('Missing org. Use org/agent or set default org.');
|
|
1877
|
-
}
|
|
1878
|
-
// Resolve workspace context for the target org
|
|
1879
|
-
const workspaceId = await (0, api_1.resolveWorkspaceIdForOrg)(resolved, org);
|
|
1880
|
-
const agentMeta = await (0, api_1.getAgentWithFallback)(resolved, org, parsed.agent, parsed.version, workspaceId);
|
|
1875
|
+
const { org, agent: agentName, version, workspaceId } = await (0, resolve_agent_1.resolveAgentContext)(agentRef, resolved);
|
|
1876
|
+
const agentMeta = await (0, api_1.getAgentWithFallback)(resolved, org, agentName, version, workspaceId);
|
|
1881
1877
|
const cloudType = canonicalAgentType(agentMeta.type);
|
|
1882
1878
|
const cloudEngine = resolveExecutionEngine({
|
|
1883
1879
|
type: agentMeta.type,
|
|
@@ -1891,10 +1887,8 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1891
1887
|
const agentRequiredSecrets = agentMeta.required_secrets;
|
|
1892
1888
|
if (agentRequiredSecrets?.length) {
|
|
1893
1889
|
try {
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
if (wsId) {
|
|
1897
|
-
const secretsResult = await (0, api_1.request)(resolved, 'GET', `/workspaces/${wsId}/secrets`);
|
|
1890
|
+
if (workspaceId) {
|
|
1891
|
+
const secretsResult = await (0, api_1.request)(resolved, 'GET', `/workspaces/${workspaceId}/secrets`);
|
|
1898
1892
|
const existingNames = new Set(secretsResult.secrets.map((s) => s.name));
|
|
1899
1893
|
const missing = agentRequiredSecrets.filter((s) => !existingNames.has(s));
|
|
1900
1894
|
if (missing.length > 0) {
|
|
@@ -1918,7 +1912,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1918
1912
|
// --estimate-only: show cost estimate and exit without running
|
|
1919
1913
|
if (options.estimate || options.estimateOnly) {
|
|
1920
1914
|
try {
|
|
1921
|
-
const est = await (0, api_1.getAgentCostEstimate)(resolved, org,
|
|
1915
|
+
const est = await (0, api_1.getAgentCostEstimate)(resolved, org, agentName, version);
|
|
1922
1916
|
const e = est.estimate;
|
|
1923
1917
|
if (e.sample_size === 0) {
|
|
1924
1918
|
process.stderr.write(chalk_1.default.yellow('\nNo run history available for cost estimation.\n'));
|
|
@@ -1988,18 +1982,8 @@ async function executeCloud(agentRef, file, options) {
|
|
|
1988
1982
|
throw new errors_1.CliError('When using --key, you must also specify --provider (openai, anthropic, or gemini)');
|
|
1989
1983
|
}
|
|
1990
1984
|
(0, llm_1.validateProvider)(effectiveProvider);
|
|
1991
|
-
if (options.model
|
|
1992
|
-
|
|
1993
|
-
const providerPatterns = {
|
|
1994
|
-
openai: /^(gpt-|o1-|o3-|davinci|text-)/,
|
|
1995
|
-
anthropic: /^claude-/,
|
|
1996
|
-
gemini: /^gemini-/,
|
|
1997
|
-
ollama: /^(llama|mistral|deepseek|phi|qwen)/,
|
|
1998
|
-
};
|
|
1999
|
-
const expectedPattern = providerPatterns[effectiveProvider];
|
|
2000
|
-
if (expectedPattern && !expectedPattern.test(modelLower)) {
|
|
2001
|
-
process.stderr.write(`Warning: Model '${options.model}' may not be a ${effectiveProvider} model.\n\n`);
|
|
2002
|
-
}
|
|
1985
|
+
if (options.model) {
|
|
1986
|
+
(0, llm_1.warnProviderModelMismatch)(options.model, effectiveProvider);
|
|
2003
1987
|
}
|
|
2004
1988
|
llmKey = options.key;
|
|
2005
1989
|
llmProvider = effectiveProvider;
|
|
@@ -2010,17 +1994,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2010
1994
|
(0, llm_1.validateProvider)(effectiveProvider);
|
|
2011
1995
|
providersToCheck = [effectiveProvider];
|
|
2012
1996
|
if (options.model) {
|
|
2013
|
-
|
|
2014
|
-
const providerPatterns = {
|
|
2015
|
-
openai: /^(gpt-|o1-|o3-|davinci|text-)/,
|
|
2016
|
-
anthropic: /^claude-/,
|
|
2017
|
-
gemini: /^gemini-/,
|
|
2018
|
-
ollama: /^(llama|mistral|deepseek|phi|qwen)/,
|
|
2019
|
-
};
|
|
2020
|
-
const expectedPattern = providerPatterns[effectiveProvider];
|
|
2021
|
-
if (expectedPattern && !expectedPattern.test(modelLower)) {
|
|
2022
|
-
process.stderr.write(`Warning: Model '${options.model}' may not be a ${effectiveProvider} model.\n\n`);
|
|
2023
|
-
}
|
|
1997
|
+
(0, llm_1.warnProviderModelMismatch)(options.model, effectiveProvider);
|
|
2024
1998
|
}
|
|
2025
1999
|
}
|
|
2026
2000
|
const detected = await (0, llm_1.detectLlmKey)(providersToCheck, resolved);
|
|
@@ -2245,7 +2219,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2245
2219
|
}
|
|
2246
2220
|
} // end of non-injection path
|
|
2247
2221
|
const verboseQs = options.verbose ? '?verbose=true' : '';
|
|
2248
|
-
const url = `${resolved.apiUrl.replace(/\/$/, '')}/${org}/${
|
|
2222
|
+
const url = `${resolved.apiUrl.replace(/\/$/, '')}/${org}/${agentName}/${version}/${endpoint}${verboseQs}`;
|
|
2249
2223
|
// Enable SSE streaming for sandbox-backed engines (unless --json or --no-stream or --output)
|
|
2250
2224
|
const isManagedLoopAgent = cloudType === 'agent' && cloudEngine === 'managed_loop';
|
|
2251
2225
|
const isCodeRuntimeAgent = cloudEngine === 'code_runtime';
|
|
@@ -2257,13 +2231,13 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2257
2231
|
}
|
|
2258
2232
|
// Print verbose debug info before request
|
|
2259
2233
|
if (options.verbose && !options.json) {
|
|
2260
|
-
process.stderr.write(chalk_1.default.gray(`\n[verbose] ${org}/${
|
|
2234
|
+
process.stderr.write(chalk_1.default.gray(`\n[verbose] ${org}/${agentName}@${version}\n` +
|
|
2261
2235
|
`[verbose] type=${cloudType} engine=${cloudEngine} endpoint=${endpoint}\n` +
|
|
2262
2236
|
`[verbose] stream=${wantStream ? 'yes' : 'no'} url=${url}\n`));
|
|
2263
2237
|
}
|
|
2264
2238
|
const { spinner, dispose: disposeSpinner } = options.json
|
|
2265
2239
|
? { spinner: null, dispose: () => { } }
|
|
2266
|
-
: (0, spinner_1.createElapsedSpinner)(`Running ${org}/${
|
|
2240
|
+
: (0, spinner_1.createElapsedSpinner)(`Running ${org}/${agentName}@${version}...`);
|
|
2267
2241
|
spinner?.start();
|
|
2268
2242
|
// Streamed sandbox runs can take longer; use 10 min timeout (or --wait-timeout).
|
|
2269
2243
|
const waitTimeoutSec = options.waitTimeout ? parseInt(options.waitTimeout, 10) : undefined;
|
|
@@ -2432,11 +2406,11 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2432
2406
|
let finalPayload = null;
|
|
2433
2407
|
let hadError = false;
|
|
2434
2408
|
if (options.verbose) {
|
|
2435
|
-
process.stderr.write(chalk_1.default.gray(`\nStreaming ${org}/${
|
|
2409
|
+
process.stderr.write(chalk_1.default.gray(`\nStreaming ${org}/${agentName}@${version} (verbose):\n`));
|
|
2436
2410
|
process.stderr.write(chalk_1.default.gray(` type=${cloudType} engine=${cloudEngine} endpoint=${endpoint}\n`));
|
|
2437
2411
|
}
|
|
2438
2412
|
else {
|
|
2439
|
-
process.stderr.write(chalk_1.default.gray(`\nStreaming ${org}/${
|
|
2413
|
+
process.stderr.write(chalk_1.default.gray(`\nStreaming ${org}/${agentName}@${version}:\n`));
|
|
2440
2414
|
}
|
|
2441
2415
|
let progressErrorShown = false;
|
|
2442
2416
|
let streamTimedOut = false;
|
|
@@ -2497,7 +2471,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2497
2471
|
? ''
|
|
2498
2472
|
: chalk_1.default.gray('Tip: Use --wait-timeout <seconds> to wait longer.\n')));
|
|
2499
2473
|
await (0, analytics_1.track)('cli_run', {
|
|
2500
|
-
agent: `${org}/${
|
|
2474
|
+
agent: `${org}/${agentName}@${version}`,
|
|
2501
2475
|
input_type: hasInjection ? 'file_injection' : unkeyedFileArgs.length > 0 ? 'file' : options.data ? 'json' : 'empty',
|
|
2502
2476
|
mode: 'cloud',
|
|
2503
2477
|
streamed: true,
|
|
@@ -2508,7 +2482,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2508
2482
|
throw err;
|
|
2509
2483
|
}
|
|
2510
2484
|
await (0, analytics_1.track)('cli_run', {
|
|
2511
|
-
agent: `${org}/${
|
|
2485
|
+
agent: `${org}/${agentName}@${version}`,
|
|
2512
2486
|
input_type: hasInjection ? 'file_injection' : unkeyedFileArgs.length > 0 ? 'file' : options.data ? 'json' : 'empty',
|
|
2513
2487
|
mode: 'cloud',
|
|
2514
2488
|
streamed: true,
|
|
@@ -2549,14 +2523,14 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2549
2523
|
}
|
|
2550
2524
|
const runId = response.headers?.get?.('x-run-id');
|
|
2551
2525
|
if (runId) {
|
|
2552
|
-
process.stderr.write(chalk_1.default.gray(`
|
|
2526
|
+
process.stderr.write(chalk_1.default.gray(`Snapshot saved · Logs: orch logs ${runId} · Replay: orch replay ${runId}\n`));
|
|
2553
2527
|
}
|
|
2554
2528
|
}
|
|
2555
2529
|
}
|
|
2556
2530
|
}
|
|
2557
2531
|
return;
|
|
2558
2532
|
}
|
|
2559
|
-
spinner?.succeed(`Ran ${org}/${
|
|
2533
|
+
spinner?.succeed(`Ran ${org}/${agentName}@${version}`);
|
|
2560
2534
|
const inputType = hasInjection
|
|
2561
2535
|
? 'file_injection'
|
|
2562
2536
|
: unkeyedFileArgs.length > 0
|
|
@@ -2569,7 +2543,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2569
2543
|
? 'metadata'
|
|
2570
2544
|
: 'empty';
|
|
2571
2545
|
await (0, analytics_1.track)('cli_run', {
|
|
2572
|
-
agent: `${org}/${
|
|
2546
|
+
agent: `${org}/${agentName}@${version}`,
|
|
2573
2547
|
input_type: inputType,
|
|
2574
2548
|
mode: 'cloud',
|
|
2575
2549
|
});
|
|
@@ -2638,7 +2612,7 @@ async function executeCloud(agentRef, file, options) {
|
|
|
2638
2612
|
}
|
|
2639
2613
|
const runId = response.headers?.get?.('x-run-id');
|
|
2640
2614
|
if (runId) {
|
|
2641
|
-
process.stderr.write(chalk_1.default.gray(`
|
|
2615
|
+
process.stderr.write(chalk_1.default.gray(`Snapshot saved · Logs: orch logs ${runId} · Replay: orch replay ${runId}\n`));
|
|
2642
2616
|
}
|
|
2643
2617
|
}
|
|
2644
2618
|
}
|
|
@@ -2657,34 +2631,24 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2657
2631
|
options.input = JSON.stringify({ path: options.path });
|
|
2658
2632
|
}
|
|
2659
2633
|
if (options.model && options.provider) {
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
const expectedPattern = providerPatterns[options.provider];
|
|
2668
|
-
if (expectedPattern && !expectedPattern.test(modelLower)) {
|
|
2669
|
-
process.stderr.write(`Warning: Model '${options.model}' may not be a ${options.provider} model.\n\n`);
|
|
2634
|
+
(0, llm_1.warnProviderModelMismatch)(options.model, options.provider);
|
|
2635
|
+
}
|
|
2636
|
+
else if (options.model && !options.provider) {
|
|
2637
|
+
const detected = (0, llm_1.detectProviderFromModel)(options.model);
|
|
2638
|
+
if (detected) {
|
|
2639
|
+
options.provider = detected;
|
|
2640
|
+
process.stderr.write(`Auto-detected provider: ${detected} (from model '${options.model}')\n\n`);
|
|
2670
2641
|
}
|
|
2671
2642
|
}
|
|
2672
2643
|
const resolved = await (0, config_1.getResolvedConfig)();
|
|
2673
|
-
const
|
|
2674
|
-
const configFile = await (0, config_1.loadConfig)();
|
|
2675
|
-
const org = parsed.org ?? configFile.workspace ?? resolved.defaultOrg;
|
|
2676
|
-
if (!org) {
|
|
2677
|
-
throw new errors_1.CliError('Missing org. Use org/agent format.');
|
|
2678
|
-
}
|
|
2679
|
-
// Resolve workspace context for the target org
|
|
2680
|
-
const workspaceId = await (0, api_1.resolveWorkspaceIdForOrg)(resolved, org);
|
|
2644
|
+
const { org, agent: localAgentName, version: localVersion, workspaceId } = await (0, resolve_agent_1.resolveAgentContext)(agentRef, resolved);
|
|
2681
2645
|
// Download agent definition with spinner
|
|
2682
|
-
const agentData = await (0, spinner_1.withSpinner)(`Downloading ${org}/${
|
|
2646
|
+
const agentData = await (0, spinner_1.withSpinner)(`Downloading ${org}/${localAgentName}@${localVersion}...`, async () => {
|
|
2683
2647
|
try {
|
|
2684
|
-
return await downloadAgent(resolved, org,
|
|
2648
|
+
return await downloadAgent(resolved, org, localAgentName, localVersion, workspaceId);
|
|
2685
2649
|
}
|
|
2686
2650
|
catch (err) {
|
|
2687
|
-
const agentMeta = await (0, api_1.getPublicAgent)(resolved, org,
|
|
2651
|
+
const agentMeta = await (0, api_1.getPublicAgent)(resolved, org, localAgentName, localVersion);
|
|
2688
2652
|
return {
|
|
2689
2653
|
type: agentMeta.type || 'agent',
|
|
2690
2654
|
run_mode: agentMeta.run_mode ?? null,
|
|
@@ -2696,7 +2660,7 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2696
2660
|
supported_providers: agentMeta.supported_providers || ['any'],
|
|
2697
2661
|
};
|
|
2698
2662
|
}
|
|
2699
|
-
}, { successText: `Downloaded ${org}/${
|
|
2663
|
+
}, { successText: `Downloaded ${org}/${localAgentName}@${localVersion}` });
|
|
2700
2664
|
const localType = canonicalAgentType(agentData.type);
|
|
2701
2665
|
const localEngine = resolveExecutionEngine(agentData);
|
|
2702
2666
|
// Skills cannot be run directly
|
|
@@ -2704,8 +2668,8 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2704
2668
|
throw new errors_1.CliError('Skills cannot be run directly.\n\n' +
|
|
2705
2669
|
'Skills are instructions meant to be injected into AI agent contexts.\n\n' +
|
|
2706
2670
|
'Options:\n' +
|
|
2707
|
-
` Install for AI tools: orchagent skill install ${org}/${
|
|
2708
|
-
` Use with an agent: orchagent run <agent> --skills ${org}/${
|
|
2671
|
+
` Install for AI tools: orchagent skill install ${org}/${localAgentName}\n` +
|
|
2672
|
+
` Use with an agent: orchagent run <agent> --skills ${org}/${localAgentName}`);
|
|
2709
2673
|
}
|
|
2710
2674
|
// Managed-loop agents execute locally with the agent runner.
|
|
2711
2675
|
if (localEngine === 'managed_loop') {
|
|
@@ -2713,11 +2677,11 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2713
2677
|
throw new errors_1.CliError('Agent prompt not available for local execution.\n\n' +
|
|
2714
2678
|
'This agent may have local download disabled.\n' +
|
|
2715
2679
|
'Remove the --local flag to run in the cloud:\n' +
|
|
2716
|
-
` orch run ${org}/${
|
|
2680
|
+
` orch run ${org}/${localAgentName}@${localVersion} --data '{"task": "..."}'`);
|
|
2717
2681
|
}
|
|
2718
2682
|
if (!options.input) {
|
|
2719
2683
|
process.stderr.write(`\nAgent downloaded. Run with:\n`);
|
|
2720
|
-
process.stderr.write(` orch run ${org}/${
|
|
2684
|
+
process.stderr.write(` orch run ${org}/${localAgentName}@${localVersion} --local --data '{\"task\": \"...\"}'\n`);
|
|
2721
2685
|
return;
|
|
2722
2686
|
}
|
|
2723
2687
|
// Resolve @file.json / @- stdin syntax before parsing
|
|
@@ -2731,7 +2695,7 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2731
2695
|
}
|
|
2732
2696
|
warnInputSchemaErrors(agentInputData, agentData.input_schema);
|
|
2733
2697
|
// Write prompt to temp dir and run
|
|
2734
|
-
const tempAgentDir = path_1.default.join(os_1.default.tmpdir(), `orchagent-agent-${
|
|
2698
|
+
const tempAgentDir = path_1.default.join(os_1.default.tmpdir(), `orchagent-agent-${localAgentName}-${Date.now()}`);
|
|
2735
2699
|
await promises_1.default.mkdir(tempAgentDir, { recursive: true });
|
|
2736
2700
|
try {
|
|
2737
2701
|
await promises_1.default.writeFile(path_1.default.join(tempAgentDir, 'prompt.md'), agentData.prompt);
|
|
@@ -2761,7 +2725,7 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2761
2725
|
}
|
|
2762
2726
|
if (choice === 'server') {
|
|
2763
2727
|
process.stderr.write(`\nRun without --local for server execution:\n`);
|
|
2764
|
-
process.stderr.write(` orch run ${org}/${
|
|
2728
|
+
process.stderr.write(` orch run ${org}/${localAgentName}@${localVersion} --data '{...}'\n\n`);
|
|
2765
2729
|
process.exit(0);
|
|
2766
2730
|
}
|
|
2767
2731
|
await downloadDependenciesRecursively(resolved, depStatuses, new Set(), workspaceId);
|
|
@@ -2784,13 +2748,13 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2784
2748
|
}
|
|
2785
2749
|
}
|
|
2786
2750
|
// Save locally
|
|
2787
|
-
const agentDir = await saveAgentLocally(org,
|
|
2751
|
+
const agentDir = await saveAgentLocally(org, localAgentName, agentData);
|
|
2788
2752
|
process.stderr.write(`\nAgent saved to: ${agentDir}\n`);
|
|
2789
2753
|
if (localEngine === 'code_runtime') {
|
|
2790
2754
|
if (agentData.has_bundle) {
|
|
2791
2755
|
if (options.downloadOnly) {
|
|
2792
2756
|
process.stdout.write(`\nCode runtime bundle is available for local execution.\n`);
|
|
2793
|
-
process.stdout.write(`Run with: orch run ${org}/${
|
|
2757
|
+
process.stdout.write(`Run with: orch run ${org}/${localAgentName} --local [args...]\n`);
|
|
2794
2758
|
return;
|
|
2795
2759
|
}
|
|
2796
2760
|
// Pre-build injected payload for bundle agent if keyed files/mounts present
|
|
@@ -2806,13 +2770,13 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2806
2770
|
});
|
|
2807
2771
|
bundleInput = injected.body;
|
|
2808
2772
|
}
|
|
2809
|
-
await executeBundleAgent(resolved, org,
|
|
2773
|
+
await executeBundleAgent(resolved, org, localAgentName, localVersion, agentData, args, bundleInput, workspaceId);
|
|
2810
2774
|
return;
|
|
2811
2775
|
}
|
|
2812
2776
|
if (agentData.run_command && (agentData.source_url || agentData.pip_package)) {
|
|
2813
2777
|
if (options.downloadOnly) {
|
|
2814
2778
|
process.stdout.write(`\nTool ready for local execution.\n`);
|
|
2815
|
-
process.stdout.write(`Run with: orch run ${org}/${
|
|
2779
|
+
process.stdout.write(`Run with: orch run ${org}/${localAgentName} --local [args...]\n`);
|
|
2816
2780
|
return;
|
|
2817
2781
|
}
|
|
2818
2782
|
await executeTool(agentData, args);
|
|
@@ -2820,12 +2784,12 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2820
2784
|
}
|
|
2821
2785
|
// Fallback: code runtime agent doesn't support local execution.
|
|
2822
2786
|
process.stdout.write(`\nThis code runtime agent is configured for server execution.\n`);
|
|
2823
|
-
process.stdout.write(`\nRun without --local: orch run ${org}/${
|
|
2787
|
+
process.stdout.write(`\nRun without --local: orch run ${org}/${localAgentName}@${localVersion} --data '{...}'\n`);
|
|
2824
2788
|
return;
|
|
2825
2789
|
}
|
|
2826
2790
|
if (options.downloadOnly) {
|
|
2827
2791
|
process.stdout.write(`\nAgent downloaded. Run with:\n`);
|
|
2828
|
-
process.stdout.write(` orch run ${org}/${
|
|
2792
|
+
process.stdout.write(` orch run ${org}/${localAgentName}@${localVersion} --local --input '{...}'\n`);
|
|
2829
2793
|
return;
|
|
2830
2794
|
}
|
|
2831
2795
|
// Check for keyed file/mount injection
|
|
@@ -2835,7 +2799,7 @@ async function executeLocal(agentRef, args, options) {
|
|
|
2835
2799
|
// Direct LLM agents execute locally via prompt composition.
|
|
2836
2800
|
if (!options.input && !execLocalHasInjection) {
|
|
2837
2801
|
process.stdout.write(`\nAgent ready.\n`);
|
|
2838
|
-
process.stdout.write(`Run with: orch run ${org}/${
|
|
2802
|
+
process.stdout.write(`Run with: orch run ${org}/${localAgentName}@${localVersion} --local --input '{...}'\n`);
|
|
2839
2803
|
return;
|
|
2840
2804
|
}
|
|
2841
2805
|
let inputData;
|