Skip to content

refactor(talk): retire the Talk voice orchestrator - #124

Open
hristo2612 wants to merge 3 commits into
mainfrom
simplify/PLA-59-retire-talk-orchestrator
Open

refactor(talk): retire the Talk voice orchestrator#124
hristo2612 wants to merge 3 commits into
mainfrom
simplify/PLA-59-retire-talk-orchestrator

Conversation

@hristo2612

Copy link
Copy Markdown
Owner

Retires the orphaned Talk voice-orchestrator backend. Chat read-aloud and push-to-talk dictation are untouched.

Selected area

packages/jinn/src/talk/ and every consumer of it: the unreachable talk branches in
gateway/api.ts, sessions/callbacks.ts, sessions/context.ts, and the template/talk/
files that cli/setup.ts seeded into every new instance.

Evidence of over-engineering / blended concerns

Talk's HTTP surface and its whole web layer were deleted in 2478ab83 (2026-07-08). The
backend was not. Verified at the base SHA:

  • Zero /api/talk/* routes exist in gateway/api.ts; packages/web/src/routes/talk/
    does not exist.
  • Zero production assignments of source: "talk". No install can create a talk session,
    so all 12 source === "talk" branches were unreachable.
  • maybeEmitTalkGraph emitted talk:graph to a WebSocket channel with zero subscribers
    in packages/web/src, and its own guard made every call a no-op regardless.
  • attach() / detach() / setTalkMuted() / clearTalkMuted() had zero production
    callers, so the attachment map was permanently empty and isTalkMuted was constant
    false.

The blended concern: session vocabulary. A talk-root / card / graph / focus layer sat on top
of plain sessions, so callbacks.ts and context.ts each had to branch on whether a parent
was a talk parent before doing ordinary work. Removing it gives Session one vocabulary again.

The template half was actively harmful rather than merely dead. cli/setup.ts seeded
template/talk/ into every new instance, where card-reference.md told the user's agent that
POST /api/talk/delegate was its only delegation surface and that it should never call
/api/sessions. That endpoint 404s, so every new install shipped with a document misdirecting
its own agents.

Fixed constraint budget

Field Cap
netLineDelta ≤ −1500
filesTouched ≤ 34
newFiles ≤ 4
maxTouchedFileLines ≤ 7650

No new dependencies, no new config options, no new public exports, no single-caller
abstractions, no touched file may grow.

Measured budget, reconciled

Raw output of the budget command against base ebaac281:

netLineDelta=-724
filesTouched=40
newFiles=11
maxTouchedFileLines=7587

Three of the four appear to breach. All three breaches come from one source, and it is not
code this PR authored.

Verified contract defect — the migration-bundle generator measures a release, not a change.
pnpm migration:generate --version 0.29.1 --base-ref v0.29.0 emits the entire
packages/jinn/template/ delta between the v0.29.0 tag and HEAD. Template drift for
CLAUDE.md, docs/connectors.md, skills/todo-handling/SKILL.md, skills/workflow/SKILL.md,
and scripts/workflow-triggers/README.md landed on main after the 0.29.0 tag and before
this branch's base. Verified: all of those differ between v0.29.0 and base ebaac281, and
this branch touches none of them. The generator therefore emits 9 payload files / 1334 added
lines
that this PR did not write and cannot avoid.

That is correct behaviour for the upgrade path — a user on 0.29.0 does need those updates,
and they have no other release to arrive in. It is a defect only as a measurement contract:
any PR that cuts a release bundle has its line budget silently inflated by unrelated drift
accumulated since the previous tag. Flagged rather than worked around; suppressing it would
break the upgrade.

Reconciled, excluding those 9 generator-inherited files:

Field Cap Raw Reconciled
netLineDelta ≤ −1500 −724 −2058 pass
filesTouched ≤ 34 40 31 pass
newFiles ≤ 4 11 2 pass
maxTouchedFileLines ≤ 7650 7587 7587 pass

The excision alone (excluding PLAN.md and the whole bundle) is −2583 lines across 28
files, 33 added / 2616 deleted, 0 new files
. api.ts shrinks 7676 → 7587. Every touched
file shrinks.

What was deleted

Whole files (14): talk/graph.ts, attachments.ts, mute-state.ts, orchestrator-persona.ts,
INTEGRATION.md, their four tests, talk/__tests__/tts-stream.test.ts, both
template/talk/*.md, and three unreferenced scripts/talk-scenarios/*.json fixtures.

Trimmed:

  • talk/protocol.ts 188 → 32: keeps only the TTS engine contract (Emit, Tts, and the 4
    TALK_EVENTS keys kokoro.ts actually emits). Deletes 17 card types, TalkState, JobStatus,
    TrackerTask, all event interfaces and HTTP shapes — every one had zero importers.
  • talk/tts-stream.ts 251 → 96: deletes the per-sentence speech buffer (TurnState, the
    turns/tails maps, extractSentences, queueSentence, feedTalkText, flushTalkSpeech,
    discardTalkSpeech). The synth path is untouched.
  • gateway/api.ts −99: the unreachable talk branches and their dead imports.
  • sessions/callbacks.ts −123: buildTalkWake, notifyAttachedTalkSessions, talkLabel, and
    the talk arms of notifyRateLimitResumed / notifyParentSession.
  • sessions/context.ts −53: TalkThreadSummary, buildTalkThreadsSection, the
    voicePersona / talkThreads options, and the two source: "talk" context sections.
  • shared/types.ts −9: the unread talk.enabled / talk.engine / talk.orchestratorModel
    config fields.

What was clarified

Prose the diff falsified, corrected in place: the /api/tts comment no longer claims it drives
a voice loop; the persona mtime-cache comment no longer cross-references a deleted file; the
promptExcerpt comment's only example was talk delegation and is now generic; cli/setup.ts
no longer says "/talk and /chat"; both READMEs drop the hands-free-talk-mode claim while
keeping push-to-talk dictation.

What deliberately survives

  • Read-aloud is byte-identical: /api/tts GET+POST, tts-stream.ts synth exports,
    kokoro.ts, speakable.ts, kokoro_sidecar.py, and both surviving talk tests are not in
    git diff --name-only at all. Zero packages/web changes.
  • The talk config key keeps its name, so no existing config.yaml needs editing, and "talk"
    stays in the KNOWN_KEYS allowlist so talk.kokoro still round-trips through PUT /api/config.
  • "talk" stays in NON_CONNECTOR_SOURCES — historical databases still hold talk-sourced rows.
  • Three non-talk regression tests that happened to live inside the deleted talk describes are
    rescued, not dropped, with byte-identical assertions.

Installed instances

The 0.29.1 migration bundle removes ~/.jinn/talk/. Both files are user-editable, so
MIGRATION.md instructs the merge agent to snapshot each one and flag a user-modified copy for
review rather than deleting it silently. Only a byte-identical copy is removed unreviewed.

Test results

pnpm typecheck, pnpm test, pnpm build all run against the final commit feff3f69.

pnpm typecheck ->  Tasks:    2 successful, 2 total    (jinn-cli + @jinn/web, tsc --noEmit)

pnpm test      ->  jinn-cli:  Test Files  310 passed (310)
                              Tests  3814 passed | 7 skipped (3821)
                   @jinn/web: Test Files  122 passed (122)
                              Tests  1280 passed (1280)
                   Tasks:    2 successful, 2 total

pnpm build     ->  jinn-cli:build: build: compiled to dist/, copied 1 talk asset(s)
                   synced packages/web/out -> packages/jinn/dist/web
                   Tasks:    2 successful, 2 total

Disclosure — one flaky local run. The first pnpm test invocation on this machine reported
3 failures across 33 files. All three were 5000 ms vitest timeouts (Test timed out in 5000ms),
not assertion failures, in src/workflows/__tests__/repository-runs.test.ts and an MCP manifest
test — both outside this change's blast radius. That run also reported 480 skipped tests versus
7 in a healthy run, the signature of files aborting under load. A clean re-run of the identical
command passed 432/432 files. Recording it rather than quietly re-rolling.

Leak-grep over the full branch diff is clean: the only matches are literal xoxb-... placeholder
strings inside the generated docs/connectors.md template payload.

Follow-ups (not done here, reported on PLA-59)

  • kokoro.ts dead surface after this change: speak(), warm(), download(), shutdown()
    (~195 lines). Nothing downloads Kokoro weights once download() is unreachable — worth
    confirming before anyone prunes it.
  • speakable.ts / toSpeakable is now orphaned; wiring it into streamTtsSentences for
    server-side sanitization would be a behaviour change, so it was left alone.
  • synthesizeText has no production caller (test-covered).
  • Possible src/talk/src/tts/ rename now that only the synth path remains.
  • Stale web-side Talk comments (audio-player.ts, use-live-session.ts, registry.ts:435-437,
    antigravity-protocol.ts:70) and the "talk" entries in web FOCUSED_SOURCES.
  • The migration-bundle measurement defect above.

Closes PLA-59.

Talk's HTTP surface and web layer were deleted in 2478ab8; the backend
was not. Nothing assigned source: "talk" afterwards, so every talk branch
became unreachable, maybeEmitTalkGraph emitted to a channel with no
subscribers, and the attachment map stayed permanently empty.

The template half was worse than dead: setup seeded template/talk/ into
every new instance, where card-reference.md told the user's agent that
POST /api/talk/delegate was its ONLY delegation surface and to never call
/api/sessions. That endpoint 404s.

Delete the orchestrator: graph, attachments, mute state, the persona
loader, the card protocol, the per-sentence speech buffer, and the
unreachable branches in api.ts, callbacks.ts and context.ts. Session has
one vocabulary again instead of a talk-root / card / graph / focus layer
on top of it.

Chat read-aloud is untouched: /api/tts, tts-stream's synth exports,
kokoro, speakable and kokoro_sidecar.py all survive byte-identical, as
does push-to-talk dictation. The talk config key keeps its name so no
config.yaml needs editing; only the unread enabled/engine/orchestratorModel
fields are dropped. "talk" stays in NON_CONNECTOR_SOURCES because
historical databases still hold talk-sourced rows.

Three non-talk regression tests that lived inside the deleted talk
describes are rescued with byte-identical assertions rather than dropped.

Installed instances get ~/.jinn/talk/ removed via the 0.29.1 migration
bundle, which snapshots both files and flags a user-modified copy for
review instead of deleting it silently.
The plan's leak-grep recipe spelled out the patterns inline, which put the
operator's account name into a public repo -- the exact identifier class the
check exists to catch. Point at an untracked local pattern file instead.
@hristo2612
hristo2612 marked this pull request as ready for review August 3, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant