Skip to content

feat: claude effort controls, ultrathink UI, and adapter robustness#1146

Merged
juliusmarminge merged 9 commits intopingdotgg:codething/648ca884-claudefrom
JustYannicc:codex/pr-179-no-teams
Mar 17, 2026
Merged

feat: claude effort controls, ultrathink UI, and adapter robustness#1146
juliusmarminge merged 9 commits intopingdotgg:codething/648ca884-claudefrom
JustYannicc:codex/pr-179-no-teams

Conversation

@JustYannicc
Copy link

@JustYannicc JustYannicc commented Mar 16, 2026

What Changed

Claude Effort Controls & Ultrathink

  • Added ClaudeCodeEffort type with levels: low, medium, high, max, ultrathink
  • getEffectiveClaudeCodeEffort() maps effort levels to Claude SDK values
  • applyClaudePromptEffortPrefix() prepends "Ultrathink:" prefix to prompts
  • Generalized CodexTraitsPicker into a provider-aware traits picker with Claude effort labels
  • Ultrathink composer chrome: animated rainbow border, chroma pill badge, model picker glow effect

Adapter Robustness (Background Agents & Subagents)

  • Synthetic turn auto-start: Assistant messages arriving without an active turn (background agent/subagent responses between user prompts) now auto-start a synthetic turn so the response is visible in the UI
  • Stale turn cleanup: Auto-close orphaned synthetic turns in sendTurn to prevent session deadlock
  • Fragment leak prevention: Clear inFlightTools map in completeTurn to prevent stale JSON fragments from corrupting subsequent turns

Subagent Progress Surfacing

  • Claude task.progress events surface as activities with summary and lastToolName
  • collab_agent_tool_call classification for Agent/Task tools with "Subagent task" labels
  • Tests for tool classification and progress forwarding

Provider Health

  • Refreshed health check status probes with Fiber-based concurrent execution

Why

Background agent results, subagent responses, and tool call details were silently dropped because the adapter's turn state machine only handled user-initiated turns. When a background agent finished work and the lead generated a response, that response was invisible in the UI.

The effort controls bring feature parity with the Codex reasoning effort UI, adapted for Claude's effort model including the ultrathink mode.

UI Changes

  • Ultrathink mode shows an animated rainbow border around the composer and a chroma-animated "Ultrathink" pill badge
  • Effort dropdown shows Claude-specific labels (Low / Medium / High / Max / Ultrathink)
  • Provider model picker shows chroma animation when ultrathink is active

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • Type checks clean across web, server, and contracts
  • All 35 existing tests pass

Note

Add Claude effort controls and ultrathink UI to the chat composer

  • Adds ClaudeCodeEffort options (low, medium, high, max, ultrathink) to contracts and shared model utilities, with ultrathink mapping to max at runtime and prefixing outgoing prompts with 'Ultrathink:\n'.
  • The chat composer resolves effort per provider, dispatches modelOptions.claudeAgent.effort in turn payloads, and shows an animated 'Ultrathink' pill and rainbow frame when ultrathink is active.
  • ClaudeAdapter forwards effective effort into Claude SDK query options and auto-closes a stale active turn instead of returning a validation error when sendTurn is called.
  • ProviderCommandReactor restarts the Claude session when modelOptions change between turns, and carries cached model options forward on runtime-mode changes.
  • ProviderTraitsPicker replaces CodexTraitsPicker with a provider-agnostic picker that shows Fast Mode only for Codex and uses provider-specific effort labels.
  • Risk: default Claude effort changes from null to 'high'; existing sessions without a persisted effort will now send effort: 'high' to the Claude API.

Macroscope summarized 3e5371c.

@coderabbitai
Copy link

coderabbitai bot commented Mar 16, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 47233b76-5c43-4f45-849f-ab43bdcef837

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Mar 16, 2026
@JustYannicc JustYannicc reopened this Mar 16, 2026
@JustYannicc JustYannicc marked this pull request as draft March 16, 2026 19:55
@JustYannicc JustYannicc changed the base branch from main to codething/648ca884-claude March 16, 2026 19:57
@JustYannicc JustYannicc force-pushed the codex/pr-179-no-teams branch from abb5d9c to 2439fca Compare March 16, 2026 20:17
@JustYannicc JustYannicc changed the title fix: improve claude adapter robustness for background agents feat: claude effort controls, ultrathink UI, and adapter robustness Mar 16, 2026
@JustYannicc JustYannicc marked this pull request as ready for review March 16, 2026 20:33
@juliusmarminge
Copy link
Member

had to do some sweeping changes to align with anthropic branding guidelines. can you resolve the conflicts?

@JustYannicc
Copy link
Author

yes working on it

@JustYannicc JustYannicc force-pushed the codex/pr-179-no-teams branch from 2439fca to f882fc9 Compare March 16, 2026 23:08
@JustYannicc
Copy link
Author

@juliusmarminge done. you should be able to merge it no problem now.

<svg {...props} preserveAspectRatio="xMidYMid" viewBox="0 0 256 257">
<path
fill="#D97757"
fill="currentColor"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the Claude icon needs to inherit Tailwind text color from the caller. Icons.tsx (line 146) so the styling in ProviderModelPicker.tsx (line 120) actually works, including the normal Claude orange and the ultrathink-chroma state. With a hardcoded fill, those classes were ignored.

MenuTrigger,
} from "../ui/menu";

export const CodexTraitsPicker = memo(function CodexTraitsPicker(props: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm not sure it's worth compacting these as one just yet... we don't really know what the future will look like so keeping them separate for now is the best. iirc i separated them when i had all codex/claude/cursor working because they had differernt enough logic to justify separate components instead of single component with switch statements internalyl

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason for the refactor is that ChatView only renders one traits-picker slot, and the current UI shape is still the same for both providers: one menu, one effort selector, plus Codex-only fast mode in the same surface. You can point at ChatView.tsx (line 3630) and CodexTraitsPicker.tsx (line 37).

But if you want I can change the implementation to be less of an abstraction

const TaskProgressPayload = Schema.Struct({
taskId: RuntimeTaskId,
description: TrimmedNonEmptyStringSchema,
summary: Schema.optional(TrimmedNonEmptyStringSchema),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does this cover that "description" doesn't? is it something claude specific? not opposed to keeping mostly curious

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description is the provider’s raw task label, while summary is an optional more user-facing progress line when the provider gives both. Claude does give both on task_progress; see ClaudeAdapter.ts (line 1698). The ingestion layer then prefers summary for the activity detail and falls back to description; see ProviderRuntimeIngestion.ts (line 363). it is an optional field that preserves richer provider data without overloading description.

JustYannicc and others added 9 commits March 17, 2026 10:41
- Auto-start synthetic turns for assistant messages arriving without an
  active turnState (fixes invisible background agent/subagent responses
  that arrive between user-initiated turns)
- Auto-close stale synthetic turns in sendTurn to prevent session deadlock
  when a background response left an orphaned turn open
- Clear inFlightTools between turns in completeTurn to prevent stale JSON
  fragments from corrupting the next turn's tool inputs
- Fix missing Fiber import in ProviderHealth

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The clear() was placed before the loop that emits item.completed events
for remaining in-flight tools, causing the loop to never execute. Move
it after the loop so tools get properly finalized before cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Updates all remaining references from "claudeCode" to "claudeAgent"
to match the Anthropic branding guidelines applied upstream. Includes
provider kind literals, object property keys, test payloads, and
component comparisons across server, web, and shared packages.

Also fixes synthetic turn state to match upstream's refactored
ClaudeTurnState interface (assistantTextBlocks map instead of the
old assistantItemId/messageCompleted/emittedTextDelta fields).

Also fixes inFlightTools.clear() placement: moved after the loop
that emits item.completed events for remaining in-flight tools,
so tools are properly finalized before cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@JustYannicc JustYannicc force-pushed the codex/pr-179-no-teams branch from 49e27ab to 3e5371c Compare March 17, 2026 09:43
@JustYannicc
Copy link
Author

@juliusmarminge let me know if you have any other concerns.

@juliusmarminge juliusmarminge merged commit e6254a8 into pingdotgg:codething/648ca884-claude Mar 17, 2026
7 checks passed
@JustYannicc JustYannicc deleted the codex/pr-179-no-teams branch March 18, 2026 09:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants