← Files ForgeMindARCHIVED FILE

src/router.mjs

3.93 KB · Oct 2, 2026 · 00:31 UTC

↓ Download file

import { evaluateAction } from './policy.mjs';

const BASE_ROUTES = {
  bug: 'forgemind-build',
  feature: 'forgemind-build',
  innovation: 'forgemind-explore',
  release: 'forgemind-verify',
  security: 'forgemind-verify',
};

const ROUTE_TOKEN_COST = {
  'forgemind-guide': 180,
  'forgemind-explore': 700,
  'forgemind-plan': 550,
  'forgemind-build': 500,
  'forgemind-verify': 450,
  'forgemind-learn': 350,
};

export function recommendRoute({ profile, task, outcomes = [], policy, routing = {} }) {
  const base = BASE_ROUTES[task.category] ?? 'forgemind-guide';
  const matching = outcomes.filter((outcome) =>
    outcome.taskCategory === task.category && stackMatch(profile.stacks ?? [], outcome.project?.stacks ?? []),
  );
  const scores = new Map([[base, 1]]);
  for (const outcome of matching) {
    const route = normalizeRoute(outcome.route);
    scores.set(route, (scores.get(route) ?? 0) + outcome.effectiveness);
  }
  const ranked = [...scores.entries()].sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]));
  let primaryRoute = ranked[0][0];
  let alternative = ranked.find(([route]) => route !== primaryRoute)?.[0] ?? (primaryRoute === base ? 'forgemind-guide' : base);
  const missingEvidence = [];
  if (!matching.length) missingEvidence.push('matching-outcomes');
  if (!BASE_ROUTES[task.category]) missingEvidence.push('known-task-category');
  const selectedEvidence = matching.filter((outcome) => normalizeRoute(outcome.route) === primaryRoute).map((outcome) => outcome.id).sort();
  const margin = ranked[0][1] - (ranked[1]?.[1] ?? 0);
  let confidence = !BASE_ROUTES[task.category] ? 0.3 : matching.length ? Math.min(0.95, 0.55 + selectedEvidence.length * 0.1 + margin * 0.05) : 0.45;
  let escalation = { decision: 'none', source: null, rationale: 'No elevated task risk declared.' };
  if (task.risk) {
    escalation = evaluateAction(policy, { kind: task.risk, path: task.path });
    if (escalation.decision === 'deny') {
      alternative = primaryRoute;
      primaryRoute = 'forgemind-guide';
      confidence = 1;
    }
  }
  const maxSkillTokens = routing.maxSkillTokens ?? 800;
  const selectedCost = ROUTE_TOKEN_COST[primaryRoute] ?? 650;
  const alternativeCost = ROUTE_TOKEN_COST[alternative] ?? 650;
  const budget = { maxSkillTokens, selectedCost, decision: 'within-budget', fallback: null };
  if (escalation.decision !== 'deny' && selectedCost > maxSkillTokens && alternativeCost <= maxSkillTokens) {
    const previous = primaryRoute;
    primaryRoute = alternative;
    alternative = previous;
    budget.decision = 'fallback';
    budget.fallback = previous;
    confidence = Math.min(confidence, 0.7);
  } else if (escalation.decision !== 'deny' && selectedCost > maxSkillTokens) {
    budget.decision = 'escalate';
    budget.fallback = 'forgemind-guide';
  }
  return {
    schemaVersion: 1,
    primaryRoute,
    confidence: Number(confidence.toFixed(2)),
    evidence: selectedEvidence,
    alternative,
    escalation,
    budget,
    missingEvidence,
    rationale: selectedEvidence.length
      ? `${primaryRoute} has the strongest matching local outcome score.`
      : `${primaryRoute} is the safe base route for ${task.category ?? 'unknown'} tasks.`,
  };
}

function normalizeRoute(route) {
  if (Object.values(BASE_ROUTES).includes(route) || route === 'forgemind-guide' || route === 'forgemind-plan' || route === 'forgemind-learn') return route;
  if (['innovation-first-autopilot', 'idea-to-mvp', 'usp-ai-strategist'].includes(route)) return 'forgemind-explore';
  if (['finish-branch', 'security-reviewer', 'mvp-test-lab'].includes(route)) return 'forgemind-verify';
  if (['learning-loop', 'outcome-memory'].includes(route)) return 'forgemind-learn';
  return 'forgemind-build';
}

function stackMatch(current, historical) {
  if (!current.length || !historical.length) return true;
  return current.some((stack) => historical.includes(stack));
}

SHA-256: d47b21e2e0641e402e429cdf824565080ddac966abf91202fcd060ba9648c373