Skip to content

🐛 fix: adjust content parsing#141

Draft
mtfoley wants to merge 11 commits intopapercomputeco:mainfrom
mtfoley:pr-parse-ollama-content
Draft

🐛 fix: adjust content parsing#141
mtfoley wants to merge 11 commits intopapercomputeco:mainfrom
mtfoley:pr-parse-ollama-content

Conversation

@mtfoley
Copy link

@mtfoley mtfoley commented Mar 4, 2026

This PR resolves #137.

@mtfoley
Copy link
Author

mtfoley commented Mar 7, 2026

FWIW, with the changes I have thus far, tapes is showing something for the conversation when using opencode and ollama, but I'm seeing some json.Unmarshal errors about tools. When I fix those errors, I'm seeing the conversation getting recorded, but it doesn't seem like deduplication is happening the way it ought to.

@mtfoley mtfoley force-pushed the pr-parse-ollama-content branch from 65c49ab to 2a92eb4 Compare March 9, 2026 00:00
@mtfoley
Copy link
Author

mtfoley commented Mar 9, 2026

Hi @jpmcb @bdougie, I'm leaving this PR in draft as I'd love some feedback, mainly on the tactic. Downsides are discussed below.

To reiterate what this change fixes, I was following along with configuration described on opencode docs and ollama docs, and I found that tapes wasn't recording anything, because its provider configuration was looking for a different format (e.g. the ollamaMessage struct). This change makes it so that if ollama provider encounters json.Unmarshal errors on requests, or responses, it will fall back to the OpenAI flavor. I refactored things so that new providers aren't spun up just to parse.

The downside to doing things this way is that every request and response gets json.Unmarshal twice when using tapes start opencode --provider ollama. There might be an opportunity at the proxy layer to take a hint from a path like /v1/chat/completions and perhaps flip a switch on the Ollama provider, or to abstract it further, make a 2nd flavor of Ollama provider meant to be used with OpenAI format. I do think that given that Ollama could respond in more than one format on different endpoints, it would be beneficial to bake that diversity into tapes in some way.

There's a related change here in proxy to capture usage statistics with an OpenAI format in Ollama to cover the gap if the ollama format didn't happen to work.

This all does appear to work as expected as far as tapes capturing conversations when I test locally. There are 3 more areas for improvement that would come to light with this change:

  1. I don't think the way TotalTokens are aggregated is compatible with the usage gathering code path here, but I can file a follow-up issue for that (e.g. a single opencode/ollama session will include multiple responses that include usage statistics accumulated thus far, so the last one is the one that matches the token count in opencode's UI, rather than the aggregate number).
  2. deck currently seems to show messages with role=tool as a User role. UI might be improved if these were shown in some other way.
  3. opencode occasionally spins up sub-agents, especially in the case of some research in Plan mode that may be more open-ended, presumably so the main agent conserves tokens. These subagents' calls to Ollama appear in tapes as separate sessions IIRC, but i noticed that the tool is called "task". Perhaps the function toolUsageIcon in tui_util.go could have a separate icon meant to call out subagent activity.

@mtfoley
Copy link
Author

mtfoley commented Mar 12, 2026

bump @bdougie @jpmcb. I'll join the Discord soon, I've had some trouble with my account and MFA as of late.

@bdougie
Copy link
Contributor

bdougie commented Mar 13, 2026

Thanks for the detailed writeup and the PR @mtfoley! The refactor to extract ParseRequestPayload/ParseResponsePayload as standalone functions is a nice foundation regardless of approach.

Re: the double-unmarshal concern -- I think path-based hinting at the proxy layer is the right call. The proxy already resolves the request path in resolveAgent() before provider selection happens (proxy.go:155), so we have /v1/chat/completions available at that point. The simplest version would be: when the resolved provider is Ollama but the path looks like an OpenAI-compatible endpoint (/v1/chat/completions), use the OpenAI parser directly.

Concretely, this could live in resolveProvider() -- if the provider is ollama and the path starts with /v1/, return the OpenAI provider instead (or a thin wrapper). That way parsing happens once with the correct parser, no fallback needed. The Provider interface stays unchanged and no double-unmarshal on every request.

The SSE usage extraction change in proxy.go for the OpenAI usage object in Ollama streams looks good and would still be needed with this approach.

For the follow-up items you mentioned: agree those are separate concerns -- feel free to file issues for the TotalTokens aggregation, tool role display in deck, and subagent icon. Happy to discuss further on Discord once you're sorted with your account.

@bdougie bdougie changed the title fix: adjust content parsing 🧹 chore: adjust content parsing Mar 14, 2026
@bdougie bdougie changed the title 🧹 chore: adjust content parsing 🐛 fix: adjust content parsing Mar 14, 2026
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.

Content parsing issue with OpenCode / Ollama

2 participants