nexus-prime 7.9.23 → 7.9.25

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.
@@ -280,9 +280,10 @@ export function buildMcpToolDefinitions() {
280
280
  specialists: { type: 'array', items: { type: 'string' }, description: 'Optional hard specialist selectors' },
281
281
  optimizationProfile: { type: 'string', enum: ['standard', 'max'], description: 'Planner optimization profile override' },
282
282
  executionPreset: { type: 'string', enum: ['fast', 'balanced', 'deep', 'release'], description: 'Optional execution preset that maps orchestration depth, verification strictness, and backend routing' },
283
- background: { type: 'boolean', description: 'When true, return a queued receipt immediately and let the run continue in the async gate.' },
283
+ background: { type: 'boolean', description: 'Compatibility flag; nexus_orchestrate already returns a queued hiring preflight by default and continues in the async gate.' },
284
284
  async: { type: 'boolean', description: 'Alias for background; useful for clients that prefer explicit async orchestration.' },
285
- waitMs: { type: 'number', description: 'Optional bounded wait before returning a queued receipt. Clamped to 45 seconds; normal orchestrate calls default to 15 seconds.' }
285
+ waitMs: { type: 'number', description: 'Advanced/debug bounded wait for inline execution. Clamped to 45 seconds; normal orchestrate calls return a queued preflight immediately.' },
286
+ inline: { type: 'boolean', description: 'Advanced/debug only: wait for inline orchestrate output instead of the default fast queued preflight.' }
286
287
  },
287
288
  required: ['prompt'],
288
289
  },
@@ -19,6 +19,7 @@ import { recordToolInvocation } from './tool-health.js';
19
19
  import { getAsyncGate, withAsyncGate } from './async-gate.js';
20
20
  import { getCircuitManager, checkBackpressure } from './circuit.js';
21
21
  import { completeRun, createRun, failRun, updateStage } from '../../../engines/orchestrator/store.js';
22
+ import { buildSelectionPlan } from '../../../engines/orchestrator/decision-spine.js';
22
23
  function summarizeAsyncMcpResult(toolName, result) {
23
24
  const text = result?.content
24
25
  ?.map((part) => part?.type === 'text' ? String(part.text ?? '') : '')
@@ -99,6 +100,9 @@ function coerceBoundedWaitMs(value) {
99
100
  function shouldReturnQueuedReceipt(toolName, args) {
100
101
  if (!SLOW_TOOLS.has(toolName))
101
102
  return false;
103
+ if (toolName === 'nexus_orchestrate') {
104
+ return !isTruthyFlag(args.inline) && !isTruthyFlag(args.sync) && !isTruthyFlag(args.blocking);
105
+ }
102
106
  return isTruthyFlag(args.background)
103
107
  || isTruthyFlag(args.async)
104
108
  || isTruthyFlag(args.queue)
@@ -109,6 +113,158 @@ function resolveMaxSyncMs(toolName, args) {
109
113
  ?? coerceBoundedWaitMs(args.maxSyncMs)
110
114
  ?? (toolName === 'nexus_orchestrate' ? ORCHESTRATE_DEFAULT_MAX_SYNC_MS : DEFAULT_MAX_SYNC_MS);
111
115
  }
116
+ function asStringList(value) {
117
+ if (Array.isArray(value)) {
118
+ return value
119
+ .map((item) => typeof item === 'string' ? item : (item && typeof item === 'object' ? String(item.name ?? item.id ?? '') : String(item ?? '')))
120
+ .map((item) => item.trim())
121
+ .filter(Boolean);
122
+ }
123
+ if (typeof value === 'string') {
124
+ return value.split(',')
125
+ .map((item) => item.trim())
126
+ .filter(Boolean);
127
+ }
128
+ return [];
129
+ }
130
+ function uniqueList(items, max = 8) {
131
+ const seen = new Set();
132
+ const out = [];
133
+ for (const item of items) {
134
+ const value = String(item ?? '').trim();
135
+ if (!value || seen.has(value))
136
+ continue;
137
+ seen.add(value);
138
+ out.push(value);
139
+ if (out.length >= max)
140
+ break;
141
+ }
142
+ return out;
143
+ }
144
+ function extractLinkedSelectors(prompt, prefix) {
145
+ const escaped = prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
146
+ const pattern = new RegExp(`\\[${escaped}([^\\]\\s]+)\\]`, 'g');
147
+ return Array.from(prompt.matchAll(pattern))
148
+ .map((match) => match[1]?.trim())
149
+ .filter(Boolean);
150
+ }
151
+ function inferQueuedOrchestratePreview(args, runId) {
152
+ const prompt = String(args.prompt ?? args.goal ?? '');
153
+ const lower = prompt.toLowerCase();
154
+ const files = uniqueList([
155
+ ...asStringList(args.files),
156
+ ...asStringList(args.filePaths),
157
+ ], 20);
158
+ const skills = uniqueList([
159
+ ...asStringList(args.skills),
160
+ ...asStringList(args.skillNames),
161
+ ...extractLinkedSelectors(prompt, '$'),
162
+ ], 20);
163
+ const isRuntimeControlPlane = /orchestrat|synapse|architect|runtime|mcp|dispatch|route|routing|queue|queued|scheduler|model routing|worker|hiring|workflow selection|token|budget|memory|lifecycle/.test(lower);
164
+ const wantsResearch = /research|paper|literature|deep-research|source-grounded|cited/.test(lower);
165
+ const wantsMemory = /memory|recall|learning|decay|graph|mcp/.test(lower);
166
+ const wantsPerf = /fast|faster|millisecond|latency|performance|budget|token|optim/i.test(lower);
167
+ const workflows = uniqueList([
168
+ ...asStringList(args.workflows),
169
+ ...asStringList(args.workflowSelectors),
170
+ isRuntimeControlPlane ? 'orchestration-execution-loop' : undefined,
171
+ isRuntimeControlPlane ? 'backend-execution-loop' : undefined,
172
+ isRuntimeControlPlane ? 'testing-execution-loop' : undefined,
173
+ isRuntimeControlPlane && !wantsResearch ? 'typescript-execution-loop' : undefined,
174
+ wantsResearch ? 'research-and-implement' : undefined,
175
+ lower.match(/dashboard|board|ui|ux/) && !isRuntimeControlPlane ? 'frontend-execution-loop' : undefined,
176
+ ], 8);
177
+ const specialists = uniqueList([
178
+ ...asStringList(args.specialists),
179
+ isRuntimeControlPlane ? 'Agents Orchestrator' : undefined,
180
+ isRuntimeControlPlane ? 'Backend Architect' : undefined,
181
+ isRuntimeControlPlane ? 'Workflow Optimizer' : undefined,
182
+ wantsPerf ? 'Performance Benchmarker' : undefined,
183
+ wantsMemory && !wantsPerf ? 'Backend Architect' : undefined,
184
+ lower.match(/dashboard|board|ui|ux/) && !isRuntimeControlPlane ? 'Frontend Developer' : undefined,
185
+ lower.match(/test|verify|qa|release|publish/) ? 'Verification Engineer' : undefined,
186
+ ], 8);
187
+ const crew = String(args.crew ?? args.selectedCrew ?? (lower.match(/orchestrat|synapse|runtime|mcp|dispatch|queue|queued/)
188
+ ? 'Implementation Crew'
189
+ : lower.match(/research|paper|literature/)
190
+ ? 'Research Crew'
191
+ : 'Implementation Crew'));
192
+ const risk = lower.match(/fix|broken|bug|doesn.?t|failed|queued|runtime|synapse|orchestrat/) ? 'high' : 'medium';
193
+ const task = {
194
+ goal: prompt,
195
+ intent: lower.match(/fix|bug|broken|doesn.?t|failed/) ? 'bugfix' : 'feature',
196
+ files,
197
+ skillNames: skills,
198
+ workflowSelectors: workflows,
199
+ };
200
+ const workerManifests = uniqueList([
201
+ specialists.length > 0 ? 'worker_coder' : undefined,
202
+ 'worker_verifier',
203
+ ]).map((workerId, index) => ({
204
+ workerId,
205
+ role: index === 0 ? 'coder' : 'verifier',
206
+ specialistName: index === 0 ? specialists[0] : 'Verification Engineer',
207
+ actions: index === 0 ? ['inspect', 'patch'] : ['verify'],
208
+ verifyCommands: index === 1 ? ['npm run lint', 'targeted tests'] : [],
209
+ }));
210
+ const run = {
211
+ runId,
212
+ requestBrief: {
213
+ id: `brief_${runId}`,
214
+ intent: task.intent,
215
+ risk,
216
+ confidence: 0.68,
217
+ },
218
+ plannerResult: {
219
+ selectedFiles: files,
220
+ selectedSkills: skills,
221
+ selectedWorkflows: workflows,
222
+ selectedSpecialists: specialists.map((name) => ({ name })),
223
+ selectedCrew: { name: crew },
224
+ },
225
+ workerManifests,
226
+ };
227
+ const plan = buildSelectionPlan({ run, task });
228
+ return { plan, crew, specialists, workflows };
229
+ }
230
+ function formatBudgetRoute(plan) {
231
+ const total = Number(plan.budgets?.total ?? 0);
232
+ const code = Number(plan.budgets?.codeBlocks ?? plan.budgets?.codeBlockPolicy?.reservedTokens ?? 0);
233
+ const cap = Number(plan.executionPolicy?.agentFlow?.maxTaskCostUsd ?? plan.executionPolicy?.budgetCapUsd ?? 0);
234
+ return `${total.toLocaleString()} tokens · ${code.toLocaleString()} code-block tokens · $${cap.toFixed(2)} task cap`;
235
+ }
236
+ function formatQueuedOrchestrateReceipt(args, receipt) {
237
+ const preview = inferQueuedOrchestratePreview(args, receipt.runId);
238
+ const plan = preview.plan;
239
+ const stages = Array.isArray(plan.executionPolicy?.agentFlow?.stages)
240
+ ? plan.executionPolicy.agentFlow.stages
241
+ : [];
242
+ const selected = plan.selected ?? {};
243
+ const specialists = uniqueList([...(selected.specialists ?? []), ...preview.specialists], 8);
244
+ const workflows = uniqueList([...(selected.workflows ?? []), ...preview.workflows], 8);
245
+ const skills = uniqueList(selected.skills ?? [], 8);
246
+ const receiptJson = JSON.stringify({ queued: true, runId: receipt.runId, etaMs: receipt.etaMs }, null, 2);
247
+ const hiredLine = [
248
+ `crew ${preview.crew}`,
249
+ specialists.length ? `specialists ${specialists.join(', ')}` : '',
250
+ workflows.length ? `workflows ${workflows.join(', ')}` : '',
251
+ skills.length ? `skills ${skills.join(', ')}` : '',
252
+ ].filter(Boolean).join(' · ');
253
+ return [
254
+ 'Nexus orchestration queued with hiring preflight.',
255
+ `Run: ${receipt.runId}`,
256
+ `ETA: ${receipt.etaMs ? `~${Math.ceil(receipt.etaMs / 1000)}s` : 'background'}`,
257
+ `Hired/selected: ${hiredLine}`,
258
+ `Model route: ${plan.modelRoute?.workerTier ?? 'T1'}${plan.modelRoute?.reviewerTier ? ` + reviewer ${plan.modelRoute.reviewerTier}` : ''}`,
259
+ `Budget route: ${formatBudgetRoute(plan)}`,
260
+ stages.length ? `AgentFlow gates: ${stages.map((stage) => `${stage.stage}:${stage.ownerRole}`).join(' -> ')}` : '',
261
+ 'Poll progress with nexus_run_status(runId).',
262
+ '',
263
+ '```json',
264
+ receiptJson,
265
+ '```',
266
+ ].filter((line) => line !== '').join('\n');
267
+ }
112
268
  /**
113
269
  * Route a tool call to the appropriate handler group.
114
270
  *
@@ -232,8 +388,10 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
232
388
  rawResult = {
233
389
  content: [{
234
390
  type: 'text',
235
- text: JSON.stringify({ queued: true, runId: gated.runId, etaMs: gated.etaMs }, null, 2)
236
- + '\n\nCall nexus_run_status(runId) to check progress.',
391
+ text: toolName === 'nexus_orchestrate'
392
+ ? formatQueuedOrchestrateReceipt(args, gated)
393
+ : JSON.stringify({ queued: true, runId: gated.runId, etaMs: gated.etaMs }, null, 2)
394
+ + '\n\nCall nexus_run_status(runId) to check progress.',
237
395
  }],
238
396
  };
239
397
  }
@@ -183,6 +183,8 @@ export declare class OrchestratorEngine {
183
183
  private searchIndexedRepoCandidates;
184
184
  private toFileRef;
185
185
  private resolveSelections;
186
+ private inferRuntimeCatalogHints;
187
+ private filterExistingCatalogSelectors;
186
188
  private getSkillCatalogItems;
187
189
  private getWorkflowCatalogItems;
188
190
  private getHookCatalogItems;
@@ -2382,10 +2382,16 @@ export class OrchestratorEngine {
2382
2382
  limit: 5,
2383
2383
  selector: 'name',
2384
2384
  });
2385
- const workflowSelection = this.resolveCatalogVotes('workflow', task, intent, options.workflowSelectors?.length ? allWorkflowItems : workflowItems, {
2385
+ const runtimeCatalogHints = this.inferRuntimeCatalogHints(task, intent, {
2386
+ workflows: allWorkflowItems,
2387
+ specialists: allSpecialistItems,
2388
+ crews: allCrewItems,
2389
+ });
2390
+ const workflowSelection = this.resolveCatalogVotes('workflow', task, intent, options.workflowSelectors?.length || runtimeCatalogHints.workflows.length ? allWorkflowItems : workflowItems, {
2386
2391
  explicit: options.workflowSelectors,
2387
2392
  planner: planner.selectedWorkflows,
2388
2393
  knowledge: knowledgeFabric.recommendations.workflows,
2394
+ runtime: runtimeCatalogHints.workflows,
2389
2395
  scorerLimit: 4,
2390
2396
  limit: 4,
2391
2397
  selector: 'name',
@@ -2423,18 +2429,20 @@ export class OrchestratorEngine {
2423
2429
  limit: intent.taskType === 'release' || this.sessionState.repeatedFailures > 0 ? 3 : 2,
2424
2430
  selector: 'name',
2425
2431
  });
2426
- const specialistSelection = this.resolveCatalogVotes('specialist', task, intent, options.specialistSelectors?.length ? allSpecialistItems : specialistItems, {
2432
+ const specialistSelection = this.resolveCatalogVotes('specialist', task, intent, options.specialistSelectors?.length || runtimeCatalogHints.specialists.length ? allSpecialistItems : specialistItems, {
2427
2433
  explicit: options.specialistSelectors,
2428
2434
  planner: planner.selectedSpecialists.map((specialist) => specialist.specialistId),
2429
2435
  knowledge: knowledgeFabric.recommendations.specialists,
2436
+ runtime: runtimeCatalogHints.specialists,
2430
2437
  scorerLimit: 4,
2431
2438
  limit: 4,
2432
2439
  selector: 'id',
2433
2440
  });
2434
- const crewSelection = this.resolveCatalogVotes('crew', task, intent, options.crewSelectors?.length ? allCrewItems : crewItems, {
2441
+ const crewSelection = this.resolveCatalogVotes('crew', task, intent, options.crewSelectors?.length || runtimeCatalogHints.crews.length ? allCrewItems : crewItems, {
2435
2442
  explicit: options.crewSelectors,
2436
2443
  planner: planner.selectedCrew ? [planner.selectedCrew.crewId] : [],
2437
2444
  knowledge: knowledgeFabric.recommendations.crews,
2445
+ runtime: runtimeCatalogHints.crews,
2438
2446
  scorerLimit: 2,
2439
2447
  limit: 1,
2440
2448
  selector: 'id',
@@ -2504,6 +2512,47 @@ export class OrchestratorEngine {
2504
2512
  },
2505
2513
  };
2506
2514
  }
2515
+ inferRuntimeCatalogHints(task, intent, catalog) {
2516
+ const lower = task.toLowerCase();
2517
+ const isControlPlane = /\b(orchestrat(?:e|or|ion)|synapse|architects?|mcp|dispatch|routing|route|queued?|queue|scheduler|runtime|control plane|agentflow|worker|hiring|specialist|crew|workflow selection|model routing|token budget|memory hook|memory graph|lifecycle)\b/.test(lower);
2518
+ if (!isControlPlane) {
2519
+ return { workflows: [], specialists: [], crews: [] };
2520
+ }
2521
+ const wantsResearch = /\b(research|papers?|literature|source-grounded|cited|deep-research)\b/.test(lower);
2522
+ const wantsMemory = /\b(memory|recall|learning|decay|graph|mcp)\b/.test(lower);
2523
+ const wantsPerf = /\b(fast|faster|milliseconds?|latency|performance|budget|token|optim(?:i|is|iz))\b/.test(lower);
2524
+ const readOnlyResearch = intent.taskType === 'research'
2525
+ && !/\b(fix|patch|implement|refactor|change|add|wire|ship|deploy|release|mutate|improve)\b/.test(lower);
2526
+ const workflowSelectors = [
2527
+ 'orchestration-execution-loop',
2528
+ 'backend-execution-loop',
2529
+ 'testing-execution-loop',
2530
+ wantsResearch ? 'research-and-implement' : 'typescript-execution-loop',
2531
+ ];
2532
+ const specialistSelectors = [
2533
+ 'specialist_specialized-agents-orchestrator',
2534
+ 'specialist_engineering-engineering-backend-architect',
2535
+ 'specialist_testing-testing-workflow-optimizer',
2536
+ wantsPerf
2537
+ ? 'specialist_testing-testing-performance-benchmarker'
2538
+ : wantsMemory
2539
+ ? 'specialist_integrations-mcp-memory-backend-architect-with-memory'
2540
+ : undefined,
2541
+ ];
2542
+ const crewSelectors = [
2543
+ readOnlyResearch ? 'crew_research' : 'crew_implementation',
2544
+ ];
2545
+ return {
2546
+ workflows: this.filterExistingCatalogSelectors(catalog.workflows, workflowSelectors, 'name'),
2547
+ specialists: this.filterExistingCatalogSelectors(catalog.specialists, specialistSelectors, 'id'),
2548
+ crews: this.filterExistingCatalogSelectors(catalog.crews, crewSelectors, 'id'),
2549
+ };
2550
+ }
2551
+ filterExistingCatalogSelectors(items, selectors, selector) {
2552
+ const existing = new Set(items.map((item) => selector === 'id' ? item.id : item.name));
2553
+ return dedupeStrings(selectors.filter((value) => Boolean(value)))
2554
+ .filter((value) => existing.has(value));
2555
+ }
2507
2556
  getSkillCatalogItems() {
2508
2557
  const skills = this.runtime.listSkillsForSelection();
2509
2558
  const signature = skills
@@ -2657,7 +2706,7 @@ export class OrchestratorEngine {
2657
2706
  applyVote(value, 'knowledge-fabric', 0.76, 'medium', 'Knowledge Fabric recommended this artifact from cross-source evidence.');
2658
2707
  });
2659
2708
  (input.runtime ?? []).forEach((value) => {
2660
- applyVote(value, 'runtime-resolver', 0.84, 'high', 'Runtime resolver matched this artifact against the registered catalog for the active goal.');
2709
+ applyVote(value, 'runtime-resolver', 2.0, 'high', 'Runtime resolver matched this artifact against the registered catalog for the active goal.');
2661
2710
  });
2662
2711
  this.pickCatalogEntries(task, intent, items, input.scorerLimit).forEach((entry) => {
2663
2712
  applyVote(input.selector === 'id' ? entry.item.id : entry.item.name, 'scorer', Math.min(0.7, entry.score / 10), entry.score >= 9 ? 'medium' : 'low', `Keyword scorer matched the task with score ${entry.score}.`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexus-prime",
3
- "version": "7.9.23",
3
+ "version": "7.9.25",
4
4
  "description": "Local-first MCP control plane for coding agents with bootstrap-orchestrate execution, memory fabric, token budgeting, and worktree-backed swarms",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",