diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e1e1abf8..b47b0b2f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,12 @@ ### Highlights - **Thinking directives & state:** `/t|/think|/thinking ` (aliases off|minimal|low|medium|high|max/highest). Inline applies to that message; directive-only message pins the level for the session; `/think:off` clears. Resolution: inline > session override > `inbound.reply.thinkingDefault` > off. Pi/Tau get `--thinking ` (except off); other agents append cue words (`think` → `think hard` → `think harder` → `ultrathink`). Heartbeat probe uses `HEARTBEAT /think:high`. -- **Verbose directives + session hints:** `/v|/verbose on|full|off` mirrors thinking: inline > session > config default. Directive-only replies with an acknowledgement; invalid levels return a hint. When enabled, tool results from JSON-emitting agents (Pi/Tau, etc.) are forwarded as `🛠️ …` messages (now streamed as they happen), and new sessions surface a `🧭 New session: ` hint. +- **Verbose directives + session hints:** `/v|/verbose on|full|off` mirrors thinking: inline > session > config default. Directive-only replies with an acknowledgement; invalid levels return a hint. When enabled, tool results from JSON-emitting agents (Pi/Tau, etc.) are forwarded as `[🛠️ ] …` messages (now streamed as they happen), and new sessions surface a `🧭 New session: ` hint. - **Directive confirmations:** Directive-only messages now reply with an acknowledgement (`Thinking level set to high.` / `Thinking disabled.`) and reject unknown levels with a helpful hint (state is unchanged). - **Pi/Tau stability:** RPC replies buffered until the assistant turn finishes; parsers return consistent `texts[]`; web auto-replies keep a warm Tau RPC process to avoid cold starts. - **Claude prompt flow:** One-time `sessionIntro` with per-message `/think:high` bodyPrefix; system prompt always sent on first turn even with `sendSystemOnce`. - **Heartbeat UX:** Backpressure skips reply heartbeats while other commands run; skips don’t refresh session `updatedAt`; web/Twilio heartbeats normalize array payloads and optional `heartbeatCommand`. +- **Tau completion signal:** RPC now resolves on Tau’s `agent_end` event so late assistant messages (e.g., camera snap + weather) aren’t truncated. ### Reliability & UX - Outbound chunking prefers newlines/word boundaries and enforces caps (1600 WhatsApp/Twilio, 4000 web). diff --git a/src/process/tau-rpc.ts b/src/process/tau-rpc.ts index adaddeb57..55e360ddc 100644 --- a/src/process/tau-rpc.ts +++ b/src/process/tau-rpc.ts @@ -67,6 +67,25 @@ class TauRpcClient { if (!this.pending) return; this.buffer.push(line); this.pending?.onEvent?.(line); + + // If Tau signals the full prompt/response cycle is finished, resolve immediately. + try { + const evt = JSON.parse(line) as { type?: string }; + if (evt?.type === "agent_end") { + if (this.idleTimer) clearTimeout(this.idleTimer); + const pending = this.pending; + this.pending = undefined; + const out = this.buffer.join("\n"); + this.buffer = []; + this.seenAssistantEnd = false; + clearTimeout(pending.timer); + pending.resolve({ stdout: out, stderr: this.stderr, code: 0 }); + return; + } + } catch { + // ignore malformed/non-JSON lines + } + // Streamed JSON arrives line-by-line; mark when an assistant message finishes // and resolve after a short idle to capture any follow-up events (e.g. tools) // that belong to the same turn.