fix: parse OpenCode nested part.text in JSON output#92
Conversation
OpenCode's --format json output wraps content in obj.part.text (type: "text") or obj.parts[].text (array), but the parser only checked top-level text/content/message fields which are empty strings. This caused both draft and convert features to produce no output when using OpenCode as the agent. Closes nexu-io#67 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
|
Heads-up: #78 is also open against this area — both PRs touch |
| } | ||
| } | ||
| if (obj.type === "text" && typeof obj.part?.text === "string") { | ||
| out.push({ kind: "delta", text: obj.part.text }); |
There was a problem hiding this comment.
parseLineWithState now handles the live part.text shape, but this regression path still has no parser-level test coverage. That matters here because this file is the only contract between the agent CLIs and /api/draft//api/convert; without a fixture that exercises empty top-level text/content/message plus singular part.text and array parts[].text, a later refactor can silently reintroduce the exact start -> done no-output failure this PR is fixing. Please add a small regression matrix around parseLine('opencode', ...)/parseLine('qwen', ...) (for example in a new next/src/lib/agents/argv.test.ts) that asserts these envelopes emit the expected delta chunks.
Covers part.text (singular), parts[].text (array), top-level fields, empty-field scenarios, and multi-line streaming via makeParser. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
| if (obj.type === "text" && typeof obj.part?.text === "string") { | ||
| out.push({ kind: "delta", text: obj.part.text }); |
There was a problem hiding this comment.
These new obj.part?.text / obj.part.text reads do not type-check against the file's parsed Record<string, unknown> shape. On this head, pnpm -F @html-anything/next typecheck fails with TS2339: Property 'text' does not exist on type '{}' on lines 374-375, so the PR still breaks the package's required compile gate even though the runtime regression tests pass. Please narrow obj.part to an object type before reading text here (for example by assigning it to a local, checking typeof part === "object", and then casting to { text?: unknown }) so the parser fix compiles cleanly as well as running correctly.
|
Hey @Aliancn — wanted to close the loop on this. PR #78 just merged into main, and it turns out it landed the same const part =
obj.part && typeof obj.part === "object"
? (obj.part as Record<string, unknown>)
: null;
const text = [part?.text, part?.content, part?.message, obj.text, ...].find(...)That's the singular I'll flag this to the maintainer team to formally close as superseded. Appreciate the contribution — you found the right field at the right time. 🙌 |
Problem
OpenCode's
--format jsonoutput wraps content in nested fields, but the parser only checked top-leveltext/content/messagefields (which are empty strings). This causes both draft and convert features to produce no output when using OpenCode as the agent.Closes #67
OpenCode actual output format
OpenCode emits JSON lines like:
{"type":"text","part":{"type":"text","text":"actual content here"}}The real content lives in:
obj.part.text(single object, whenobj.type === "text")obj.parts[].text(array form, for forward-compatibility)Top-level
text/content/messageare empty strings.Fix
Extended the OpenCode/Qwen parser in
argv.tsto also extract content from:obj.parts[].text— array formobj.part.textwhenobj.type === "text"— the actual current output formatTesting
Relationship to PR #78
PR #78 addressed this issue by adding
parts[].textparsing, but it doesn't cover the actualpart.text(singular) field that OpenCode currently emits. This PR covers both cases.