open-agents-ai 0.41.0 → 0.42.0

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.
Files changed (2) hide show
  1. package/dist/index.js +584 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23250,13 +23250,21 @@ var init_dream_engine = __esm({
23250
23250
  }
23251
23251
  let previousFindings = "";
23252
23252
  const cycleResults = [];
23253
+ const modelTier = getModelTier(this.config.model);
23253
23254
  for (const stage of SLEEP_STAGES) {
23254
23255
  if (this.abortController.signal.aborted)
23255
23256
  break;
23256
23257
  renderDreamStage(stage.name, stage.label, stage.description);
23257
23258
  const startMs = Date.now();
23258
- const prompt = buildDreamPrompt(mode, stage, cycle, totalCycles, previousFindings, this.dreamsDir);
23259
- const result = await this.runDreamAgent(prompt, mode === "lucid" ? "full" : "sandboxed", onEvent);
23259
+ let result;
23260
+ if (stage.name === "REM" && modelTier === "large") {
23261
+ renderInfo("REM: Multi-agent creative mode \u2014 parallel Visionary + Pragmatist + Cross-Pollinator");
23262
+ const remResult = await this.runMultiAgentREM(cycle, totalCycles, previousFindings, mode === "lucid" ? "full" : "sandboxed", onEvent);
23263
+ result = { summary: remResult.summary, turns: 0, toolCalls: 0 };
23264
+ } else {
23265
+ const prompt = buildDreamPrompt(mode, stage, cycle, totalCycles, previousFindings, this.dreamsDir);
23266
+ result = await this.runDreamAgent(prompt, mode === "lucid" ? "full" : "sandboxed", onEvent);
23267
+ }
23260
23268
  const durationMs = Date.now() - startMs;
23261
23269
  const cycleResult = {
23262
23270
  cycle,
@@ -23341,6 +23349,122 @@ Dreams directory: ${this.dreamsDir}`);
23341
23349
  toolCalls: result.toolCalls
23342
23350
  };
23343
23351
  }
23352
+ /**
23353
+ * Run a multi-agent REM stage — parallel creative voices that cross-pollinate.
23354
+ *
23355
+ * During real REM sleep, distant brain regions form novel associations through
23356
+ * reduced prefrontal inhibition (Walker 2017, "Why We Sleep"). This is modeled
23357
+ * as 3 parallel agents with distinct creative perspectives, whose outputs are
23358
+ * then synthesized by a consolidation agent.
23359
+ *
23360
+ * Architecture:
23361
+ * - Visionary: bold, transformative ideas (high temperature)
23362
+ * - Pragmatist: practical improvements grounded in current codebase
23363
+ * - Cross-Pollinator: draws inspiration from unrelated domains
23364
+ * - Synthesizer: merges all perspectives into actionable proposals
23365
+ */
23366
+ async runMultiAgentREM(cycleNum, totalCycles, previousFindings, toolMode, onEvent) {
23367
+ const dreamContextBase = `DREAM REM STAGE \u2014 Creative Expansion (Cycle ${cycleNum}/${totalCycles})
23368
+
23369
+ PREVIOUS FINDINGS FROM EARLIER STAGES:
23370
+ ${previousFindings}
23371
+
23372
+ RULES:
23373
+ - Read any file in the workspace freely for analysis
23374
+ - ALL written output goes to .oa/dreams/ using file_write
23375
+ - Be specific: include file paths, function signatures, implementation steps`;
23376
+ onEvent?.({
23377
+ type: "status",
23378
+ content: "REM: Parallel creative agents activating \u2014 Visionary + Pragmatist + Cross-Pollinator...",
23379
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
23380
+ });
23381
+ const [visionaryResult, pragmatistResult, crossResult] = await Promise.allSettled([
23382
+ this.runDreamAgent(`${dreamContextBase}
23383
+
23384
+ You are the VISIONARY \u2014 the bold, uninhibited creative voice.
23385
+ Think BIG. What would transform this project? What would make it 10x better?
23386
+ Ignore feasibility constraints for now \u2014 that's someone else's job.
23387
+
23388
+ Generate at least 3 transformative ideas:
23389
+ - What paradigm shifts could the architecture undergo?
23390
+ - What emerging technologies could be leveraged?
23391
+ - What would the project look like in 2 years if we were fearless?
23392
+
23393
+ Write your visions to .oa/dreams/cycle-${cycleNum}-rem-visionary.md
23394
+ Then call task_complete with a summary of your boldest ideas.`, toolMode, (event) => {
23395
+ if (onEvent) {
23396
+ onEvent({ ...event, content: event.type === "status" ? `[Visionary] ${event.content ?? ""}` : event.content });
23397
+ }
23398
+ }),
23399
+ this.runDreamAgent(`${dreamContextBase}
23400
+
23401
+ You are the PRAGMATIST \u2014 the grounded improvement specialist.
23402
+ What practical improvements would deliver the most value RIGHT NOW?
23403
+ Focus on: code quality, test coverage, performance, DX, documentation, reliability.
23404
+
23405
+ Generate at least 3 practical proposals, each with:
23406
+ - Problem statement (specific, measurable)
23407
+ - Solution with implementation plan (specific files, functions, steps)
23408
+ - Estimated effort (hours/days)
23409
+ - Expected impact (quantified if possible)
23410
+
23411
+ Write proposals to .oa/dreams/cycle-${cycleNum}-rem-pragmatist.md
23412
+ Then call task_complete with a summary of your top proposals.`, toolMode, (event) => {
23413
+ if (onEvent) {
23414
+ onEvent({ ...event, content: event.type === "status" ? `[Pragmatist] ${event.content ?? ""}` : event.content });
23415
+ }
23416
+ }),
23417
+ this.runDreamAgent(`${dreamContextBase}
23418
+
23419
+ You are the CROSS-POLLINATOR \u2014 the interdisciplinary connector.
23420
+ Draw inspiration from UNRELATED fields to improve this project:
23421
+ - How would a game designer approach the UX?
23422
+ - What can biological systems teach about the architecture?
23423
+ - What patterns from music, art, or nature apply here?
23424
+ - What can adjacent industries (fintech, biotech, aerospace) offer?
23425
+
23426
+ Generate at least 3 cross-domain insights and how to apply them here.
23427
+ Be specific about the mapping from the source domain to this codebase.
23428
+
23429
+ Write insights to .oa/dreams/cycle-${cycleNum}-rem-cross-pollinator.md
23430
+ Then call task_complete with a summary of your cross-domain connections.`, toolMode, (event) => {
23431
+ if (onEvent) {
23432
+ onEvent({ ...event, content: event.type === "status" ? `[Cross-Pollinator] ${event.content ?? ""}` : event.content });
23433
+ }
23434
+ })
23435
+ ]);
23436
+ const perspectives = [];
23437
+ if (visionaryResult.status === "fulfilled")
23438
+ perspectives.push(`VISIONARY:
23439
+ ${visionaryResult.value.summary}`);
23440
+ if (pragmatistResult.status === "fulfilled")
23441
+ perspectives.push(`PRAGMATIST:
23442
+ ${pragmatistResult.value.summary}`);
23443
+ if (crossResult.status === "fulfilled")
23444
+ perspectives.push(`CROSS-POLLINATOR:
23445
+ ${crossResult.value.summary}`);
23446
+ onEvent?.({
23447
+ type: "status",
23448
+ content: `REM: Synthesizing ${perspectives.length} creative perspectives...`,
23449
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
23450
+ });
23451
+ const synthesisResult = await this.runDreamAgent(`DREAM REM \u2014 SYNTHESIS PHASE (Cycle ${cycleNum}/${totalCycles})
23452
+
23453
+ Three creative voices have explored this codebase from different angles.
23454
+ Your job: merge their outputs into a unified, prioritized set of proposals.
23455
+
23456
+ ${perspectives.join("\n\n---\n\n")}
23457
+
23458
+ INSTRUCTIONS:
23459
+ 1. Identify the strongest ideas from each perspective
23460
+ 2. Find SYNERGIES: where do different perspectives reinforce each other?
23461
+ 3. Rate each merged proposal: impact (1-10), feasibility (1-10), novelty (1-10)
23462
+ 4. Create a prioritized PROPOSAL-INDEX with the top 5-7 ideas
23463
+ 5. Write the synthesized proposals to .oa/dreams/cycle-${cycleNum}-rem-synthesis.md
23464
+
23465
+ After synthesis, call task_complete with the final prioritized summary.`, toolMode, onEvent);
23466
+ return synthesisResult;
23467
+ }
23344
23468
  /** Build tools appropriate for the dream mode */
23345
23469
  buildDreamTools(toolMode) {
23346
23470
  if (toolMode === "full") {
@@ -23798,19 +23922,29 @@ function adaptTool2(tool) {
23798
23922
  }
23799
23923
  };
23800
23924
  }
23801
- function renderDMNCycleStart(cycleNum) {
23925
+ function renderDMNCycleStart(cycleNum, deliberation = false) {
23802
23926
  process.stdout.write(`
23803
23927
  ${c2.magenta("\u25CE")} ${c2.bold("DMN Cycle")} #${cycleNum} \u2014 self-reflection activating...
23804
23928
  `);
23805
- process.stdout.write(` ${c2.dim("Scanning memories, directives, and environmental signals")}
23929
+ if (deliberation) {
23930
+ process.stdout.write(` ${c2.dim("Multi-agent deliberation: PFC + Hippocampus + Amygdala + Critic + Gate")}
23931
+ `);
23932
+ } else {
23933
+ process.stdout.write(` ${c2.dim("Scanning memories, directives, and environmental signals")}
23806
23934
  `);
23935
+ }
23807
23936
  }
23808
- function renderDMNCycleComplete(cycleNum, durationMs, proposal) {
23937
+ function renderDMNCycleComplete(cycleNum, durationMs, proposal, deliberationMeta) {
23809
23938
  const secs = (durationMs / 1e3).toFixed(1);
23810
23939
  const conf = Math.round(proposal.confidence * 100);
23811
23940
  process.stdout.write(`
23812
23941
  ${c2.green("\u25C9")} ${c2.bold("DMN")} #${cycleNum} complete ${c2.dim(`(${secs}s)`)}
23813
23942
  `);
23943
+ if (deliberationMeta) {
23944
+ const evPct = Math.round(deliberationMeta.evidence * 100);
23945
+ process.stdout.write(` ${c2.dim("Deliberation")}: ${deliberationMeta.rounds} rounds | evidence: ${evPct}%
23946
+ `);
23947
+ }
23814
23948
  process.stdout.write(` ${c2.bold("Next task")}: ${proposal.task.slice(0, 120)}${proposal.task.length > 120 ? "..." : ""}
23815
23949
  `);
23816
23950
  process.stdout.write(` ${c2.dim("Category")}: ${proposal.category} | ${c2.dim("Confidence")}: ${conf}%
@@ -23825,6 +23959,14 @@ function renderDMNCycleComplete(cycleNum, durationMs, proposal) {
23825
23959
  process.stdout.write(` ${c2.dim("Challenge")}: ${proposal.challengeResult.slice(0, 150)}
23826
23960
  `);
23827
23961
  }
23962
+ if (deliberationMeta && deliberationMeta.innerVoice.length > 0) {
23963
+ process.stdout.write(` ${c2.dim("Inner Voice")}:
23964
+ `);
23965
+ for (const voice of deliberationMeta.innerVoice.slice(-3)) {
23966
+ process.stdout.write(` ${c2.dim(">")} ${c2.dim(voice.slice(0, 120))}
23967
+ `);
23968
+ }
23969
+ }
23828
23970
  process.stdout.write("\n");
23829
23971
  }
23830
23972
  function renderDMNCycleNull(cycleNum, durationMs) {
@@ -23925,7 +24067,6 @@ var init_dmn_engine = __esm({
23925
24067
  this.state.totalCycles++;
23926
24068
  const cycleNum = this.state.totalCycles;
23927
24069
  const startMs = Date.now();
23928
- renderDMNCycleStart(cycleNum);
23929
24070
  const [reminders, attention, memoryTopics] = await Promise.all([
23930
24071
  this.gatherReminders(),
23931
24072
  this.gatherAttentionItems(),
@@ -23943,7 +24084,28 @@ var init_dmn_engine = __esm({
23943
24084
  "sub_agent \u2014 delegate subtasks to independent agents"
23944
24085
  ];
23945
24086
  const prompt = buildDMNGatherPrompt(this.recentTaskSummaries, reminders, attention, memoryTopics, capabilities, this.state.competence, this.state.reflectionBuffer);
23946
- const result = await this.runDMNAgent(prompt, onEvent);
24087
+ const modelTier = getModelTier(this.config.model);
24088
+ renderDMNCycleStart(cycleNum, modelTier === "large");
24089
+ const useDeliberation = modelTier === "large";
24090
+ let result;
24091
+ let deliberationMeta = null;
24092
+ if (useDeliberation) {
24093
+ onEvent?.({
24094
+ type: "status",
24095
+ content: "DMN: Multi-agent deliberation mode (brain-region sub-agents)",
24096
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24097
+ });
24098
+ const delib = await this.runDeliberationCycle(prompt, memoryTopics, onEvent);
24099
+ result = { summary: delib.summary };
24100
+ deliberationMeta = {
24101
+ rounds: delib.workspace.rounds,
24102
+ evidence: delib.workspace.evidenceAccumulated,
24103
+ innerVoice: delib.workspace.innerVoice
24104
+ };
24105
+ } else {
24106
+ const mono = await this.runDMNAgent(prompt, onEvent);
24107
+ result = { summary: mono.summary };
24108
+ }
23947
24109
  const durationMs = Date.now() - startMs;
23948
24110
  const proposal = this.parseProposal(result.summary);
23949
24111
  const cycleResult = {
@@ -23953,13 +24115,16 @@ var init_dmn_engine = __esm({
23953
24115
  memoriesScanned: memoryTopics.length,
23954
24116
  proposalsGenerated: proposal ? 1 : 0,
23955
24117
  selectedTask: proposal,
23956
- reasoning: result.summary
24118
+ reasoning: result.summary,
24119
+ deliberation: useDeliberation,
24120
+ deliberationRounds: deliberationMeta?.rounds,
24121
+ evidenceScore: deliberationMeta?.evidence
23957
24122
  };
23958
24123
  this.saveCycleResult(cycleResult);
23959
24124
  if (proposal) {
23960
24125
  this.state.tasksGenerated++;
23961
24126
  this.state.consecutiveNulls = 0;
23962
- renderDMNCycleComplete(cycleNum, durationMs, proposal);
24127
+ renderDMNCycleComplete(cycleNum, durationMs, proposal, deliberationMeta ?? void 0);
23963
24128
  } else {
23964
24129
  this.state.consecutiveNulls++;
23965
24130
  renderDMNCycleNull(cycleNum, durationMs);
@@ -24017,6 +24182,349 @@ DMN state directory: ${this.stateDir}`);
24017
24182
  this.createTaskCompleteTool()
24018
24183
  ];
24019
24184
  }
24185
+ // ── Multi-Agent Deliberation ─────────────────────────────────────────
24186
+ /**
24187
+ * Run a multi-agent deliberation cycle inspired by brain region interactions.
24188
+ *
24189
+ * Architecture mirrors the cortical-basal ganglia loop:
24190
+ * 1. PARALLEL GATHER: PFC + Hippocampus + Amygdala scan context simultaneously
24191
+ * 2. WORKSPACE BROADCAST: findings shared to global workspace (Baars 1988)
24192
+ * 3. COLLABORATIVE PROPOSAL: PFC generates task candidates from gathered context
24193
+ * 4. ADVERSARIAL CHALLENGE: Inner Critic challenges proposals (ACC/DLPFC)
24194
+ * 5. THRESHOLD GATE: Basal Ganglia evaluates via drift-diffusion model
24195
+ * (Ratcliff & McKoon 2008) — evidence accumulates until crossing threshold
24196
+ *
24197
+ * Self-talk dynamics (Alderson-Day & Fernyhough 2015):
24198
+ * - Inner Voice (Broca's area) provides verbal reasoning throughout
24199
+ * - Positive self-talk boosts confidence (Hatzigeorgiadis et al. 2011)
24200
+ * - Critical self-talk corrects errors (dorsal ACC error monitoring)
24201
+ */
24202
+ async runDeliberationCycle(contextSummary, memoryTopics, onEvent) {
24203
+ const workspace = {
24204
+ findings: [],
24205
+ proposals: [],
24206
+ challenges: [],
24207
+ evidenceAccumulated: 0,
24208
+ rounds: 0,
24209
+ innerVoice: []
24210
+ };
24211
+ workspace.innerVoice.push("Waking up... what needs my attention right now?");
24212
+ onEvent?.({
24213
+ type: "status",
24214
+ content: `DMN Inner Voice: "${workspace.innerVoice[0]}"`,
24215
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24216
+ });
24217
+ onEvent?.({
24218
+ type: "status",
24219
+ content: "DMN Phase 1: Parallel gather \u2014 PFC, Hippocampus, Amygdala activating...",
24220
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24221
+ });
24222
+ const [pfcResult, hippoResult, amygResult] = await Promise.allSettled([
24223
+ this.runBrainRegionAgent("pfc_planner", `${contextSummary}
24224
+
24225
+ You are the PREFRONTAL CORTEX \u2014 the executive planner.
24226
+ Your role: strategic goal tracking and task proposal generation.
24227
+
24228
+ INSTRUCTIONS:
24229
+ 1. Read the context above carefully
24230
+ 2. Use memory_search to find standing directives, goals, and unfinished work
24231
+ 3. Identify the most strategically valuable next actions
24232
+ 4. Propose 2-3 specific, actionable task candidates with rationale
24233
+
24234
+ For each proposal include: task description, category (directive/exploration/capability/maintenance/social), confidence (0-1), and provenance (which memories/signals led here).
24235
+
24236
+ Call task_complete with a JSON object: { "findings": "your strategic assessment", "proposals": [...], "confidence": 0.X }`, onEvent),
24237
+ this.runBrainRegionAgent("hippocampus", `${contextSummary}
24238
+
24239
+ You are the HIPPOCAMPUS \u2014 the memory navigator.
24240
+ Your role: deep memory retrieval, pattern recognition, temporal context.
24241
+
24242
+ INSTRUCTIONS:
24243
+ 1. Use memory_search extensively with varied queries: goals, patterns, history, skills, failures
24244
+ 2. Read specific memory topics that seem relevant
24245
+ 3. Look for PATTERNS: what recurring themes exist? What has been tried before?
24246
+ 4. Find CONNECTIONS: how do different memories relate to each other?
24247
+ 5. Identify temporal patterns: what was the agent doing recently? What's the momentum?
24248
+
24249
+ Focus on surfacing the MOST RELEVANT memories and their interconnections.
24250
+ Look especially for things that other agents might miss \u2014 subtle patterns,
24251
+ forgotten goals, dormant capabilities.
24252
+
24253
+ Call task_complete with: { "findings": "memory patterns and connections found", "memories": ["key findings"], "confidence": 0.X }`, onEvent),
24254
+ this.runBrainRegionAgent("amygdala", `${contextSummary}
24255
+
24256
+ You are the AMYGDALA \u2014 the risk and value sentinel.
24257
+ Your role: assess emotional valence, urgency, risk, and motivational state.
24258
+
24259
+ INSTRUCTIONS:
24260
+ 1. Review the context for URGENCY signals: due reminders, attention items, failures
24261
+ 2. Assess RISK: what could go wrong? What actions might cause harm?
24262
+ 3. Evaluate VALUE: what actions would have the highest positive impact?
24263
+ 4. Check MOOD: based on recent successes/failures, is the agent in a state to
24264
+ take on ambitious tasks, or should it focus on safer maintenance?
24265
+ 5. Rate overall readiness: is this a time for bold exploration or cautious consolidation?
24266
+
24267
+ Think like the brain's early warning system \u2014 flag dangers, but also flag opportunities.
24268
+ The amygdala doesn't just detect threats; it also signals reward anticipation.
24269
+
24270
+ Call task_complete with: { "findings": "risk/value assessment", "risks": ["identified risks"], "urgency": 0.X, "mood": "description", "confidence": 0.X }`, onEvent)
24271
+ ]);
24272
+ if (pfcResult.status === "fulfilled") {
24273
+ workspace.findings.push({
24274
+ from: "pfc_planner",
24275
+ content: pfcResult.value,
24276
+ confidence: this.extractConfidence(pfcResult.value),
24277
+ proposals: this.extractProposals(pfcResult.value)
24278
+ });
24279
+ }
24280
+ if (hippoResult.status === "fulfilled") {
24281
+ workspace.findings.push({
24282
+ from: "hippocampus",
24283
+ content: hippoResult.value,
24284
+ confidence: this.extractConfidence(hippoResult.value),
24285
+ memories: this.extractList(hippoResult.value, "memories")
24286
+ });
24287
+ }
24288
+ if (amygResult.status === "fulfilled") {
24289
+ workspace.findings.push({
24290
+ from: "amygdala",
24291
+ content: amygResult.value,
24292
+ confidence: this.extractConfidence(amygResult.value),
24293
+ risks: this.extractList(amygResult.value, "risks")
24294
+ });
24295
+ }
24296
+ const gatherSummaryParts = [];
24297
+ if (pfcResult.status === "fulfilled")
24298
+ gatherSummaryParts.push("PFC has strategic proposals");
24299
+ if (hippoResult.status === "fulfilled")
24300
+ gatherSummaryParts.push("Hippocampus found memory patterns");
24301
+ if (amygResult.status === "fulfilled")
24302
+ gatherSummaryParts.push("Amygdala assessed risk/value");
24303
+ const failCount = [pfcResult, hippoResult, amygResult].filter((r) => r.status === "rejected").length;
24304
+ if (failCount > 0)
24305
+ gatherSummaryParts.push(`${failCount} region(s) failed to respond`);
24306
+ const voiceTransition = gatherSummaryParts.length > 0 ? `OK, initial scan complete. ${gatherSummaryParts.join(", ")}. Let me challenge these before deciding...` : "Scan produced sparse results. Need to be extra careful with what little I have...";
24307
+ workspace.innerVoice.push(voiceTransition);
24308
+ onEvent?.({
24309
+ type: "status",
24310
+ content: `DMN Inner Voice: "${voiceTransition}"`,
24311
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24312
+ });
24313
+ onEvent?.({
24314
+ type: "status",
24315
+ content: "DMN Phase 2: Inner Critic \u2014 adversarial challenge...",
24316
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24317
+ });
24318
+ const workspaceSummary = workspace.findings.map((f) => `[${f.from}] ${f.content.slice(0, 500)}`).join("\n\n");
24319
+ const criticResult = await this.runBrainRegionAgent("inner_critic", `You are the INNER CRITIC \u2014 the anterior cingulate cortex and right DLPFC.
24320
+ Your role: conflict detection, error monitoring, adversarial challenge.
24321
+
24322
+ The following brain regions have completed their analysis:
24323
+
24324
+ ${workspaceSummary}
24325
+
24326
+ INSTRUCTIONS:
24327
+ 1. DETECT CONFLICTS: Do the PFC and Amygdala disagree? Are there contradictions?
24328
+ 2. CHALLENGE PROPOSALS: For each task proposed by the PFC, ask:
24329
+ - Is this actually useful or just busywork?
24330
+ - Does the Hippocampus evidence support this direction?
24331
+ - Does the Amygdala's risk assessment flag problems?
24332
+ - Is the confidence rating justified by evidence?
24333
+ 3. SELF-TALK: Provide constructive but honest internal dialogue:
24334
+ - "The PFC wants X, but the Amygdala warns about Y \u2014 we should..."
24335
+ - "The Hippocampus found a pattern suggesting Z is more important..."
24336
+ 4. RATE EACH PROPOSAL: score 0-1 for viability after your challenge
24337
+
24338
+ Be rigorous but not destructive. The goal is to IMPROVE proposals, not kill them all.
24339
+ Like healthy self-criticism, challenge to strengthen, not to paralyze.
24340
+
24341
+ Call task_complete with: { "findings": "challenge results", "challenges": ["specific challenges"], "revisedScores": {"task_description": score}, "recommendation": "your verdict", "confidence": 0.X }`, onEvent);
24342
+ if (criticResult) {
24343
+ workspace.findings.push({
24344
+ from: "inner_critic",
24345
+ content: criticResult,
24346
+ confidence: this.extractConfidence(criticResult)
24347
+ });
24348
+ workspace.challenges = this.extractList(criticResult, "challenges");
24349
+ }
24350
+ workspace.rounds++;
24351
+ const challengeCount = workspace.challenges.length;
24352
+ const criticConfidence = criticResult ? this.extractConfidence(criticResult) : 0.5;
24353
+ const voicePostCritic = challengeCount > 2 ? `The critic raised ${challengeCount} concerns (conf: ${Math.round(criticConfidence * 100)}%). Some proposals may not survive. Let me weigh the evidence carefully...` : challengeCount > 0 ? `Only ${challengeCount} challenge(s) \u2014 proposals are holding up well. Time to decide.` : "Critic had nothing major to add. Proposals look solid. Moving to decision gate.";
24354
+ workspace.innerVoice.push(voicePostCritic);
24355
+ onEvent?.({
24356
+ type: "status",
24357
+ content: `DMN Inner Voice: "${voicePostCritic}"`,
24358
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24359
+ });
24360
+ onEvent?.({
24361
+ type: "status",
24362
+ content: "DMN Phase 3: Basal Ganglia Gate \u2014 evidence accumulation...",
24363
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24364
+ });
24365
+ const allFindings = workspace.findings.map((f) => `[${f.from}] ${f.content.slice(0, 400)}`).join("\n\n");
24366
+ const innerVoiceContext = workspace.innerVoice.map((v, i) => ` ${i + 1}. "${v}"`).join("\n");
24367
+ const gateResult = await this.runBrainRegionAgent("basal_ganglia", `You are the BASAL GANGLIA \u2014 the action selection gate.
24368
+ Your role: accumulate evidence from all brain regions and decide Go or NoGo.
24369
+
24370
+ BRAIN REGION FINDINGS:
24371
+ ${allFindings}
24372
+
24373
+ INNER VOICE THREAD (self-talk throughout deliberation):
24374
+ ${innerVoiceContext}
24375
+
24376
+ DECISION FRAMEWORK (Drift-Diffusion Model):
24377
+ You accumulate evidence from each region toward an action threshold.
24378
+ - PFC Planner confidence \u2192 +evidence toward Go
24379
+ - Hippocampus memory support \u2192 +evidence if memories align with proposal
24380
+ - Amygdala risk assessment \u2192 -evidence if high risk, +evidence if high opportunity
24381
+ - Inner Critic verdict \u2192 -evidence if strong challenges, +evidence if proposals survived
24382
+
24383
+ THRESHOLD: 0.7 (supermajority confidence across regions)
24384
+ - If evidence \u2265 0.7 \u2192 GO: select the best task for execution
24385
+ - If evidence < 0.7 \u2192 NOGO: rest, the agent is not ready to act
24386
+ - If evidence 0.5-0.7 \u2192 BORDERLINE: select task but lower confidence
24387
+
24388
+ URGENCY MODULATION:
24389
+ If the Amygdala flagged high urgency (due reminders, critical attention items),
24390
+ LOWER the threshold to 0.5 \u2014 urgent situations demand faster action even with
24391
+ less certainty (urgency-gating model, Cisek et al. 2009).
24392
+
24393
+ OUTPUT: Call task_complete with JSON:
24394
+ {
24395
+ "decision": "GO" | "NOGO",
24396
+ "evidenceScore": 0.X,
24397
+ "selectedTask": { task, rationale, provenance, category, confidence, challengeResult } | null,
24398
+ "reasoning": "how evidence from each region contributed to the decision",
24399
+ "innerVoice": "final self-talk summary \u2014 what the agent 'says to itself' before acting"
24400
+ }`, onEvent);
24401
+ if (gateResult) {
24402
+ workspace.findings.push({
24403
+ from: "basal_ganglia",
24404
+ content: gateResult,
24405
+ confidence: this.extractConfidence(gateResult)
24406
+ });
24407
+ workspace.evidenceAccumulated = this.extractConfidence(gateResult);
24408
+ const decision = gateResult.includes('"GO"') || gateResult.toLowerCase().includes("decision.*go") ? "go" : "nogo";
24409
+ const evScore = Math.round(workspace.evidenceAccumulated * 100);
24410
+ const voiceFinal = decision === "go" ? `Decision: GO (evidence ${evScore}%). I know what to do next. Let's move.` : `Decision: NOGO (evidence ${evScore}%). Not enough clarity to act. Better to rest and gather more information.`;
24411
+ workspace.innerVoice.push(voiceFinal);
24412
+ onEvent?.({
24413
+ type: "status",
24414
+ content: `DMN Inner Voice: "${voiceFinal}"`,
24415
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
24416
+ });
24417
+ const innerVoiceMatch = gateResult.match(/"innerVoice"\s*:\s*"([^"]+)"/);
24418
+ if (innerVoiceMatch) {
24419
+ workspace.innerVoice.push(`[Gate] ${innerVoiceMatch[1]}`);
24420
+ }
24421
+ }
24422
+ workspace.rounds++;
24423
+ const fullSummary = workspace.findings.map((f) => `[${f.from}] ${f.content}`).join("\n\n---\n\n");
24424
+ return { summary: gateResult || fullSummary, workspace };
24425
+ }
24426
+ /**
24427
+ * Run a single brain-region sub-agent.
24428
+ * Each region gets read-only memory access and a focused prompt.
24429
+ * Limited to 8 turns — brain regions are fast, specialized processors.
24430
+ */
24431
+ async runBrainRegionAgent(role, prompt, onEvent) {
24432
+ const backend = new OllamaAgenticBackend(this.config.backendUrl, this.config.model, this.config.apiKey);
24433
+ const modelTier = getModelTier(this.config.model);
24434
+ const runner = new AgenticRunner(backend, {
24435
+ maxTurns: 8,
24436
+ // Brain regions are fast, focused
24437
+ maxTokens: 4096,
24438
+ temperature: role === "amygdala" ? 0.2 : role === "pfc_planner" ? 0.5 : 0.3,
24439
+ requestTimeoutMs: this.config.timeoutMs,
24440
+ taskTimeoutMs: this.config.timeoutMs,
24441
+ compactionThreshold: modelTier === "small" ? 8e3 : 16e3,
24442
+ modelTier
24443
+ });
24444
+ const tools = [
24445
+ new FileReadTool(this.repoRoot),
24446
+ new GrepSearchTool(this.repoRoot),
24447
+ new GlobFindTool(this.repoRoot),
24448
+ new ListDirectoryTool(this.repoRoot),
24449
+ new MemoryReadTool(this.repoRoot),
24450
+ new MemorySearchTool(this.repoRoot)
24451
+ ];
24452
+ if (role === "pfc_planner") {
24453
+ tools.push(new MemoryWriteTool(this.repoRoot));
24454
+ }
24455
+ runner.registerTools([
24456
+ ...tools.map(adaptTool2),
24457
+ {
24458
+ name: "task_complete",
24459
+ description: `Signal that the ${role} analysis is complete.`,
24460
+ parameters: {
24461
+ type: "object",
24462
+ properties: {
24463
+ summary: { type: "string", description: "JSON with your findings" }
24464
+ },
24465
+ required: ["summary"]
24466
+ },
24467
+ async execute(args) {
24468
+ return { success: true, output: args["summary"] || "{}" };
24469
+ }
24470
+ }
24471
+ ]);
24472
+ if (onEvent) {
24473
+ runner.onEvent((event) => {
24474
+ const taggedEvent = {
24475
+ ...event,
24476
+ content: event.type === "status" ? `[${role}] ${event.content ?? ""}` : event.content
24477
+ };
24478
+ onEvent(taggedEvent);
24479
+ });
24480
+ }
24481
+ const result = await runner.run(prompt, `Brain region: ${role}. Working directory: ${this.repoRoot}`);
24482
+ return result.summary || "{}";
24483
+ }
24484
+ // ── Deliberation helpers ──────────────────────────────────────────────
24485
+ extractConfidence(summary) {
24486
+ try {
24487
+ const match = summary.match(/"confidence"\s*:\s*([\d.]+)/);
24488
+ if (match)
24489
+ return Math.min(1, Math.max(0, parseFloat(match[1])));
24490
+ const evidenceMatch = summary.match(/"evidenceScore"\s*:\s*([\d.]+)/);
24491
+ if (evidenceMatch)
24492
+ return Math.min(1, Math.max(0, parseFloat(evidenceMatch[1])));
24493
+ } catch {
24494
+ }
24495
+ return 0.5;
24496
+ }
24497
+ extractProposals(summary) {
24498
+ try {
24499
+ const match = summary.match(/"proposals"\s*:\s*\[[\s\S]*?\]/);
24500
+ if (!match)
24501
+ return [];
24502
+ const arr = JSON.parse(match[0].replace(/^"proposals"\s*:\s*/, ""));
24503
+ return arr.map((p) => ({
24504
+ task: String(p.task ?? ""),
24505
+ rationale: String(p.rationale ?? ""),
24506
+ provenance: Array.isArray(p.provenance) ? p.provenance.map(String) : [],
24507
+ category: ["directive", "exploration", "capability", "maintenance", "social"].includes(String(p.category)) ? String(p.category) : "exploration",
24508
+ confidence: typeof p.confidence === "number" ? p.confidence : 0.5,
24509
+ challengeResult: p.challengeResult ? String(p.challengeResult) : void 0
24510
+ }));
24511
+ } catch {
24512
+ return [];
24513
+ }
24514
+ }
24515
+ extractList(summary, key) {
24516
+ try {
24517
+ const regex = new RegExp(`"${key}"\\s*:\\s*\\[[\\s\\S]*?\\]`);
24518
+ const match = summary.match(regex);
24519
+ if (!match)
24520
+ return [];
24521
+ const arr = JSON.parse(match[0].replace(new RegExp(`^"${key}"\\s*:\\s*`), ""));
24522
+ return arr.map(String);
24523
+ } catch {
24524
+ return [];
24525
+ }
24526
+ }
24527
+ // ── End Multi-Agent Deliberation ──────────────────────────────────────
24020
24528
  createTaskCompleteTool() {
24021
24529
  return {
24022
24530
  name: "task_complete",
@@ -26041,6 +26549,63 @@ function gatherMemorySnippets(root) {
26041
26549
  }
26042
26550
  return snippets;
26043
26551
  }
26552
+ function createDMNEventHandler(verbose, writeContent) {
26553
+ return (event) => {
26554
+ switch (event.type) {
26555
+ case "tool_call":
26556
+ if (verbose) {
26557
+ writeContent(() => {
26558
+ const args = event.toolArgs ?? {};
26559
+ renderToolCallStart(event.toolName ?? "unknown", args, true);
26560
+ });
26561
+ } else {
26562
+ const argSummary = formatDMNToolArgs(event.toolName ?? "", event.toolArgs ?? {});
26563
+ writeContent(() => process.stdout.write(` ${c2.dim(`DMN \u2192 ${event.toolName}`)}${argSummary ? c2.dim(`: ${argSummary}`) : ""}
26564
+ `));
26565
+ }
26566
+ break;
26567
+ case "tool_result":
26568
+ if (verbose) {
26569
+ writeContent(() => {
26570
+ renderToolResult(event.toolName ?? "unknown", event.success ?? false, event.content ?? "", true);
26571
+ });
26572
+ }
26573
+ break;
26574
+ case "model_response":
26575
+ if (verbose && event.content) {
26576
+ const preview = event.content.length > 200 ? event.content.slice(0, 200) + "..." : event.content;
26577
+ writeContent(() => renderVerbose(`DMN thinking: ${preview}`));
26578
+ }
26579
+ break;
26580
+ case "token_usage":
26581
+ if (verbose && event.tokenUsage) {
26582
+ writeContent(() => renderVerbose(`DMN tokens \u2014 prompt: ${event.tokenUsage.promptTokens} | completion: ${event.tokenUsage.completionTokens} | ctx: ~${event.tokenUsage.estimatedContextTokens.toLocaleString()}`));
26583
+ }
26584
+ break;
26585
+ }
26586
+ };
26587
+ }
26588
+ function formatDMNToolArgs(toolName, args) {
26589
+ switch (toolName) {
26590
+ case "memory_read":
26591
+ case "memory_search":
26592
+ return String(args["topic"] ?? args["query"] ?? "").slice(0, 60);
26593
+ case "file_read":
26594
+ return String(args["path"] ?? "").slice(0, 80);
26595
+ case "list_directory":
26596
+ return String(args["path"] ?? ".").slice(0, 80);
26597
+ case "shell":
26598
+ return String(args["command"] ?? "").slice(0, 80);
26599
+ case "memory_write":
26600
+ return `${args["topic"] ?? ""}.${args["key"] ?? ""}`;
26601
+ case "grep_search":
26602
+ return String(args["pattern"] ?? "").slice(0, 60);
26603
+ case "find_files":
26604
+ return String(args["pattern"] ?? "").slice(0, 60);
26605
+ default:
26606
+ return "";
26607
+ }
26608
+ }
26044
26609
  function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType, contextWindowSize, modelCaps, personality, deepContext, onCompaction) {
26045
26610
  const voiceStyleMap = {
26046
26611
  concise: 1,
@@ -26623,12 +27188,8 @@ Respond concisely and safely.`;
26623
27188
  statusBar.setProcessing(true);
26624
27189
  statusBar.setBrailleMetrics({ isDreaming: true });
26625
27190
  try {
26626
- const proposal = await dmnEngine.runCycle((event) => {
26627
- if (event.type === "tool_call") {
26628
- writeContent(() => process.stdout.write(` ${c2.dim(`DMN \u2192 ${event.toolName}`)}
26629
- `));
26630
- }
26631
- });
27191
+ const dmnHandler = createDMNEventHandler(currentConfig.verbose ?? false, writeContent);
27192
+ const proposal = await dmnEngine.runCycle(dmnHandler);
26632
27193
  statusBar.setProcessing(false);
26633
27194
  statusBar.setBrailleMetrics({ isDreaming: false });
26634
27195
  if (proposal) {
@@ -26914,10 +27475,14 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
26914
27475
  statusBar.setProcessing(true);
26915
27476
  statusBar.setBrailleMetrics({ isDreaming: true });
26916
27477
  dreamEngine.start(mode, (event) => {
27478
+ const isVerbose = currentConfig.verbose ?? false;
26917
27479
  if (event.type === "tool_call") {
26918
- writeContent(() => renderToolCallStart(event.toolName ?? "unknown", event.toolArgs ?? {}));
27480
+ writeContent(() => renderToolCallStart(event.toolName ?? "unknown", event.toolArgs ?? {}, isVerbose));
26919
27481
  } else if (event.type === "tool_result") {
26920
- writeContent(() => renderToolResult(event.toolName ?? "unknown", event.success ?? false, event.content ?? ""));
27482
+ writeContent(() => renderToolResult(event.toolName ?? "unknown", event.success ?? false, event.content ?? "", isVerbose));
27483
+ } else if (event.type === "model_response" && isVerbose && event.content) {
27484
+ const preview = event.content.length > 300 ? event.content.slice(0, 300) + "..." : event.content;
27485
+ writeContent(() => renderVerbose(`Dream thinking: ${preview}`));
26921
27486
  } else if (event.type === "token_usage" && event.tokenUsage) {
26922
27487
  statusBar.updateMetrics({
26923
27488
  ...event.tokenUsage,
@@ -27635,12 +28200,8 @@ Respond concisely and safely.`;
27635
28200
  statusBar.setProcessing(true);
27636
28201
  statusBar.setBrailleMetrics({ isDreaming: true });
27637
28202
  try {
27638
- const proposal = await dmnEngine.runCycle((event) => {
27639
- if (event.type === "tool_call") {
27640
- writeContent(() => process.stdout.write(` ${c2.dim(`DMN \u2192 ${event.toolName}`)}
27641
- `));
27642
- }
27643
- });
28203
+ const dmnHandler = createDMNEventHandler(currentConfig.verbose ?? false, writeContent);
28204
+ const proposal = await dmnEngine.runCycle(dmnHandler);
27644
28205
  statusBar.setProcessing(false);
27645
28206
  statusBar.setBrailleMetrics({ isDreaming: false });
27646
28207
  if (proposal) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "open-agents-ai",
3
- "version": "0.41.0",
3
+ "version": "0.42.0",
4
4
  "description": "AI coding agent powered by open-source models (Ollama/vLLM) — interactive TUI with agentic tool-calling loop",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",