Skip to content

v0.19.2

Choose a tag to compare

@github-actions github-actions released this 10 Sep 08:29
9bcb276

Fixed

  • Phase sub-agents died instantly on any model from an extension-registered provider. A phase failed in 38ms with No API key found for <provider>. Use /login to log into a provider…, while the same model worked in the orchestrator session that launched it, and /login could not fix it because the parent's credentials were never the problem. All three child sessions codecarto creates — the phase runner, the next-phase rewriter, and the dashboard narrator — load with noExtensions: true so a globally installed codecarto does not register its commands and tool guards a second time inside its own sub-agent. But providers a different global extension contributes through pi.registerProvider() reach the model runtime by exactly the same path: Pi registers them from the resource loader that loaded the extension. Stripping extensions therefore stripped the provider table too, so the child inherited the parent's selected model object and then had no provider definition to resolve it against. AgentSession.prompt() checks hasConfiguredAuth before its first turn, that check returned false for a provider the child had never heard of, and the phase was dead before a single token was sent — which is why the failure was instant and cost nothing. Built-in providers were unaffected, so this only bit users who had wired up their own. Child sessions now carry the parent's registered provider configs onto their own runtime, keeping the sub-agent on the model the user actually picked while preserving the extension isolation the flag is there for.

  • Reasoning tokens were eating the output budget, truncating lens JSON and billing for thinking that was thrown away. Broad-Side sent no reasoning field at all, so every model applied its own default. A reasoning-capable model then spent its max_tokens thinking rather than answering: one measured run used 5,758 of a 6,000-token budget on reasoning and left ~230 tokens for the JSON, which truncated mid-structure on 11 of 13 slices. Those tokens bill at the full output rate, so the run paid for roughly 6,000 output tokens per slice to receive 230 usable ones — and estimateCost had no way to anticipate it, since it budgets output on the assumption that output means JSON. #133's truncation repair could not rescue it either: doubling the cap scales the reasoning budget too, so 24 completed retry jobs moved that run from 2 parseable slices to 3. This was not a multi-model problem. The shipped default model does the same thing less consistently — reasoning from 0 to 5,757 tokens across the same 13 slices, three of them cut off at finish_reason: length — so runs have been quietly losing slices to it all along. Lens requests now carry an explicit reasoning budget, capped at a quarter of the lens's output allowance so three quarters remain for the answer, which is precisely the split estimateCost already assumed. It is a cap rather than an off switch on purpose: google/gemini-3.8-flash:batch refuses an entire batch with "Reasoning is mandatory for this endpoint and cannot be disabled", so disabling turns a partial result into none at all — verified live, 13 of 13 requests failed that way. Capping works either way. Measured on the same model, same commit, same 13 slices: 2 of 13 slices parseable before, 13 of 13 after, with finish_reason: stop and reasoning_tokens: 0 across the board, and 37 findings where the uncapped run produced 6. A lens can set its own reasoning, and reasoning: in .codecarto/broadside/config.yaml overrides every lens.

  • The shipped config.yaml recommended a model that cannot be submitted. Its lens_models example named anthropic/claude-opus-4.5:batch for the security and defect lenses, and that id has no batch endpoint — submitting it returns Model 'anthropic/claude-opus-4.5:batch' does not have a :batch endpoint. Every Anthropic and OpenAI batch id tried so far is rejected the same way, while Google's and DeepSeek's work, and nothing in OpenRouter's catalog distinguishes them beforehand. The example now names a verified-submittable model, and both config.yaml and the Broad-Side skill explain that the models action lists ids the Batch API will refuse and that a rejected batch costs nothing, so a candidate should be probed on one lens before being relied on.

  • /codecarto-complete threw its refusals instead of showing them. Completion refuses for reasons the framework words carefully — a missing phase handoff names the file to write and every field it needs; a carry-forward without derives_from and a closure lacking runtime evidence explain what is missing and why. That guidance is the entire point of the refusal. Every other failure in this handler was caught and notified, but the autoCompletePhase call was not, so those messages escaped as a rejection and the user never saw them. It was the only unguarded call of its kind in the extension; switch-pipeline, refresh-scaffold, amend and the post-phase path all wrap theirs. The irony was sharp: /codecarto-next catches this same throw and advises running /codecarto-complete manually, which then threw. Found by writing the first tests that invoke these handlers at all.