Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
1 line
16 KiB
JSON
1 line
16 KiB
JSON
{"repo": "atlansdaddy/atlan", "files": {"server/src/hierarchy.js": {"aac087b06a32f33ae50673f8537734b5d3cdf01c": {"t": 1786068264.4317994, "n": 15932, "h": "10e8bd618e3e5dfe", "c": "import { query } from '@anthropic-ai/claude-agent-sdk';\nimport { randomUUID } from 'node:crypto';\nimport { mkdirSync, readFileSync } from 'node:fs';\nimport { atomicWrite } from './fsutil.js';\nimport { join } from 'node:path';\nimport { FLEET_DIR } from './config.js';\nimport { listCommands, listPersonas, compilePersona, compileCommand, templateSchema, runCheckers } from './personas.js';\nimport { getStoredKey } from './keys.js';\n\n// Worker hierarchy — the approved schema, made runtime. A JOB is a chain of\n// scoped LINKS; each Link is a Persona+ structured command run by the CHEAPEST\n// capable worker on its ladder; deterministic checkers gate the output; a\n// checker failure ESCALATES up the model tier; a human gate pauses where\n// tier-3 (semantic-but-valid) risk concentrates. Decomposition is design-time\n// (authored links), execution is deterministic — no runtime planner in the loop.\nmkdirSync(FLEET_DIR, { recursive: true });\nconst JOBS_FILE = join(FLEET_DIR, 'hierarchy-jobs.json');\nconst loadJson = (p, f) => { try { return JSON.parse(readFileSync(p, 'utf8')); } catch { return f; } };\n\nlet broadcast = () => {};\nexport function initHierarchy(fn) { if (fn) broadcast = fn; }\n\n// The model ladder — cheapest first. Config-aware would override this later;\n// for now the honest default: free local → cheap cloud → frontier.\n// Tier endpoints are env-overridable (tests point local/cloud-sm at mock\n// engines to exercise the escalation ladder without real spend). An overridden\n// base needs no key.\nconst localBase = process.env.ATLAN_TIER_LOCAL_BASE || 'http://127.0.0.1:8080/v1';\n// Rungs spread across BOTH model strength and capability class, and every rung\n// is something this device can actually reach. The old middle rung was DeepSeek\n// behind DEEPSEEK_API_KEY — unconfigured, so every escalation threw\n// \"cloud-sm needs DEEPSEEK_API_KEY\", and it was also the ladder's only metered\n// step. Gemini 3.6 Flash replaces it: already keyed, verified free-tier, ~1.6s.\n// (Probed 2026-07-26: 3.6-flash is the ONLY text model this key reaches —\n// 3.1-flash / 3.1-pro / 3-pro / 3.6-pro all 404. No free rung exists between\n// Flash and frontier, so the ladder is three rungs, not four.)\nconst cloudBase = process.env.ATLAN_TIER_CLOUDSM_BASE || 'https://generativelanguage.googleapis.com/v1beta/openai';\nexport const TIERS = {\n // constrained = grammar/schema-locked JSON out\n local: { engine: 'local', base: localBase, keyEnv: null, model: 'qwen', constrained: true, label: 'on-phone Qwen (free)' },\n 'cloud-sm': { engine: 'gemini', base: cloudBase, keyEnv: process.env.ATLAN_TIER_CLOUDSM_BASE ? null : 'GEMINI_API_KEY', model: 'gemini-3.6-flash', constrained: true, label: 'Gemini Flash (free tier)' },\n // Opus 5 rather than Fable 5: it leads SWE-bench Verified (~80.8%) for the\n // code-shaped work this rung catches, and Fable's thinking cannot be disabled.\n // Both run on the subscription via frontierExecute, so this is a capability\n // choice, not a cost one — set ATLAN_TIER_FRONTIER_MODEL to override.\n frontier: { engine: 'claude', base: null, keyEnv: null, model: process.env.ATLAN_TIER_FRONTIER_MODEL || 'claude-opus-5', constrained: false, label: 'Claude Opus 5 (frontier)' },\n};\nexport const tierList = Object.entries(TIERS).map(([id, t]) => ({ id, label: t.label, constrained: t.constrained }));\n\n// ── job store (authored plans persist; runs are in-memory + audit-logged) ──\nlet jobs = loadJson(JOBS_FILE, []);\nconst saveJobs = () => atomicWrite(JOBS_FILE, JSON.stringify(jobs, null, 1));\nexport function listJobs() { return jobs.map(publicJob); }\nfunction publicJob(j) {\n return { id: j.id, title: j.title, humanGate: j.humanGate, maxEscalations: j.maxEscalations, budget: j.budget, links: j.links };\n}\n\nconst S = (v, n = 400) => String(v ?? '').slice(0, n).trim();\nexport function upsertJob(input) {\n const links = (Array.isArray(input.links) ? input.links : []).slice(0, 30).map((l) => ({\n id: S(l.id, 40).replace(/\\W/g, '_') || randomUUID().slice(0, 6),\n commandId: S(l.commandId, 40),\n inputsFrom: (Array.isArray(l.inputsFrom) ? l.inputsFrom : []).slice(0, 12).map((x) => S(x, 80)),\n startTier: TIERS[l.startTier] ? l.startTier : 'local',\n escalation: (Array.isArray(l.escalation) ? l.escalation : ['local', 'cloud-sm', 'frontier']).filter((t) => TIERS[t]),\n onCheckerFail: ['escalate', 'human', 'halt'].includes(l.onCheckerFail) ? l.onCheckerFail : 'escalate',\n humanGate: !!l.humanGate,\n })).filter((l) => l.commandId);\n const out = {\n id: input.id && jobs.some((j) => j.id === input.id) ? input.id : randomUUID().slice(0, 8),\n title: S(input.title, 120) || 'untitled job',\n humanGate: ['never', 'final', 'each-link', 'on-tier3'].includes(input.humanGate) ? input.humanGate : 'on-tier3',\n maxEscalations: Math.max(0, Math.min(5, Number(input.maxEscalations) || 2)),\n budget: Math.max(1000, Math.min(2_000_000, Number(input.budget) || 200000)),\n links,\n };\n if (!links.length) throw new Error('a job needs at least one link (each link references a structured command)');\n for (const l of links) if (!listCommands().some((c) => c.id === l.commandId)) throw new Error(`link \"${l.id}\": no such command ${l.commandId}`);\n jobs = [out, ...jobs.filter((j) => j.id !== out.id)].slice(0, 100);\n saveJobs();\n return publicJob(out);\n}\nexport function deleteJob(id) {\n const n = jobs.length;\n jobs = jobs.filter((j) => j.id !== id);\n saveJobs();\n return jobs.length < n;\n}\n\n// ── execution ──\nconst runs = new Map(); // runId → live run state\nexport function listRuns() { return [...runs.values()].map(publicRunState); }\nexport function getRun(id) { const r = runs.get(id); return r ? publicRunState(r) : null; }\nfunction publicRunState(r) {\n return {\n id: r.id, jobId: r.jobId, title: r.title, status: r.status,\n tokens: r.tokens, budget: r.budget, startedAt: r.startedAt, endedAt: r.endedAt,\n steps: r.steps.map((s) => ({\n linkId: s.linkId, command: s.command, status: s.status, tier: s.tier,\n escalations: s.escalations, tokens: s.tokens, passed: s.passed,\n checks: s.checks, output: s.output, note: s.note,\n })),\n awaiting: r.awaiting, // { linkId } when paused at a human gate\n result: r.result,\n };\n}\n\nfunction emit(r) { broadcast({ t: 'hierarchy.update', run: publicRunState(r) }); }\n\nexport function startJob(jobId, jobInput = {}) {\n const job = jobs.find((j) => j.id === jobId);\n if (!job) throw new Error('no such job');\n const run = {\n id: randomUUID().slice(0, 8), jobId: job.id, title: job.title, job,\n status: 'running', tokens: 0, budget: job.budget, startedAt: Date.now(), endedAt: null,\n blackboard: { 'job.input': jobInput }, steps: [], awaiting: null, result: null,\n };\n runs.set(run.id, run);\n emit(run);\n execJob(run).catch((err) => { run.status = 'error'; run.result = String(err?.message ?? err); run.endedAt = Date.now(); emit(run); });\n return publicRunState(run);\n}\n\n// resume a run paused at a human gate: approve (optionally edited output) or reject\nexport function resolveGate(runId, { approve, editedOutput = null } = {}) {\n const run = runs.get(runId);\n if (!run || !run.awaiting) throw new Error('run is not awaiting a human gate');\n const resolver = run._gateResolver;\n run.awaiting = null;\n run._gateResolver = null;\n resolver?.({ approve: !!approve, editedOutput });\n return publicRunState(run);\n}\n\nasync function execJob(run) {\n const { job } = run;\n for (const link of job.links) {\n if (run.status !== 'running') break;\n const cmd = listCommands().find((c) => c.id === link.commandId);\n const step = { linkId: link.id, command: cmd?.name ?? '(missing)', status: 'running', tier: link.startTier, escalations: 0, tokens: 0, passed: false, checks: [], output: null, note: '' };\n run.steps.push(step);\n emit(run);\n if (!cmd) { step.status = 'error'; step.note = 'command deleted'; run.status = 'error'; run.result = `link ${link.id}: command missing`; break; }\n\n const vars = resolveInputs(link, run.blackboard, jobInputOf(run));\n let tierIdx = Math.max(0, link.escalation.indexOf(link.startTier));\n let done = false;\n while (!done) {\n const tierId = link.escalation[tierIdx];\n step.tier = tierId;\n emit(run);\n let out, verdict, err = null;\n try {\n out = await callTier(tierId, cmd, vars, run);\n verdict = runCheckers(cmd, out, vars);\n } catch (e) { err = e; verdict = { passed: false, results: [{ tier: 0, check: 'engine', ok: false, got: String(e.message).slice(0, 120) }] }; }\n step.tokens += out?._tokens ?? 0;\n run.tokens += out?._tokens ?? 0;\n step.checks = verdict.results;\n step.output = out && !err ? stripMeta(out) : null;\n\n if (run.tokens >= run.budget) { step.status = 'halted'; step.note = 'job budget hit'; run.status = 'halted-budget'; done = true; break; }\n\n if (verdict.passed) {\n // human gate where configured / where tier-3 risk concentrates\n const gate = link.humanGate || job.humanGate === 'each-link'\n || (job.humanGate === 'on-tier3' && link.escalation.length && tierId === link.escalation[link.escalation.length - 1]);\n if (gate) {\n const decision = await humanGate(run, step);\n if (!decision.approve) { step.status = 'rejected'; step.note = 'you rejected this output'; run.status = 'halted'; run.result = `stopped at ${link.id} (human reject)`; done = true; break; }\n if (decision.editedOutput) step.output = decision.editedOutput;\n }\n step.status = 'done'; step.passed = true;\n run.blackboard[link.id] = step.output;\n done = true;\n } else if (tierIdx < link.escalation.length - 1 && step.escalations < job.maxEscalations && link.onCheckerFail === 'escalate') {\n step.escalations++; tierIdx++; step.note = `checks failed → escalating to ${link.escalation[tierIdx]}`;\n emit(run);\n } else if (link.onCheckerFail === 'human') {\n const decision = await humanGate(run, step);\n if (decision.approve) { step.status = 'done'; step.passed = true; step.output = decision.editedOutput ?? step.output; run.blackboard[link.id] = step.output; }\n else { step.status = 'failed'; run.status = 'halted'; run.result = `stopped at ${link.id}`; }\n done = true;\n } else {\n step.status = 'failed'; step.note = 'checks failed, ladder exhausted';\n run.status = 'error'; run.result = `link ${link.id} failed its checkers`;\n done = true;\n }\n }\n if (run.status !== 'running') break;\n }\n if (run.status === 'running') { run.status = 'done'; run.result = assemble(run); }\n run.endedAt = Date.now();\n emit(run);\n}\n\n// Frontier execution: a no-tools Agent SDK query, awaited, returns text+tokens.\nasync function frontierExecute(prompt, model) {\n const q = query({\n prompt,\n options: {\n model,\n settingSources: [],\n maxTurns: 1,\n systemPrompt: { type: 'preset', preset: 'claude_code', excludeDynamicSections: true },\n disallowedTools: ['Bash', 'Edit', 'Write', 'Read', 'Grep', 'Glob', 'LS', 'WebFetch', 'WebSearch', 'Task', 'TodoWrite', 'NotebookEdit'],\n },\n });\n let text = '', tokens = 0;\n for await (const m of q) {\n if (m.type === 'assistant') {\n for (const b of m.message?.content ?? []) if (b.type === 'text') text += b.text;\n const u = m.message?.usage;\n if (u) tokens += (u.input_tokens ?? 0) + (u.output_tokens ?? 0) + (u.cache_creation_input_tokens ?? 0);\n }\n }\n return { text, tokens };\n}\n\nfunction jobInputOf(run) { return run.blackboard['job.input'] ?? {}; }\n// inputsFrom wiring: \"job.input.x\" or \"<linkId>.<field>\" or bare \"<linkId>\"\nfunction resolveInputs(link, blackboard, jobInput) {\n const vars = {};\n for (const ref of link.inputsFrom) {\n const [head, ...rest] = ref.split('.');\n if (head === 'job') { const key = rest.slice(1).join('.') || rest[0]; vars[rest[rest.length - 1] || 'input'] = dig(jobInput, rest.slice(1)); }\n else {\n const src = blackboard[head];\n const field = rest.join('.');\n vars[field || head] = field ? dig(src, rest) : src;\n }\n }\n // also expose the raw job input fields by name for convenience\n if (jobInput && typeof jobInput === 'object') for (const [k, v] of Object.entries(jobInput)) if (!(k in vars)) vars[k] = v;\n return vars;\n}\nfunction dig(obj, path) { return path.reduce((o, k) => (o == null ? o : o[k]), obj); }\nfunction stripMeta(o) { if (o && typeof o === 'object') { const { _tokens, ...rest } = o; return rest; } return o; }\n\nfunction humanGate(run, step) {\n run.awaiting = { linkId: step.linkId };\n step.status = 'awaiting-you';\n emit(run);\n return new Promise((resolve) => { run._gateResolver = resolve; });\n}\n\nfunction assemble(run) {\n // deterministic final: the last link's output, plus the full blackboard\n const last = run.steps[run.steps.length - 1];\n return { final: last?.output ?? null, blackboard: run.blackboard, audit: run.steps.map((s) => ({ link: s.linkId, tier: s.tier, escalations: s.escalations, tokens: s.tokens })) };\n}\n\n// Run a compiled command at a given tier. Frontier uses a real fleet run\n// (has hands); local/cloud use constrained OpenAI-compat chat completions.\nasync function callTier(tierId, cmd, vars, run) {\n const tier = TIERS[tierId];\n const persona = listPersonas().find((p) => p.id === cmd.personaId);\n if (tier.engine === 'claude') {\n // frontier tier: the Agent SDK, no tools, awaited to completion so its JSON\n // is checked and passed down the chain like any other tier's output.\n const prompt = `${persona ? compilePersona(persona) + '\\n\\n' : ''}${compileCommand(cmd, vars)}\\n\\n[Reply with ONLY the JSON object the template demands — no prose, no fences. This is a hierarchy escalation: a smaller model failed the deterministic checkers.]`;\n const { text, tokens } = await frontierExecute(prompt, tier.model);\n let parsed;\n try { parsed = JSON.parse(text.replace(/^```(json)?\\s*|\\s*```$/g, '').trim()); } catch { throw new Error('frontier output was not valid JSON'); }\n parsed._tokens = tokens;\n return parsed;\n }\n const key = tier.keyEnv ? (process.env[tier.keyEnv] || getStoredKey(tier.keyEnv)) : null;\n if (tier.keyEnv && !key) throw new Error(`${tierId} needs ${tier.keyEnv}`);\n const messages = [\n { role: 'system', content: (persona ? compilePersona(persona) + '\\n\\n' : '') + 'Execute one structured command; reply with ONLY the JSON object the template demands.' },\n { role: 'user', content: compileCommand(cmd, vars) },\n ];\n const res = await fetch(`${tier.base}/chat/completions`, {\n method: 'POST', headers: { 'content-type': 'application/json', ...(key ? { authorization: `Bearer ${key}` } : {}) },\n body: JSON.stringify({\n model: tier.model, messages, temperature: 0.1, stream: false,\n response_format: { type: 'json_schema', json_schema: { name: 'template', schema: templateSchema(cmd), strict: true } },\n // qwen3.5/3.6 ignore --reasoning-budget 0 and think themselves past any\n // token budget before the grammar ever fires; this kwarg is the real\n // off-switch. llama.cpp-only field — local tier only.\n ...(tierId === 'local' ? { chat_template_kwargs: { enable_thinking: false } } : {}),\n }),\n signal: AbortSignal.timeout(120000),\n });\n if (!res.ok) throw new Error(`${tierId} ${res.status}: ${(await res.text()).slice(0, 160)}`);\n const json = await res.json();\n const raw = json.choices?.[0]?.message?.content ?? '';\n let parsed;\n try { parsed = JSON.parse(raw.replace(/^```(json)?\\s*|\\s*```$/g, '')); } catch { throw new Error('output was not valid JSON'); }\n parsed._tokens = json.usage?.total_tokens ?? 0;\n return parsed;\n}\n"}}}} |