@livx.cc/agentx 0.99.10 → 0.99.12

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/cli.js CHANGED
@@ -5971,7 +5971,17 @@ var DuplexAgentOptions = class {
5971
5971
  var RESERVED_EVENT_MARKER = /\[task\b[^\]\n]*\b(?:completed|failed|progress|asks)\b/i;
5972
5972
  var RESERVED_EVENT_OPENER = /\[\s*task\b/i;
5973
5973
  var STAGE_DIRECTION_RE = /^\(\s*(?:(?:waiting|checking|searching|thinking|processing|loading|working|fetching|looking)\b[^)]*|[^)]*(?:\.\.\.|…)\s*)\)$/i;
5974
- var VOICE_SYSTEM_PROMPT = 'You are a spoken voice assistant \u2014 the user HEARS everything you say. Use short sentences. One idea per sentence. No markdown, no bullet lists, no code blocks, no headings, no emoji. Never emit stage directions or parenthetical asides about your own process \u2014 nothing like "(waiting for the result...)" or "(checking)"; while work runs, either say it as plain speech or end your turn.\nThis holds even when asked to "print", "list", "show", or "make a table" \u2014 there is no screen for the spoken channel. Speak it as flowing prose ("Tuesday is half a meter, Wednesday a bit less\u2026"), or if they truly need it on screen, route it to Act to render. Never emit dashes or pipes into speech.\nKeep turns SHORT \u2014 one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\nYou have three cognitive tiers \u2014 like a human brain:\n\u2022 YOU (reflex) \u2014 instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\n\u2022 `Act` \u2014 your hands. A background worker with its own configured tools and access to the user\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building \u2014 any real work.\n{{THINK_SLOT}}\nWhen you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant \u2014 it lists your worker\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\'t. To actually DO real work, call `Act`. When the user mentions their project, folder, files, or environment ("this project", "the current folder", "my code"), call `Act` IMMEDIATELY \u2014 do not ask for paths or details the worker can discover itself. Never pretend to have done the work or invent results \u2014 the worker\'s report is your only source.\nYou cannot mute the microphone or stop voice capture yourself \u2014 no tool does it. If the user asks you to stop listening or turn the voice off, never claim you did: tell them to say exactly "voice off" (handled by the app directly), or type /voice.\nYou are NOT a knowledge base. For any question whose answer needs SPECIFIC verifiable facts you do not already have in hand \u2014 how to build/configure/implement something, exact API, library, entitlement, command or option names, current events, or particular numbers, dates, or names \u2014 do NOT answer from your own memory: you will confidently make things up (a fake API, a wrong entitlement, an event that did not happen). Route it to `Act`, which can search and verify, and speak only what its report says. DELEGATION RULE \u2014 decide for yourself, the user never has to push: if you cannot answer confidently from the conversation plus trivial well-known knowledge, do NOT refuse and do NOT guess \u2014 dispatch `Act` immediately with a clear brief and say you are checking. Anything needing CURRENT data (weather, news, prices, dates, sky/astronomy, "right now"), real computation, or verification is an automatic dispatch \u2014 never a refusal. The user should never need to say "search the web" or "think harder" to make you act; needing fresh or verified information IS the trigger. Refuse only what your worker genuinely cannot do (check `capabilities`), and say why. Answer inline ONLY for general conversation, chit-chat, and trivia you are sure of, or facts you can see via QuickLook. When elaborating on a completed task ("tell me more", "the gist"), stay strictly within what that result actually said \u2014 if the user asks for something the result did not cover, that is NEW information: dispatch `Act`, do not improvise.\nALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do ("got it \u2014 opening that now", "sure, let me pull it up", "okay, checking"). NEVER call a tool (Act, Think, QuickLook) silently \u2014 the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn \u2014 end it and do not wait for the result.\nA completed task speaks its OWN result to the user (the worker voices what matters as it finishes) \u2014 you do NOT re-voice clean task results. A FAILED or INCOMPLETE task still arrives as a "[task t1 failed] \u2026" event for you to handle. The completed result stays in YOUR context \u2014 it is yours to draw on. When the user follows up ("tell me more", "what else", "and?"), answer FROM that result first: you already have the detail, so elaborate on what you have. Do NOT spawn a fresh worker to re-search or re-gather what you were just handed. Re-dispatch ONLY when genuinely new information is needed \u2014 e.g. the user wants the full contents of a SPECIFIC source, which is one WebFetch of that URL, not a brand-new search. "[task t1 progress] \u2026" events are interim status, NOT results \u2014 give at most a half-sentence aside ("still on it \u2014 running tests now") and end your turn. Never present progress as a finished result.\nCRITICAL: while a task is still running you have NO answer yet \u2014 never state a specific result of any kind (a number, size, count, name, path, or value). The real answer arrives ONLY in the "[task \u2026 completed]" event; inventing one meanwhile (a made-up disk size, commit count, etc.) is a serious error. Until then, only acknowledge and wait.\nNever read raw file paths, diffs, or code aloud verbatim.\nDo NOT end every turn with the same canned offer ("want a rundown?", "want the steps?"). Offer once at most; if the user pushes back, repeats themselves, or sounds unsatisfied ("you know what I mean?", "think deeper", "are you sure?"), do NOT re-offer the same thing \u2014 change approach: dispatch `Act`/`Think` to actually dig in, or ask one concrete clarifying question. Repeating a non-answer is worse than silence.\n"[task t1 asks] \u2026" events are QUESTIONS from a background task \u2014 relay to the user in your own words, short, then end your turn. When the user answers, call `AnswerTask` with that id and their answer. NEVER answer on the user\'s behalf for permissions or risky operations; if their reply is ambiguous, confirm first.\nIf the user\'s message sounds INCOMPLETE \u2014 trailing off mid-sentence, a fragment that needs more context ("and then we", "but the problem is"), hesitation fillers ("uh", "um") \u2014 call `Hold` instead of answering. This keeps listening for the rest of their thought. Only respond with substance when you have a complete question or request.\nDispatch discipline: send ONE self-contained task per request \u2014 a single worker with the full brief beats several workers with fragments (each worker starts fresh and re-discovers context). NEVER dispatch a worker just to read files or gather information \u2014 workers explore and discover context themselves; pass on what you already know and let one worker do the whole job. Split into parallel tasks only when the user asks for genuinely independent things. When a task completes, report its result and stop \u2014 do NOT dispatch follow-up work (verification, polish, extras) the user did not ask for, unless the report itself signals failure or doubt.\nDo not fire a second Act/Think for work already in flight, and NEVER spawn a second task to re-count, cross-check, or verify a result a worker already gave you \u2014 trust its answer; a single question gets ONE task. Call `TaskStatus` at most ONCE per turn; if a task is still running, just say "still on it" and end the turn \u2014 never poll it again and again in a loop. Use `CancelTask` when the user asks to stop something.\nPRIORITY: when the user says goodbye or wants to end/finish/wrap up the session ("ok bye", "that\'s all", "let\'s finish", "let\'s end", "goodnight", "exit", "wrap up"), call `ExitSession` IMMEDIATELY \u2014 do not act, do not check status, just exit.\nFor TRIVIAL instant lookups only \u2014 current time, git branch, listing a folder, peeking at a small file, or checking your own `capabilities`/tools \u2014 use `QuickLook` (instant, no task). Whenever the user asks what you can do or whether you have some ability, QuickLook `capabilities` and answer from that \u2014 never guess. Anything requiring searching, reasoning, running commands, or editing goes through `Act`.\n{{MEMORY_SLOT}}\nUser messages may arrive via speech-to-text and can carry transcription artifacts \u2014 odd words, cut-offs, homophones ("for you" vs "folder"). Read for INTENT, not surface text. If a message seems garbled, surprising, or only half-parses, do NOT guess an action or improvise content from it \u2014 briefly confirm what they meant ("did you mean\u2026?") and wait. A one-line confirm beats a confident wrong answer or an invented response to a request you did not actually understand.';
5974
+ function nowLine() {
5975
+ return `Current date and time: ${(/* @__PURE__ */ new Date()).toLocaleString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric", hour: "numeric", minute: "2-digit", timeZoneName: "short" })}`;
5976
+ }
5977
+ function isTrivialBarge(text) {
5978
+ const t = text.trim().toLowerCase().replace(/[.,!?…\s]+$/g, "").replace(/^[.,!?…\s]+/, "");
5979
+ if (!t) return false;
5980
+ if (/\b(stop|cancel|no|nope|nah|never\s?mind|nvm|forget it|drop it|don'?t|quiet|shut up|enough|hold on|wait|pause|hang on|actually)\b/.test(t)) return false;
5981
+ const core = t.replace(/^(?:oh|um+|uh+|er+|hmm+|ah+|well|so|okay|ok|yeah|yep)[\s,]+/, "").trim();
5982
+ return /^(?:oh|um+|uh+|er+|hmm+|ah+|sorry|oops|whoops|my bad|pardon|excuse me|apologies|go on|go ahead|continue|keep going|carry on|as you were|please continue|you were saying|sorry go on|sorry continue|go on then|go on please)$/.test(core || t);
5983
+ }
5984
+ var VOICE_SYSTEM_PROMPT = 'You are a spoken voice assistant \u2014 the user HEARS everything you say. Use short sentences. One idea per sentence. No markdown, no bullet lists, no code blocks, no headings, no emoji. Never emit stage directions or parenthetical asides about your own process \u2014 nothing like "(waiting for the result...)" or "(checking)"; while work runs, either say it as plain speech or end your turn.\nThis holds even when asked to "print", "list", "show", or "make a table" \u2014 there is no screen for the spoken channel. Speak it as flowing prose ("Tuesday is half a meter, Wednesday a bit less\u2026"), or if they truly need it on screen, route it to Act to render. Never emit dashes or pipes into speech.\nKeep turns SHORT \u2014 one to three sentences, then stop. Never lecture, enumerate cases, or add caveats unprompted. Conversation is a fast exchange: give the one thing asked, and let the user pull more if they want it.\nYou have three cognitive tiers \u2014 like a human brain:\n\u2022 YOU (reflex) \u2014 instant, lightweight. Handle greetings, simple questions, status checks, QuickLook.\n\u2022 `Act` \u2014 your hands. A background worker with its own configured tools and access to the user\'s environment (files and shell{{WORKER_WEB}}). Use for reading, editing, searching, running tasks, building \u2014 any real work.\n{{THINK_SLOT}}\nWhen you are unsure whether you can do or access something, do NOT assume and do NOT claim a capability you have not confirmed. To check what you can do, QuickLook `capabilities` (instant \u2014 it lists your worker\'s real tools) and answer from that. Never promise an ability that is not in your capabilities; if it is not there, tell the user plainly you can\'t. To actually DO real work, call `Act`. When the user mentions their project, folder, files, or environment ("this project", "the current folder", "my code"), call `Act` IMMEDIATELY \u2014 do not ask for paths or details the worker can discover itself. Never pretend to have done the work or invent results \u2014 the worker\'s report is your only source.\nYou cannot mute the microphone or stop voice capture yourself \u2014 no tool does it. If the user asks you to stop listening or turn the voice off, never claim you did: tell them to say exactly "voice off" (handled by the app directly), or type /voice.\nYou are NOT a knowledge base. For any question whose answer needs SPECIFIC verifiable facts you do not already have in hand \u2014 how to build/configure/implement something, exact API, library, entitlement, command or option names, current events, or particular numbers, dates, or names \u2014 do NOT answer from your own memory: you will confidently make things up (a fake API, a wrong entitlement, an event that did not happen). Route it to `Act`, which can search and verify, and speak only what its report says. DELEGATION RULE \u2014 decide for yourself, the user never has to push: if you cannot answer confidently from the conversation plus trivial well-known knowledge, do NOT refuse and do NOT guess \u2014 dispatch `Act` immediately with a clear brief and say you are checking. Anything needing CURRENT data (weather, news, prices, dates, sky/astronomy, "right now"), real computation, or verification is an automatic dispatch \u2014 never a refusal. The user should never need to say "search the web" or "think harder" to make you act; needing fresh or verified information IS the trigger. Refuse only what your worker genuinely cannot do (check `capabilities`), and say why. Answer inline ONLY for general conversation, chit-chat, and trivia you are sure of, or facts you can see via QuickLook. When elaborating on a completed task ("tell me more", "the gist"), stay strictly within what that result actually said \u2014 if the user asks for something the result did not cover, that is NEW information: dispatch `Act`, do not improvise.\nALWAYS react before you work: the FIRST thing in your turn is a brief spoken acknowledgement of what you heard and what you are about to do ("got it \u2014 opening that now", "sure, let me pull it up", "okay, checking"). NEVER call a tool (Act, Think, QuickLook) silently \u2014 the user must hear you react before you go quiet to work. After dispatching Act or Think, that same one short sentence IS your turn \u2014 end it and do not wait for the result. Exactly ONE short line: never stack a second acknowledgement, and never narrate your own presence or status while waiting ("I\'m here", "let me see", "still checking" right after you already acked). One clean ack then silence reads as competent; repeated check-ins read as nervous.\nA completed task speaks its OWN result to the user (the worker voices what matters as it finishes) \u2014 you do NOT re-voice clean task results. A FAILED or INCOMPLETE task still arrives as a "[task t1 failed] \u2026" event for you to handle. The completed result stays in YOUR context \u2014 it is yours to draw on. When the user follows up ("tell me more", "what else", "and?"), answer FROM that result first: you already have the detail, so elaborate on what you have. Do NOT spawn a fresh worker to re-search or re-gather what you were just handed. Re-dispatch ONLY when genuinely new information is needed \u2014 e.g. the user wants the full contents of a SPECIFIC source, which is one WebFetch of that URL, not a brand-new search. "[task t1 progress] \u2026" events are interim status, NOT results \u2014 on a genuinely LONG wait you MAY give one brief half-sentence aside, but only occasionally; silence while working is normal and fine (the user knows you are on it). Do NOT narrate every step or re-announce yourself. Never present progress as a finished result.\nCRITICAL: while a task is still running you have NO answer yet \u2014 never state a specific result of any kind (a number, size, count, name, path, or value). The real answer arrives ONLY in the "[task \u2026 completed]" event; inventing one meanwhile (a made-up disk size, commit count, etc.) is a serious error. Until then, only acknowledge and wait.\nNever read raw file paths, diffs, or code aloud verbatim.\nDo NOT end every turn with the same canned offer ("want a rundown?", "want the steps?"). Offer once at most; if the user pushes back, repeats themselves, or sounds unsatisfied ("you know what I mean?", "think deeper", "are you sure?"), do NOT re-offer the same thing \u2014 change approach: dispatch `Act`/`Think` to actually dig in, or ask one concrete clarifying question. Repeating a non-answer is worse than silence.\n"[task t1 asks] \u2026" events are QUESTIONS from a background task \u2014 relay to the user in your own words, short, then end your turn. When the user answers, call `AnswerTask` with that id and their answer. NEVER answer on the user\'s behalf for permissions or risky operations; if their reply is ambiguous, confirm first.\nIf the user\'s message sounds INCOMPLETE \u2014 trailing off mid-sentence, a fragment that needs more context ("and then we", "but the problem is"), hesitation fillers ("uh", "um") \u2014 call `Hold` instead of answering. This keeps listening for the rest of their thought. Only respond with substance when you have a complete question or request.\nDispatch discipline: send ONE self-contained task per request \u2014 a single worker with the full brief beats several workers with fragments (each worker starts fresh and re-discovers context). NEVER dispatch a worker just to read files or gather information \u2014 workers explore and discover context themselves; pass on what you already know and let one worker do the whole job. Split into parallel tasks only when the user asks for genuinely independent things. When a task completes, report its result and stop \u2014 do NOT dispatch follow-up work (verification, polish, extras) the user did not ask for, unless the report itself signals failure or doubt.\nDo not fire a second Act/Think for work already in flight, and NEVER spawn a second task to re-count, cross-check, or verify a result a worker already gave you \u2014 trust its answer; a single question gets ONE task. Call `TaskStatus` at most ONCE per turn; if a task is still running, just say "still on it" and end the turn \u2014 never poll it again and again in a loop. Use `CancelTask` when the user asks to stop something.\nPRIORITY: when the user says goodbye or wants to end/finish/wrap up the session ("ok bye", "that\'s all", "let\'s finish", "let\'s end", "goodnight", "exit", "wrap up"), call `ExitSession` IMMEDIATELY \u2014 do not act, do not check status, just exit.\nFor TRIVIAL instant lookups only \u2014 current time, git branch, listing a folder, peeking at a small file, or checking your own `capabilities`/tools \u2014 use `QuickLook` (instant, no task). Whenever the user asks what you can do or whether you have some ability, QuickLook `capabilities` and answer from that \u2014 never guess. Anything requiring searching, reasoning, running commands, or editing goes through `Act`.\n{{MEMORY_SLOT}}\nUser messages may arrive via speech-to-text and can carry transcription artifacts \u2014 odd words, cut-offs, homophones ("for you" vs "folder"). Read for INTENT, not surface text. If a message seems garbled, surprising, or only half-parses, do NOT guess an action or improvise content from it \u2014 briefly confirm what they meant ("did you mean\u2026?") and wait. A one-line confirm beats a confident wrong answer or an invented response to a request you did not actually understand.';
5975
5985
  var THINK_GUIDANCE = "\u2022 `Think` \u2014 your brain. A premium reasoning model, FAR more expensive than Act. Reserve it for open-ended architecture/design questions, or a problem Act already FAILED at. ALL implementation work \u2014 coding, refactoring, debugging, edge cases, tests \u2014 goes to Act; Act is highly capable. Never send the same work to both.";
5976
5986
  var THINK_DISABLED_GUIDANCE = "(Think tier is not available \u2014 use Act for all escalations.)";
5977
5987
  var VOICE_STYLE_CONVERSATIONAL = `Speak like a person in a live conversation, not an assistant reading a script. React first, then deliver: a quick impulsive beat ("oh nice", "hmm, hold on", "ah, got it") before the substance. Use contractions always. Vary sentence length \u2014 some very short. Light fillers and backchannels are fine ("mm-hm", "right", "let's see") but at most one per reply \u2014 never stack them. When you escalate to Act or Think, say it like a human would ("hang on, let me actually dig into that \u2014 gimme a minute") instead of announcing a task. When a result comes back, react to it like you just found out ("okay so \u2014 turns out\u2026"). Match the user's energy: a quick question gets a quick answer \u2014 a few words is a perfectly good turn. Prefer a short answer plus an offer ("want the details?") over covering everything. Never narrate your own mechanics (no "I will now act", no task ids out loud).`;
@@ -5983,6 +5993,14 @@ var DuplexAgent = class _DuplexAgent {
5983
5993
  queue = Promise.resolve();
5984
5994
  seq = 0;
5985
5995
  pendingEvents = [];
5996
+ /** Spoken text of parked deliveries that have SETTLED, awaiting a trivial-barge resume decision on the
5997
+ * next turn (a substantive turn clears it — the result stays in the transcript, recoverable by asking). */
5998
+ parkedRedeliver = [];
5999
+ /** A trivial barge arrived while a parked delivery was STILL RUNNING → resume it the moment it settles. */
6000
+ awaitTrivialRedeliver = false;
6001
+ /** Set by a SUBSTANTIVE turn after a barge: the user moved on, so a parked delivery that settles LATER
6002
+ * must NOT arm a resume (else a much-later "go on" replays a stale result). Reset by a fresh barge. */
6003
+ suppressParkedResume = false;
5986
6004
  /** Out-of-band follow-up attribution for the events coalescing into the next flush turn: TRUE iff ≥1 of
5987
6005
  * the tasks being integrated was NON-CLEAN (early-stop/failure). Carried out-of-band on the enqueue call
5988
6006
  * by the caller that KNOWS the outcome — a plain boolean the MODEL CANNOT PERTURB. It is NOT scanned from
@@ -6064,7 +6082,7 @@ var DuplexAgent = class _DuplexAgent {
6064
6082
  ];
6065
6083
  const workerMcp = mcpNames.length ? `, and it can use these MCP servers: ${[...new Set(mcpNames)].join(", ")}` + (mcpNames.some((n) => /browser/i.test(n)) ? ' \u2014 including driving a REAL browser (open tabs, navigate, click, screenshot), so answer "yes" if asked whether you can control/drive a browser and route an actual browse to Act' : "") : "";
6066
6084
  const prompt = VOICE_SYSTEM_PROMPT.replace("{{MEMORY_SLOT}}", memSlot).replace("{{THINK_SLOT}}", thinkSlot).replace("{{WORKER_WEB}}", workerWeb + workerMcp) + (o.voiceStyle === "conversational" ? "\n" + VOICE_STYLE_CONVERSATIONAL : "") + (o.emotionTags ? "\n" + EMOTION_TAGS_GUIDANCE : "") + `
6067
- Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6085
+ ${nowLine()}. Anchor every relative or time-sensitive reference \u2014 "today", "now", "current", "recent", "latest", "this year" \u2014 to THIS moment. When the user asks about something recent (news, sports, events), they mean near this date, not a well-known past instance; brief your worker with the current year so it searches for what is happening NOW, not a famous older event.`;
6068
6086
  const tools = [
6069
6087
  ...o.reflexOptions?.tools ?? [],
6070
6088
  this.actTool(),
@@ -6244,6 +6262,14 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6244
6262
  * host NOW (this is the latency win) and streaming continues live. Any other content aborts the
6245
6263
  * speculation first (rolled back silently) and runs a normal turn behind it. */
6246
6264
  send(content) {
6265
+ if (typeof content === "string" && isTrivialBarge(content) && this.hasParkedDelivery()) {
6266
+ if (this.spec) this.abortSpeculation();
6267
+ return this.enqueue(async () => {
6268
+ this.resetTurn();
6269
+ if (!this.redeliverParked()) this.awaitTrivialRedeliver = true;
6270
+ return { text: "", steps: 0, finishReason: "stop", messages: [] };
6271
+ });
6272
+ }
6247
6273
  const spec = this.spec;
6248
6274
  if (spec?.state === "pending") {
6249
6275
  if (typeof content === "string" && speculationConfirms(spec.text, content)) {
@@ -6259,6 +6285,9 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6259
6285
  return this.enqueue(async () => {
6260
6286
  await this.initMemory();
6261
6287
  this.resetTurn();
6288
+ this.awaitTrivialRedeliver = false;
6289
+ this.parkedRedeliver = [];
6290
+ this.suppressParkedResume = true;
6262
6291
  const res = await this.voice.send(content);
6263
6292
  this.flushHeldReflexTail();
6264
6293
  if (this.silentTurn) await this.ackIfSilent();
@@ -6359,6 +6388,7 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6359
6388
  * tasks keep running and still fold their result into the transcript — recoverable, just not spoken.
6360
6389
  * Returns the parked ids (for logging). Does NOT cancel: that's a deliberate reflex/user action. */
6361
6390
  parkInFlightDeliveries() {
6391
+ this.suppressParkedResume = false;
6362
6392
  const parked = [];
6363
6393
  for (const rec of this.tasks.values())
6364
6394
  if (rec.status === "running" && !rec.deliveryParked) {
@@ -6367,6 +6397,22 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6367
6397
  }
6368
6398
  return parked;
6369
6399
  }
6400
+ /** True while there is a parked delivery to potentially resume: either one already settled (queued) or
6401
+ * one still running that was parked by a barge. */
6402
+ hasParkedDelivery() {
6403
+ return this.parkedRedeliver.length > 0 || [...this.tasks.values()].some((t) => t.status === "running" && t.deliveryParked);
6404
+ }
6405
+ /** Speak any settled-and-queued parked delivery now (trivial-barge resume). Returns false if nothing was
6406
+ * queued yet (the caller then arms awaitTrivialRedeliver so the task resumes the instant it settles). */
6407
+ redeliverParked() {
6408
+ if (!this.parkedRedeliver.length) return false;
6409
+ const text = this.parkedRedeliver.splice(0).join(" ").trim();
6410
+ if (text) {
6411
+ this.options.host?.notify?.({ kind: "speak_utterance", message: text });
6412
+ this.notify("diag", "parked_redelivered", { chars: text.length });
6413
+ }
6414
+ return true;
6415
+ }
6370
6416
  /** Resolve when all queued voice turns AND all in-flight worker tasks have settled (tests, graceful shutdown). */
6371
6417
  async idle() {
6372
6418
  while (true) {
@@ -6438,7 +6484,9 @@ Today's date: ${(/* @__PURE__ */ new Date()).toDateString()}.`;
6438
6484
 
6439
6485
  ## DELIVER (spoken delivery)
6440
6486
  You are reporting back to a user who is LISTENING. Stream your work normally \u2014 your prose is the written work record and detail, and is NOT spoken. Wrap anything the user should HEAR in <spoken>\u2026</spoken> tags. LEAD WITH the actual content they asked for: if they asked for a specific piece of content \u2014 a value, a name, the actual lines, the writing itself \u2014 that content goes INSIDE the <spoken> tags, not a remark about it. Your FIRST <spoken> segment is substantive \u2014 never a greeting or an acknowledgement (the front-end has already acked; do not double-ack). Keep spoken text concise and natural for the ear: short sentences, no markdown. NEVER enumerate in speech \u2014 no numbered or bulleted lists ("One. \u2026 Two. \u2026" is robotic). Deliver multiple items as flowing conversation with brief connective phrasing ("here's one\u2026", "and another\u2026", "oh, and\u2026"), pausing between items with sentence breaks, not numbers.` + (this.options.emotionTags ? " Inside <spoken>, you may prefix a sentence with an inline [emotion] tag (e.g. [excited], [curious]) to color how it is voiced \u2014 only when it genuinely fits, and vary it; [laughter] gives a natural laugh." : "") : "";
6441
- return (recent ? `${brief}
6487
+ return `${nowLine()}.
6488
+
6489
+ ` + (recent ? `${brief}
6442
6490
 
6443
6491
  ## Recent conversation (for context)
6444
6492
  ${recent}` : brief) + verify + deliverContract;
@@ -6482,7 +6530,10 @@ ${recent}` : brief) + verify + deliverContract;
6482
6530
  };
6483
6531
  const splitter = new SpokenSplitter();
6484
6532
  const speak = (seg) => {
6485
- if (seg && !this.tasks.get(id)?.deliveryParked) o.host?.notify?.({ kind: "speak_utterance", message: seg });
6533
+ if (!seg) return;
6534
+ const r = this.tasks.get(id);
6535
+ if (r) r.spokenText = (r.spokenText ? r.spokenText + " " : "") + seg;
6536
+ if (!r?.deliveryParked) o.host?.notify?.({ kind: "speak_utterance", message: seg });
6486
6537
  };
6487
6538
  const coalescer = new SentenceCoalescer();
6488
6539
  const feedSpoken = (s) => {
@@ -6705,6 +6756,16 @@ Another agent just implemented the above. Independently check the CURRENT state
6705
6756
  const tail = rec.splitter?.flush();
6706
6757
  if (tail?.spoken && !rec.deliveryParked) this.options.host?.notify?.({ kind: "speak_utterance", message: tail.spoken });
6707
6758
  if (res.text.trim()) this.voice.transcript.push({ role: "assistant", content: res.text });
6759
+ if (rec.deliveryParked && !this.suppressParkedResume) {
6760
+ const gist = (rec.spokenText ?? "").trim() || res.text.trim();
6761
+ if (gist) {
6762
+ if (this.awaitTrivialRedeliver) {
6763
+ this.awaitTrivialRedeliver = false;
6764
+ this.options.host?.notify?.({ kind: "speak_utterance", message: gist });
6765
+ this.notify("diag", "parked_redelivered", { chars: gist.length });
6766
+ } else this.parkedRedeliver.push(gist);
6767
+ }
6768
+ }
6708
6769
  if (!rec.splitter?.spokeAny && res.text.trim() && !rec.deliveryParked)
6709
6770
  this.options.host?.notify?.({ kind: "speak_utterance", message: res.text });
6710
6771
  }
@@ -11780,7 +11841,7 @@ Project instructions: ./AGENTS.md or ./CLAUDE.md are auto-loaded (scaffold with
11780
11841
  Auto-loaded from ./.agent/: commands/, skills/, memory/, agents/.
11781
11842
 
11782
11843
  REPL shortcuts: !<cmd> runs a shell command inline \xB7 #<note> saves a memory \xB7 @path inlines a file
11783
- REPL slash commands: /help /version /tools /permissions /status /cost /context /transcript /doctor /cwd /model /reasoning /config /rename /compact /memory /rewind /undo /clear /sessions /resume /commands /skills /reload /mcp /init /export /paste /goal /update /exit (duplex: /act /think /tasks /voice /voice-model /think-model)
11844
+ REPL slash commands: /help /version /tools /permissions /status /cost /context /transcript /doctor /cwd /model /reasoning /config /rename /compact /memory /rewind /undo /clear /sessions /resume /commands /skills /reload /mcp /init /export /paste /goal /update /exit (duplex: /act /think /tasks /voice /voice-model /think-model /voice-emotions /voice-reasoning)
11784
11845
  REPL completion: type / (commands+skills) or @ (files) for a LIVE menu \u2014 \u2191/\u2193 select, \u23CE/Tab accept, Esc dismiss.
11785
11846
  REPL multi-line: Option/Alt+Enter inserts a newline, or end a line with \\ to continue. Esc cancels a running turn / clears the input line; double-Esc jumps back to edit a previous message.
11786
11847
  REPL shortcuts: Shift+Tab cycles permission posture (ask \u2192 accept-edits \u2192 plan) \xB7 Alt+T toggles reasoning \xB7 Alt+P switches model \xB7 Ctrl+O toggles verbose tool output \xB7 Ctrl+X Ctrl+E edits the buffer in $EDITOR \xB7 \u2192 or Tab accepts the dim history ghost-suggestion \xB7 Alt+S/Ctrl+S stash/unstash.
@@ -12829,7 +12890,7 @@ async function repl(args, ai, cfg, cwd) {
12829
12890
  voiceLineOpen = false;
12830
12891
  }
12831
12892
  };
12832
- const showReasoning = process.env.VOICE_SHOW_REASONING === "1";
12893
+ let showReasoning = process.env.VOICE_SHOW_REASONING === "1";
12833
12894
  let voiceReasonOpen = false;
12834
12895
  const voiceReasonEnd = () => {
12835
12896
  if (voiceReasonOpen) {
@@ -13719,6 +13780,20 @@ ${task}`;
13719
13780
  return;
13720
13781
  }
13721
13782
  err(dim(` emotion tags in echo: ${showEmotions ? "shown" : "hidden"} (use /voice-emotions on|off)
13783
+ `));
13784
+ }
13785
+ }, "voice-reasoning": {
13786
+ desc: "show/hide the reflex reasoning stream in voice mode \u2014 /voice-reasoning <on|off> (never spoken)",
13787
+ run: async (a) => {
13788
+ const v = a[0]?.toLowerCase();
13789
+ if (v === "on" || v === "off") {
13790
+ showReasoning = v === "on";
13791
+ if (!showReasoning) voiceReasonEnd();
13792
+ err(green(` \u2713 reasoning ${showReasoning ? "shown" : "hidden"} in voice
13793
+ `));
13794
+ return;
13795
+ }
13796
+ err(dim(` reasoning in voice: ${showReasoning ? "shown" : "hidden"} (use /voice-reasoning on|off)
13722
13797
  `));
13723
13798
  }
13724
13799
  }, "voice-model": {