Repository navigation
[workspace-migration] fix(voice-agent): resolve voice-context.txt fallback via import.meta.url, not cwd - #1332
liususan091219 wants to merge 1 commit into
Conversation
…ce file, not cwd
[workspace-migration] src/voice-agent.ts:641 used bare readFileSync('voice-context.txt', 'utf-8')
as the fallback when no $SUTANDO_MEMORY_DIR/voice-contexts/active pointer was set. The bare
relative path is resolved against the process cwd, which is only the repo root when the
agent is launched via the documented `npx tsx src/voice-agent.ts` from $REPO. For:
- app-bundle launches (cwd = bundle dir, not repo)
- any `cd /tmp && npx tsx <abspath>/src/voice-agent.ts` style invocation
- the soon-to-arrive Sutando.app launch path (#831 SUTANDO_REPO_DIR work)
…the fallback silently fell through to the empty-context branch ("no context loaded"),
masking the bug because the no-env path was the silent-success branch too.
Fix: anchor the fallback to the source file's location. `_voiceAgentDir` already
exists at L187 (= dirname(fileURLToPath(import.meta.url)) = $REPO/src) — the fallback
file sits one dir up at $REPO/voice-context.txt. Resolve via path.join(_voiceAgentDir,
'..', 'voice-context.txt').
This intentionally keeps the fallback REPO-anchored (not workspace) because the file is
a public-repo asset, not per-user state. The audit calls this out as bug 11 — the only
fix is to resolve relative to the source file, since the file's home IS the repo.
Empirical PoC:
CWD=repo: OLD reads OK / NEW reads OK
CWD=/tmp: OLD reads MISSING / NEW reads OK
`npx tsc --noEmit` clean.
Refs v3 workspace-contract audit, bug 11.
|
LGTM — minimum-viable fix. 1 file, +9/-2. Resolves the fallback path from The "silent fallthrough" framing is the right one: the bug isn't that the file wasn't loaded — it's that the failure mode was indistinguishable from "no fallback file exists." A user who did have a Surgical: doesn't change the env-var path priority, doesn't change the pointer-file path, doesn't change the "no context loaded" log when nothing is found. Only the fallback resolver. Minor stylistic (non-blocking): 👍 |
|
LGTM. Verified the resolution target is correct:
The bare |
|
Closing per Susan 2026-05-29 — Qingyun is redesigning the workspace migration approach. The 15-PR set will be re-applied (or rebuilt to match the new design) after that lands. Branch is preserved; can be reopened or cherry-picked when ready. |
Summary
src/voice-agent.ts:641uses a barereadFileSync('voice-context.txt', 'utf-8')as the fallback when no$SUTANDO_MEMORY_DIR/voice-contexts/activepointer is set. The bare path resolves against process cwd, which is only the repo root for the documentednpx tsx src/voice-agent.tslaunch from$REPO. Every other launch path silently fell through to the "no context loaded" branch.Why it's silent
The control flow at L621-648 is:
So when the fallback path fails (cwd != repo), the catch logs "no context loaded — no env, no pointer, no fallback file" — which is also the legitimate empty-context message when none of the three sources exist. Operators couldn't tell from the log line whether the fallback file was missing or the resolver was just wrong.
Affected launch paths
cd /tmp && npx tsx <abspath>/src/voice-agent.tsstyle invocationSUTANDO_REPO_DIRwork) — the app starts the agent with cwd set to the app's working dir, not the checkoutFix
Anchor the fallback to the source file's location via
import.meta.url._voiceAgentDiralready exists at L187 (= dirname(fileURLToPath(import.meta.url)) = $REPO/src). The fallback file sits one dir up at$REPO/voice-context.txt, so:The log line also prints the resolved absolute path now so future cwd-confusion is debuggable from the first run.
This intentionally keeps the fallback repo-anchored, not workspace. The audit explicitly tags this file as "public-repo voice-context.txt" — it's a checked-in asset, not per-user state. Workspace-anchoring would just create a different invisible failure mode (file simply doesn't exist there because nothing puts it there). The primary loader at L623-637 IS workspace/memory-dir anchored; this is the secondary public fallback.
Empirical PoC
npx tsc --noEmitclean.Notes
upstream/main(0 commits behind at branch time).workspace/notes/cwd-audit-v3-2026-05-27.md).🤖 Generated with Claude Code