@orchagent/cli 0.3.90 → 0.3.92

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.
@@ -16,15 +16,24 @@ function deriveSlug(name) {
16
16
  async function resolveWorkspaceId(config, slug) {
17
17
  const configFile = await (0, config_1.loadConfig)();
18
18
  const targetSlug = slug ?? configFile.workspace;
19
- if (!targetSlug) {
20
- throw new errors_1.CliError('No workspace specified. Use --workspace <slug> or run `orchagent workspace use <slug>` first.');
21
- }
22
19
  const response = await (0, api_1.request)(config, 'GET', '/workspaces');
23
- const workspace = response.workspaces.find((w) => w.slug === targetSlug);
24
- if (!workspace) {
25
- throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
20
+ if (targetSlug) {
21
+ const workspace = response.workspaces.find((w) => w.slug === targetSlug);
22
+ if (!workspace) {
23
+ throw new errors_1.CliError(`Workspace '${targetSlug}' not found.`);
24
+ }
25
+ return workspace.id;
26
+ }
27
+ // No workspace specified — auto-select if user has exactly one
28
+ if (response.workspaces.length === 0) {
29
+ throw new errors_1.CliError('No workspaces found. Create one with `orch workspace create <name>`.');
30
+ }
31
+ if (response.workspaces.length === 1) {
32
+ return response.workspaces[0].id;
26
33
  }
27
- return workspace.id;
34
+ const slugs = response.workspaces.map((w) => w.slug).join(', ');
35
+ throw new errors_1.CliError(`Multiple workspaces available: ${slugs}\n` +
36
+ 'Specify one with --workspace <slug> or run `orch workspace use <slug>`.');
28
37
  }
29
38
  async function listWorkspaces(config, options) {
30
39
  const response = await (0, api_1.request)(config, 'GET', '/workspaces');
@@ -6,8 +6,11 @@ function parseAgentRef(value, defaultVersion = 'latest') {
6
6
  const [ref, versionPart] = value.split('@');
7
7
  const version = versionPart?.trim() || defaultVersion;
8
8
  const segments = ref.split('/');
9
+ if (segments.length === 1) {
10
+ return { org: undefined, agent: segments[0], version };
11
+ }
9
12
  if (segments.length === 2) {
10
13
  return { org: segments[0], agent: segments[1], version };
11
14
  }
12
- throw new errors_1.CliError('Invalid agent reference. Use org/agent[@version] format');
15
+ throw new errors_1.CliError('Invalid agent reference. Use agent or org/agent[@version] format');
13
16
  }
@@ -59,6 +59,7 @@ async function waitForCallback(port, timeoutMs) {
59
59
  let server = null;
60
60
  const cleanup = () => {
61
61
  if (server) {
62
+ server.closeAllConnections();
62
63
  server.close();
63
64
  server = null;
64
65
  }
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dependencyRef = dependencyRef;
4
+ exports.validateScaffoldAgentName = validateScaffoldAgentName;
5
+ exports.dedupeOrchestrationDependencies = dedupeOrchestrationDependencies;
6
+ exports.buildOrchestrationCustomTools = buildOrchestrationCustomTools;
7
+ exports.buildOrchestrationManifest = buildOrchestrationManifest;
8
+ exports.buildOrchestrationPrompt = buildOrchestrationPrompt;
9
+ exports.buildOrchestrationSchema = buildOrchestrationSchema;
10
+ const BUILTIN_TOOL_NAMES = new Set([
11
+ 'bash',
12
+ 'read_file',
13
+ 'write_file',
14
+ 'list_files',
15
+ 'submit_result',
16
+ ]);
17
+ const DEFAULT_MAX_TURNS = 25;
18
+ const DEFAULT_TIMEOUT_MS = 180000;
19
+ const DEFAULT_PER_CALL_DOWNSTREAM_CAP = 50;
20
+ function dependencyId(dep) {
21
+ return `${dep.org}/${dep.name}`;
22
+ }
23
+ function dependencyRef(dep) {
24
+ return `${dependencyId(dep)}@${dep.version}`;
25
+ }
26
+ function sanitizeToolToken(value) {
27
+ const token = value
28
+ .trim()
29
+ .toLowerCase()
30
+ .replace(/[^a-z0-9]+/g, '_')
31
+ .replace(/^_+|_+$/g, '');
32
+ return token || 'dependency';
33
+ }
34
+ function defaultToolInputSchema() {
35
+ return {
36
+ type: 'object',
37
+ description: 'JSON payload forwarded to the dependency agent',
38
+ additionalProperties: true,
39
+ };
40
+ }
41
+ function normalizeToolInputSchema(inputSchema) {
42
+ if (!inputSchema || typeof inputSchema !== 'object' || Array.isArray(inputSchema)) {
43
+ return defaultToolInputSchema();
44
+ }
45
+ return inputSchema;
46
+ }
47
+ function summarizeDependencyDescription(dep) {
48
+ const prefix = `Call ${dependencyRef(dep)}`;
49
+ const raw = dep.description?.trim();
50
+ if (!raw)
51
+ return prefix;
52
+ const compact = raw.replace(/\s+/g, ' ');
53
+ if (compact.length <= 140)
54
+ return `${prefix}: ${compact}`;
55
+ return `${prefix}: ${compact.slice(0, 137)}...`;
56
+ }
57
+ function nextUniqueToolName(dep, usedNames) {
58
+ const candidates = [
59
+ `call_${sanitizeToolToken(dep.name)}`,
60
+ `call_${sanitizeToolToken(dep.org)}_${sanitizeToolToken(dep.name)}`,
61
+ ];
62
+ for (const candidate of candidates) {
63
+ if (!usedNames.has(candidate) && !BUILTIN_TOOL_NAMES.has(candidate)) {
64
+ usedNames.add(candidate);
65
+ return candidate;
66
+ }
67
+ }
68
+ let suffix = 2;
69
+ const stablePrefix = `call_${sanitizeToolToken(dep.org)}_${sanitizeToolToken(dep.name)}`;
70
+ while (true) {
71
+ const candidate = `${stablePrefix}_${suffix}`;
72
+ if (!usedNames.has(candidate) && !BUILTIN_TOOL_NAMES.has(candidate)) {
73
+ usedNames.add(candidate);
74
+ return candidate;
75
+ }
76
+ suffix += 1;
77
+ }
78
+ }
79
+ function defaultMaxHops(depCount) {
80
+ return Math.max(2, Math.min(8, depCount + 1));
81
+ }
82
+ function validateScaffoldAgentName(name) {
83
+ const errors = [];
84
+ const trimmed = name.trim();
85
+ const nameRegex = /^[a-z0-9][a-z0-9-]*[a-z0-9]$/;
86
+ if (trimmed.length < 2 || trimmed.length > 50) {
87
+ errors.push('Agent name must be 2-50 characters');
88
+ }
89
+ if (trimmed !== trimmed.toLowerCase()) {
90
+ errors.push('Agent name must be lowercase');
91
+ }
92
+ if (trimmed.length > 1 && !nameRegex.test(trimmed)) {
93
+ errors.push('Agent name must contain only lowercase letters, numbers, and hyphens, and must start/end with a letter or number');
94
+ }
95
+ if (trimmed.includes('--')) {
96
+ errors.push('Agent name must not contain consecutive hyphens');
97
+ }
98
+ return errors;
99
+ }
100
+ function dedupeOrchestrationDependencies(dependencies) {
101
+ const deduped = [];
102
+ const duplicates = [];
103
+ const byId = new Map();
104
+ const versionsById = new Map();
105
+ for (const dep of dependencies) {
106
+ const id = dependencyId(dep);
107
+ const existing = byId.get(id);
108
+ if (!existing) {
109
+ byId.set(id, dep);
110
+ deduped.push(dep);
111
+ versionsById.set(id, new Set([dep.version]));
112
+ continue;
113
+ }
114
+ versionsById.get(id)?.add(dep.version);
115
+ if (existing.version === dep.version) {
116
+ duplicates.push(dependencyRef(dep));
117
+ }
118
+ }
119
+ const conflicts = [];
120
+ for (const [id, versions] of versionsById.entries()) {
121
+ if (versions.size > 1) {
122
+ conflicts.push({ id, versions: [...versions].sort() });
123
+ }
124
+ }
125
+ return { dependencies: deduped, duplicates, conflicts };
126
+ }
127
+ function buildOrchestrationCustomTools(dependencies) {
128
+ const usedNames = new Set();
129
+ return dependencies.map((dep) => {
130
+ return {
131
+ name: nextUniqueToolName(dep, usedNames),
132
+ description: summarizeDependencyDescription(dep),
133
+ input_schema: normalizeToolInputSchema(dep.inputSchema),
134
+ command: `python3 /home/user/helpers/orch_call.py ${dependencyRef(dep)}`,
135
+ };
136
+ });
137
+ }
138
+ function buildOrchestrationManifest(args) {
139
+ const maxTurns = args.maxTurns ?? DEFAULT_MAX_TURNS;
140
+ const timeoutMs = args.timeoutMs ?? DEFAULT_TIMEOUT_MS;
141
+ const maxHops = args.maxHops ?? defaultMaxHops(args.dependencies.length);
142
+ const perCallDownstreamCap = args.perCallDownstreamCap ?? DEFAULT_PER_CALL_DOWNSTREAM_CAP;
143
+ return {
144
+ name: args.name,
145
+ type: 'agent',
146
+ description: `Managed-loop orchestrator that coordinates ${args.dependencies.length} dependency agents`,
147
+ run_mode: 'on_demand',
148
+ tags: ['orchestration'],
149
+ supported_providers: ['any'],
150
+ required_secrets: [],
151
+ max_turns: maxTurns,
152
+ custom_tools: args.customTools,
153
+ // Keep loop in sync with top-level compatibility fields for local + cloud parity.
154
+ loop: {
155
+ max_turns: maxTurns,
156
+ custom_tools: args.customTools,
157
+ },
158
+ manifest: {
159
+ manifest_version: 1,
160
+ dependencies: args.dependencies.map((dep) => ({
161
+ id: `${dep.org}/${dep.name}`,
162
+ version: dep.version,
163
+ })),
164
+ max_hops: maxHops,
165
+ timeout_ms: timeoutMs,
166
+ per_call_downstream_cap: perCallDownstreamCap,
167
+ },
168
+ };
169
+ }
170
+ function buildOrchestrationPrompt(args) {
171
+ const toolLines = args.customTools.map((tool, idx) => {
172
+ const dep = args.dependencies[idx];
173
+ const description = dep.description?.trim() ? ` — ${dep.description.trim()}` : '';
174
+ return `- \`${tool.name}\` -> \`${dependencyRef(dep)}\`${description}`;
175
+ });
176
+ return [
177
+ `You are ${args.name}, an orchestration agent that delegates work to specialist dependency agents.`,
178
+ '',
179
+ 'Primary objective:',
180
+ '- Use the dependency tools to solve the incoming task with accurate, well-structured results.',
181
+ '',
182
+ 'Available dependency tools:',
183
+ ...toolLines,
184
+ '',
185
+ 'Operating rules:',
186
+ '1. Prefer the dependency tools over ad-hoc bash implementations when a dependency can handle the task.',
187
+ '2. Pass only relevant fields to each tool call; do not invent required fields.',
188
+ '3. Chain tool calls when needed and reconcile conflicting outputs before finalizing.',
189
+ '4. If a dependency fails, retry once with corrected input; if still failing, return a clear partial result with the failure reason.',
190
+ '5. Always finish by calling submit_result with output that matches schema.json.',
191
+ '',
192
+ 'Input template:',
193
+ '- `{{task}}`: the user task you must complete.',
194
+ '',
195
+ 'Use concise, factual language in the final response.',
196
+ '',
197
+ ].join('\n');
198
+ }
199
+ function buildOrchestrationSchema() {
200
+ return {
201
+ input: {
202
+ type: 'object',
203
+ properties: {
204
+ task: {
205
+ type: 'string',
206
+ description: 'Task to delegate across dependency agents',
207
+ },
208
+ context: {
209
+ type: 'object',
210
+ description: 'Optional context payload forwarded to dependency tools as needed',
211
+ additionalProperties: true,
212
+ },
213
+ },
214
+ required: ['task'],
215
+ },
216
+ output: {
217
+ type: 'object',
218
+ properties: {
219
+ result: {
220
+ type: 'string',
221
+ description: 'Final synthesized answer for the task',
222
+ },
223
+ used_tools: {
224
+ type: 'array',
225
+ items: { type: 'string' },
226
+ description: 'Dependency tool names used to produce the result',
227
+ },
228
+ notes: {
229
+ type: 'array',
230
+ items: { type: 'string' },
231
+ description: 'Warnings, fallbacks, or caveats encountered during orchestration',
232
+ },
233
+ },
234
+ required: ['result', 'used_tools'],
235
+ },
236
+ };
237
+ }