@defai.digital/automatosx 12.4.1 → 12.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/mcp/index.js CHANGED
@@ -8727,7 +8727,7 @@ var PRECOMPILED_CONFIG = {
8727
8727
  "enableFreeTierPrioritization": true,
8728
8728
  "enableWorkloadAwareRouting": true
8729
8729
  },
8730
- "version": "12.4.1"
8730
+ "version": "12.5.1"
8731
8731
  };
8732
8732
 
8733
8733
  // src/core/config/schemas.ts
@@ -20348,6 +20348,232 @@ ${context.task}`;
20348
20348
  }
20349
20349
  };
20350
20350
 
20351
+ // src/agents/agent-selector.ts
20352
+ init_esm_shims();
20353
+ init_logger();
20354
+ function scoreAgent(task, profile) {
20355
+ let score = 0;
20356
+ const taskLower = task.toLowerCase();
20357
+ if (profile.selectionMetadata?.primaryIntents) {
20358
+ for (const intent of profile.selectionMetadata.primaryIntents) {
20359
+ const intentKeywords = intent.toLowerCase().split(/\s+/);
20360
+ const matchedKeywords = intentKeywords.filter(
20361
+ (keyword) => taskLower.includes(keyword) && keyword.length > 3
20362
+ );
20363
+ if (matchedKeywords.length >= 2) {
20364
+ score += 10;
20365
+ } else if (matchedKeywords.length === 1) {
20366
+ score += 5;
20367
+ }
20368
+ }
20369
+ }
20370
+ if (profile.selectionMetadata?.secondarySignals) {
20371
+ for (const signal of profile.selectionMetadata.secondarySignals) {
20372
+ if (taskLower.includes(signal.toLowerCase())) {
20373
+ score += 5;
20374
+ }
20375
+ }
20376
+ }
20377
+ if (profile.selectionMetadata?.negativeIntents) {
20378
+ for (const negative of profile.selectionMetadata.negativeIntents) {
20379
+ const keywords = negative.split("(")[0]?.toLowerCase() || "";
20380
+ const negativeKeywords = keywords.split(/\s+/).filter((k) => k.length > 3);
20381
+ const matchedNegative = negativeKeywords.filter(
20382
+ (keyword) => taskLower.includes(keyword)
20383
+ );
20384
+ if (matchedNegative.length >= 2) {
20385
+ score -= 20;
20386
+ }
20387
+ }
20388
+ }
20389
+ if (profile.selectionMetadata?.redirectWhen) {
20390
+ for (const rule of profile.selectionMetadata.redirectWhen) {
20391
+ try {
20392
+ const regex = new RegExp(rule.phrase, "i");
20393
+ if (regex.test(task)) {
20394
+ score -= 15;
20395
+ }
20396
+ } catch (error) {
20397
+ logger.debug("Invalid regex pattern in redirectWhen rule", {
20398
+ pattern: rule.phrase,
20399
+ error: error instanceof Error ? error.message : String(error)
20400
+ });
20401
+ }
20402
+ }
20403
+ }
20404
+ if (profile.abilitySelection?.taskBased) {
20405
+ for (const keyword of Object.keys(profile.abilitySelection.taskBased)) {
20406
+ if (taskLower.includes(keyword.toLowerCase())) {
20407
+ score += 3;
20408
+ }
20409
+ }
20410
+ }
20411
+ return Math.max(0, score);
20412
+ }
20413
+ function buildRationale(task, profile) {
20414
+ const rationale = [];
20415
+ const taskLower = task.toLowerCase();
20416
+ if (profile.selectionMetadata?.primaryIntents) {
20417
+ const matchedIntents = profile.selectionMetadata.primaryIntents.filter((intent) => {
20418
+ const keywords = intent.toLowerCase().split(/\s+/);
20419
+ return keywords.some((k) => taskLower.includes(k) && k.length > 3);
20420
+ });
20421
+ if (matchedIntents.length > 0) {
20422
+ rationale.push(`Matches: ${matchedIntents.slice(0, 2).join(", ")}`);
20423
+ }
20424
+ }
20425
+ if (profile.selectionMetadata?.secondarySignals) {
20426
+ const matchedSignals = profile.selectionMetadata.secondarySignals.filter(
20427
+ (signal) => taskLower.includes(signal.toLowerCase())
20428
+ );
20429
+ if (matchedSignals.length > 0) {
20430
+ rationale.push(`Keywords: ${matchedSignals.slice(0, 3).join(", ")}`);
20431
+ }
20432
+ }
20433
+ if (profile.abilitySelection?.taskBased) {
20434
+ const matchedAbilities = Object.keys(profile.abilitySelection.taskBased).filter(
20435
+ (keyword) => taskLower.includes(keyword.toLowerCase())
20436
+ );
20437
+ if (matchedAbilities.length > 0) {
20438
+ rationale.push(`Abilities: ${matchedAbilities.slice(0, 2).join(", ")}`);
20439
+ }
20440
+ }
20441
+ if (rationale.length === 0) {
20442
+ rationale.push("General capability match");
20443
+ }
20444
+ return rationale;
20445
+ }
20446
+ function getConfidence(score) {
20447
+ if (score >= 30) return "high";
20448
+ if (score >= 15) return "medium";
20449
+ return "low";
20450
+ }
20451
+ var MIN_SELECTION_SCORE = 5;
20452
+ var FALLBACK_AGENT = "standard";
20453
+ var AgentSelector = class {
20454
+ profileLoader;
20455
+ constructor(profileLoader) {
20456
+ this.profileLoader = profileLoader;
20457
+ }
20458
+ /**
20459
+ * Select the best agent for a task
20460
+ *
20461
+ * @param task - Task description
20462
+ * @returns Selection result with agent, score, confidence, and rationale
20463
+ */
20464
+ async selectAgent(task) {
20465
+ logger.debug("[AgentSelector] Selecting agent for task", {
20466
+ taskPreview: task.substring(0, 100)
20467
+ });
20468
+ const agentNames = await this.profileLoader.listProfiles();
20469
+ if (agentNames.length === 0) {
20470
+ logger.warn("[AgentSelector] No agents found, using fallback");
20471
+ return this.createFallbackResult(task);
20472
+ }
20473
+ const profileResults = await Promise.all(
20474
+ agentNames.map(async (name) => {
20475
+ try {
20476
+ const profile = await this.profileLoader.loadProfile(name);
20477
+ return { name, profile, score: scoreAgent(task, profile) };
20478
+ } catch (error) {
20479
+ logger.debug(`[AgentSelector] Failed to load profile: ${name}`, { error });
20480
+ return null;
20481
+ }
20482
+ })
20483
+ );
20484
+ const scoredAgents = profileResults.filter(
20485
+ (result) => result !== null
20486
+ );
20487
+ if (scoredAgents.length === 0) {
20488
+ logger.warn("[AgentSelector] Failed to load any profiles, using fallback");
20489
+ return this.createFallbackResult(task);
20490
+ }
20491
+ scoredAgents.sort((a, b) => b.score - a.score);
20492
+ const best = scoredAgents[0];
20493
+ const alternatives = scoredAgents.slice(1, 4).map((a) => ({
20494
+ agent: a.name,
20495
+ score: a.score
20496
+ }));
20497
+ if (best.score < MIN_SELECTION_SCORE) {
20498
+ logger.info("[AgentSelector] Best score below threshold, using fallback", {
20499
+ bestAgent: best.name,
20500
+ bestScore: best.score,
20501
+ threshold: MIN_SELECTION_SCORE
20502
+ });
20503
+ const standardAgent = scoredAgents.find((a) => a.name === FALLBACK_AGENT);
20504
+ if (standardAgent) {
20505
+ return {
20506
+ agent: standardAgent.name,
20507
+ displayName: standardAgent.profile.displayName || standardAgent.name,
20508
+ role: standardAgent.profile.role,
20509
+ score: standardAgent.score,
20510
+ confidence: "low",
20511
+ rationale: ["No strong match found, using general-purpose agent"],
20512
+ alternatives: scoredAgents.filter((a) => a.name !== FALLBACK_AGENT).slice(0, 3).map((a) => ({ agent: a.name, score: a.score })),
20513
+ usedFallback: true
20514
+ };
20515
+ }
20516
+ return {
20517
+ agent: best.name,
20518
+ displayName: best.profile.displayName || best.name,
20519
+ role: best.profile.role,
20520
+ score: best.score,
20521
+ confidence: "low",
20522
+ rationale: ["Low confidence match - consider specifying agent explicitly"],
20523
+ alternatives,
20524
+ usedFallback: false
20525
+ };
20526
+ }
20527
+ const rationale = buildRationale(task, best.profile);
20528
+ const confidence = getConfidence(best.score);
20529
+ logger.info("[AgentSelector] Agent selected", {
20530
+ agent: best.name,
20531
+ score: best.score,
20532
+ confidence,
20533
+ rationale
20534
+ });
20535
+ return {
20536
+ agent: best.name,
20537
+ displayName: best.profile.displayName || best.name,
20538
+ role: best.profile.role,
20539
+ score: best.score,
20540
+ confidence,
20541
+ rationale,
20542
+ alternatives,
20543
+ usedFallback: false
20544
+ };
20545
+ }
20546
+ /**
20547
+ * Create a fallback result when no agents are available
20548
+ */
20549
+ async createFallbackResult(_task) {
20550
+ try {
20551
+ const profile = await this.profileLoader.loadProfile(FALLBACK_AGENT);
20552
+ return {
20553
+ agent: FALLBACK_AGENT,
20554
+ displayName: profile.displayName || FALLBACK_AGENT,
20555
+ role: profile.role,
20556
+ score: 0,
20557
+ confidence: "low",
20558
+ rationale: ["No agents available, using fallback"],
20559
+ alternatives: [],
20560
+ usedFallback: true
20561
+ };
20562
+ } catch {
20563
+ return {
20564
+ agent: FALLBACK_AGENT,
20565
+ displayName: "Standard",
20566
+ role: "General-purpose agent",
20567
+ score: 0,
20568
+ confidence: "low",
20569
+ rationale: ["No agents available"],
20570
+ alternatives: [],
20571
+ usedFallback: true
20572
+ };
20573
+ }
20574
+ }
20575
+ };
20576
+
20351
20577
  // src/mcp/tools/run-agent.ts
20352
20578
  init_logger();
20353
20579
 
@@ -20647,22 +20873,41 @@ async function buildAgentContext(agentName, task, deps, callerProvider, bestProv
20647
20873
  }
20648
20874
  function createRunAgentHandler(deps) {
20649
20875
  return async (input, context) => {
20650
- const { agent, task, provider, no_memory, mode = "auto" } = input;
20876
+ const { task, provider, no_memory, mode = "auto" } = input;
20877
+ let { agent } = input;
20651
20878
  if (context?.signal?.aborted) {
20652
20879
  throw new Error("Request was cancelled");
20653
20880
  }
20654
- validateAgentName(agent);
20655
20881
  validateStringParameter(task, "task", {
20656
20882
  required: true,
20657
20883
  minLength: 1,
20658
20884
  maxLength: 1e4
20659
20885
  });
20886
+ let autoSelected = false;
20887
+ if (!agent && deps.profileLoader) {
20888
+ const selector = new AgentSelector(deps.profileLoader);
20889
+ const selection = await selector.selectAgent(task);
20890
+ agent = selection.agent;
20891
+ autoSelected = true;
20892
+ logger.info("[MCP] run_agent auto-selected agent", {
20893
+ task: task.substring(0, 100),
20894
+ selectedAgent: agent,
20895
+ confidence: selection.confidence,
20896
+ score: selection.score,
20897
+ rationale: selection.rationale
20898
+ });
20899
+ }
20900
+ if (!agent) {
20901
+ throw new Error("Agent name is required when profileLoader is not available");
20902
+ }
20903
+ validateAgentName(agent);
20660
20904
  const actualProvider = mapMcpProviderToActual(provider);
20661
20905
  const session = deps.getSession?.() || null;
20662
20906
  const callerProvider = session?.normalizedProvider || "unknown";
20663
20907
  const callerActual = mapNormalizedCallerToActual(callerProvider);
20664
20908
  logger.info("[MCP] run_agent called (Smart Routing v10.5.0)", {
20665
20909
  agent,
20910
+ autoSelected,
20666
20911
  task: task.substring(0, 100),
20667
20912
  mcpProvider: provider,
20668
20913
  actualProvider,
@@ -21475,20 +21720,35 @@ init_logger();
21475
21720
  function createGetAgentContextHandler(deps) {
21476
21721
  return async (input) => {
21477
21722
  const {
21478
- agent,
21479
21723
  task,
21480
21724
  includeMemory = true,
21481
21725
  maxMemoryResults = 5
21482
21726
  } = input;
21727
+ let { agent } = input;
21483
21728
  const startTime = Date.now();
21484
- validateAgentName(agent);
21485
21729
  validateStringParameter(task, "task", {
21486
21730
  required: true,
21487
21731
  minLength: 1,
21488
21732
  maxLength: 1e4
21489
21733
  });
21734
+ let autoSelected = false;
21735
+ if (!agent) {
21736
+ const selector = new AgentSelector(deps.profileLoader);
21737
+ const selection = await selector.selectAgent(task);
21738
+ agent = selection.agent;
21739
+ autoSelected = true;
21740
+ logger.info("[MCP] get_agent_context auto-selected agent", {
21741
+ task: task.substring(0, 100),
21742
+ selectedAgent: agent,
21743
+ confidence: selection.confidence,
21744
+ score: selection.score,
21745
+ rationale: selection.rationale
21746
+ });
21747
+ }
21748
+ validateAgentName(agent);
21490
21749
  logger.info("[MCP] get_agent_context called", {
21491
21750
  agent,
21751
+ autoSelected,
21492
21752
  task: task.substring(0, 100),
21493
21753
  includeMemory,
21494
21754
  maxMemoryResults
@@ -26039,17 +26299,24 @@ var McpServer = class _McpServer {
26039
26299
  return [
26040
26300
  {
26041
26301
  name: "run_agent",
26042
- description: "Execute an AutomatosX agent with a specific task. Uses Smart Routing: returns context for same-provider calls, spawns cross-provider execution.",
26302
+ description: `Execute an AutomatosX agent with a specific task.
26303
+
26304
+ v12.5.1: Agent auto-selection - if agent is omitted, system automatically selects the best agent based on task keywords.
26305
+ Uses Smart Routing: returns context for same-provider calls, spawns cross-provider execution.
26306
+
26307
+ Examples:
26308
+ - With agent: run_agent({ agent: "backend", task: "implement API" })
26309
+ - Auto-select: run_agent({ task: "fix bugs in the codebase" }) \u2192 selects "quality" agent`,
26043
26310
  inputSchema: {
26044
26311
  type: "object",
26045
26312
  properties: {
26046
- agent: { type: "string", description: "The name of the agent to run (e.g., backend, Paris, Bob)" },
26313
+ agent: { type: "string", description: "Optional: Agent name (e.g., backend, quality). If omitted, best agent is auto-selected based on task." },
26047
26314
  task: { type: "string", description: "The task for the agent to perform" },
26048
26315
  provider: { type: "string", description: "Optional: Override the AI provider", enum: ["claude", "gemini", "openai"] },
26049
26316
  no_memory: { type: "boolean", description: "Optional: Skip memory injection", default: false },
26050
26317
  mode: { type: "string", description: "Optional: Execution mode - auto (default), context (always return context), execute (always spawn)", enum: ["auto", "context", "execute"], default: "auto" }
26051
26318
  },
26052
- required: ["agent", "task"]
26319
+ required: ["task"]
26053
26320
  }
26054
26321
  },
26055
26322
  {
@@ -26161,16 +26428,18 @@ Use this tool first to understand what AutomatosX offers.`,
26161
26428
  // v10.5.0: Smart Routing - Explicit context retrieval
26162
26429
  {
26163
26430
  name: "get_agent_context",
26164
- description: "Get agent context without executing. Returns profile, relevant memory, and enhanced prompt for AI assistant to execute directly.",
26431
+ description: `Get agent context without executing. Returns profile, relevant memory, and enhanced prompt for AI assistant to execute directly.
26432
+
26433
+ v12.5.1: Agent auto-selection - if agent is omitted, system automatically selects the best agent based on task keywords.`,
26165
26434
  inputSchema: {
26166
26435
  type: "object",
26167
26436
  properties: {
26168
- agent: { type: "string", description: "The name of the agent (e.g., backend, Paris, Bob)" },
26437
+ agent: { type: "string", description: "Optional: Agent name (e.g., backend, quality). If omitted, best agent is auto-selected based on task." },
26169
26438
  task: { type: "string", description: "The task description for context building" },
26170
26439
  includeMemory: { type: "boolean", description: "Include relevant memory entries (default: true)", default: true },
26171
26440
  maxMemoryResults: { type: "number", description: "Maximum memory entries to return (default: 5)", default: 5 }
26172
26441
  },
26173
- required: ["agent", "task"]
26442
+ required: ["task"]
26174
26443
  }
26175
26444
  },
26176
26445
  // v11.3.5: Task Engine tools
@@ -26179,6 +26448,8 @@ Use this tool first to understand what AutomatosX offers.`,
26179
26448
  getTaskResultSchema,
26180
26449
  listTasksSchema,
26181
26450
  deleteTaskSchema
26451
+ // v12.4.0: Bugfix tools intentionally NOT exposed via MCP
26452
+ // Access via: run_agent({ agent: "quality", task: "scan for bugs" })
26182
26453
  ];
26183
26454
  }
26184
26455
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defai.digital/automatosx",
3
- "version": "12.4.1",
3
+ "version": "12.5.1",
4
4
  "description": "Provider-agnostic AI orchestration platform with 20+ specialized agents, persistent memory, and multi-provider routing for Claude Code, Gemini CLI, Codex CLI, GLM, and Grok",
5
5
  "type": "module",
6
6
  "publishConfig": {