Skip to content

perf(providers): provider capabilities and default turn-session adapter (PR7) - #720

Merged
Vasanthdev2004 merged 4 commits into
mainfrom
perf/provider-turn-session
Jul 18, 2026
Merged

perf(providers): provider capabilities and default turn-session adapter (PR7)#720
Vasanthdev2004 merged 4 commits into
mainfrom
perf/provider-turn-session

Conversation

@Vasanthdev2004

@Vasanthdev2004 Vasanthdev2004 commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Implements PR7 of the Zero Agent Performance Program: provider capabilities and the default turn-session adapter — the architecture seam that PR8 (one optimized provider session) and a future native-compaction session plug into without touching the agent loop again.

Added

  • zeroruntime.TurnSession — one provider conversation per run: Prewarm (best-effort, no-op by default), Stream (signature-identical to Provider.StreamCompletion), Compact (returns ErrCompactionUnsupported on the default adapter; dormant until a native-compaction session exists), Close (idempotent no-op by default).
  • zeroruntime.TurnSessionProvider — opens a session for a run and exposes ProviderCapabilities.
  • zeroruntime.ProviderCapabilities — a flat projection of the resolved model's static capabilities (context window, max output tokens, vision/reasoning/prompt-cache flags, reasoning efforts). Deliberately plain data: modelregistry imports zeroruntime, so typed registry fields here would form an import cycle. providers.NewTurnSessionProvider does the projection instead.
  • providers.NewTurnSessionProvider — builds the default adapter for every current provider kind (openai, openai-compatible, anthropic, anthropic-compatible, google, and the chatgpt path via New), populating capabilities from the same registry entry New already resolves.
  • Loop integration: agent.Run opens a session at run start (before session hooks, so a failed open is a clean run-start error with nothing to unwind), routes all provider I/O through it via a one-line Provider shim — per-turn streams, mid-stream retries, the compaction summarizer, and the final-answer request — and closes it at teardown. A mid-run model switch closes the old session and opens a fresh one over the escalated provider.
  • Options.TurnSessionProvider (optional): nil keeps the default wrapper over the passed provider, so every existing caller is unaffected — no signature changes anywhere.

No performance change expected

This PR is a pure extension point. The default session's Stream is provider.StreamCompletion; Prewarm/Close are no-ops; no extra network round-trips, no hot-path allocation beyond a value-typed shim. Behavior identity is asserted by tests, not claimed: the same scripted run with the default path and an explicit adapter produces identical results and request counts.

Safety properties

Preserves permissions, sandboxing, secret scrubbing, output ceilings, transcript ordering, exactly one result per tool call, reconnect/stall-retry behavior (streamWithReconnect is unchanged and still wraps every stream), and cancellation semantics. A TurnSession.Close failure never fails the run; a Prewarm failure is ignored by contract.

Scope boundaries

No connection reuse, prewarm implementation, request-prefix fingerprint reuse, provider-specific sessions, or native compaction — those are PR8 and later, behind this seam. The ModelSwitcher contract still returns a bare Provider, so an optimized session is not carried across a mid-run swap (documented next to the existing context-window limitation; fixing both needs the same switcher contract change).

Verification

  • go build ./..., go vet ./..., gofmt -l clean
  • go test ./internal/zeroruntime/ ./internal/providers/... ./internal/agent/ ./internal/cli/ ./internal/tui/ green
  • New tests: default-adapter forwarding is verbatim (request and events), Prewarm/Close no-op + idempotent, Compact unsupported; fault injection — a failed OpenTurnSession surfaces as a wrapped run-start error with zero provider requests, a failing Close is swallowed; every request of a run flows through the session (prewarmed once, closed once); the default path is behavior-identical to an explicit adapter; a mid-run model switch closes the old session exactly once and continues on the new provider; every provider kind wraps; registry capabilities project correctly.
  • Existing escalation, completion-gate, and reconnect test suites pass unchanged.

Summary by CodeRabbit

  • New Features
    • Added per-run turn sessions to centralize streaming and lifecycle handling.
    • Introduced TurnSessionProvider and ModelSessionSwitcher options for target-aware mid-run escalation.
    • Added capability projection for sessions (limits, support flags, reasoning tiers).
  • Reliability
    • Turn session open failures surface cleanly; teardown close errors no longer fail runs.
    • Mid-run model/session switching continues on errors and records a user-visible notice.
  • Tests
    • Expanded coverage for session routing, lifecycle safety, capability projection, and escalation switching behavior.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 36296485-7428-4851-8ec5-5ff73a67077e

📥 Commits

Reviewing files that changed from the base of the PR and between 968cd1e and 39d0136.

📒 Files selected for processing (1)
  • internal/agent/turn_session_test.go

Walkthrough

Adds per-run turn-session abstractions and default provider adapters, projects model capabilities, routes agent-loop I/O through sessions, and reopens sessions during model escalation with lifecycle and compatibility tests.

Changes

Turn session execution

Layer / File(s) Summary
Session contracts and default adapter
internal/zeroruntime/session.go, internal/zeroruntime/session_test.go, internal/agent/turn_session.go
Defines turn-session lifecycle, streaming, compaction, and capability contracts, with a default adapter that forwards to existing providers.
Provider factory and capabilities
internal/providers/factory.go, internal/providers/factory_turn_session_test.go
Adds NewTurnSessionProvider and projects registry model metadata into provider capabilities, including effective reasoning efforts.
Agent loop session lifecycle
internal/agent/types.go, internal/agent/loop.go
Adds configurable session providers, routes run-loop I/O through sessions, and replaces the session during model escalation.
Agent lifecycle validation
internal/agent/turn_session_test.go
Validates session opening, prewarming, closure, request routing, default behavior, and model-switch continuation and errors.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant AgentRun
  participant TurnSessionProvider
  participant TurnSession
  participant ModelSessionSwitcher
  AgentRun->>TurnSessionProvider: Open initial turn session
  AgentRun->>TurnSession: Prewarm and stream completions
  AgentRun->>ModelSessionSwitcher: Request target model session
  ModelSessionSwitcher-->>AgentRun: Return switched session provider
  AgentRun->>TurnSession: Close previous session
  AgentRun->>TurnSession: Stream subsequent completions
Loading

Possibly related PRs

  • Gitlawb/zero#167: Modifies agent-loop streamed completion handling and reasoning-effort propagation.
  • Gitlawb/zero#581: Modifies the agent-loop session lifecycle and related hook ordering.

Suggested reviewers: anandh8x, gnanam1990

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main changes: provider capabilities plus the default turn-session adapter.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/provider-turn-session

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/agent/loop.go`:
- Around line 748-768: The model-switch path in internal/agent/loop.go lines
748-768 must preserve the configured optimized TurnSessionProvider instead of
always wrapping the switched Provider with the default adapter; update the
ModelSwitcher contract or add a target-aware session resolver that returns the
appropriate provider/model session, while retaining prewarm, replacement, and
close behavior. In internal/agent/turn_session_test.go lines 190-215, add a
distinct switched session and assert it receives streams, is prewarmed, and is
closed exactly once.

In `@internal/providers/factory.go`:
- Around line 151-153: Update the capability construction loop in the provider
factory to populate caps.ReasoningEfforts from
Registry.ReasoningEfforts(strings.TrimSpace(profile.Model)) instead of
entry.ReasoningEfforts, preserving the string conversion and append behavior.
Add a fixture covering a registered model whose effective reasoning efforts
differ from the raw catalog entry.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4ffc9921-f6f5-4099-b488-d975930776a9

📥 Commits

Reviewing files that changed from the base of the PR and between 18cce35 and e2c4c42.

📒 Files selected for processing (8)
  • internal/agent/loop.go
  • internal/agent/turn_session.go
  • internal/agent/turn_session_test.go
  • internal/agent/types.go
  • internal/providers/factory.go
  • internal/providers/factory_turn_session_test.go
  • internal/zeroruntime/session.go
  • internal/zeroruntime/session_test.go

Comment thread internal/agent/loop.go Outdated
Comment thread internal/providers/factory.go Outdated
@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 39d0136eb228
Changed files (8): internal/agent/loop.go, internal/agent/turn_session.go, internal/agent/turn_session_test.go, internal/agent/types.go, internal/providers/factory.go, internal/providers/factory_turn_session_test.go, internal/zeroruntime/session.go, internal/zeroruntime/session_test.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator Author

Addressed the review in 96ac8689 — one fix, one deliberate defer:

  • Effective reasoning efforts: fixed. resolveCapabilities now reads efforts through Registry.ReasoningEfforts instead of the raw entry, so the projection matches what the /effort picker and run-time resolver advertise — including the name-inferred fallback for catalog entries that enumerate no efforts of their own. Added TestNewTurnSessionProviderUsesEffectiveReasoningEfforts with a gpt-5-family fixture whose entry lists no efforts but projects [minimal low medium high]. Good catch — the whole point of the flat projection is that it agrees with what the rest of the product reports.

  • Optimized session across a mid-run model switch: deliberately out of scope. The switch path wrapping the escalated provider in a default session is the documented limitation, not an oversight: ModelSwitcher returns a bare Provider, so carrying an optimized session across a swap needs a switcher contract change — the same change the pre-existing context-window limitation right below it has been waiting on. In this PR there is no optimized session implementation at all (the default adapter is the only one), so the limitation is unreachable today; it becomes real work when the optimized session lands, and the contract change belongs there. The suggested distinct-switched-session test needs that same contract to be observable, so it lands with it. Both limitations are called out in the same comment block so they get fixed together.

CI is green on the head with the fix.

anandh8x
anandh8x previously approved these changes Jul 17, 2026

@anandh8x anandh8x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the latest head (96ac868). PR7's required seam is implemented cleanly: every run routes provider I/O through a TurnSession without provider-specific loop branching; the default adapter preserves current behavior; lifecycle failures, prewarm/close behavior, capability projection, and model switching are covered by focused tests. The effective reasoning-effort projection fix is correct.\n\nValidated locally: git diff --check; go test ./internal/providers ./internal/zeroruntime ./internal/agent; and the broader agent/CLI/TUI suites on the preceding code commit. No blocking findings.\n\nNon-blocking PR8 follow-up: when an optimized session exists, extend the ModelSwitcher contract/session resolver so escalation preserves optimized session semantics instead of falling back to the default adapter, with lifecycle coverage for the switched session.

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

gnanam1990
gnanam1990 previously approved these changes Jul 18, 2026

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the latest head (96ac868). The provider turn-session seam routes run I/O through the session while the default adapter preserves existing behavior. The reasoning-effort capability projection now uses Registry.ReasoningEfforts and includes coverage for inferred effective tiers. Focused lifecycle/provider validation and all CI checks pass. No blocking findings.\n\nNon-blocking PR8 follow-up: preserve optimized TurnSessionProvider semantics across ModelSwitcher escalation instead of falling back to the default adapter, with lifecycle coverage for the switched session.

@Vasanthdev2004
Vasanthdev2004 dismissed stale reviews from gnanam1990 and anandh8x via 968cd1e July 18, 2026 03:28
@Vasanthdev2004

Copy link
Copy Markdown
Collaborator Author

Took the second suggestion after all — 968cd1ee implements the target-aware session resolver instead of deferring it:

  • New optional Options.ModelSessionSwitcher func(ctx, modelID) (zeroruntime.TurnSessionProvider, error) — the loop prefers it over ModelSwitcher, so an optimized session (and its capabilities) survives a mid-run model switch. ModelSwitcher remains as the unchanged fallback (bare Provider wrapped in the default no-op session), same non-fatal error contract, so every existing caller and test is untouched.
  • The requested test is in: TestRunModelSessionSwitcherCarriesOptimizedSession uses a distinct switched session and asserts it receives the post-switch streams, is prewarmed exactly once, and is closed exactly once at teardown — plus that the legacy switcher is never consulted when both are set. TestRunModelSessionSwitcherErrorIsNonFatal covers the error path (run continues on the current session with a transcript note).
  • The known-limitation comment now covers only what genuinely remains deferred: the compactor's context-window budget across a switch, which needs the switcher to also report the new window.

The full escalation suite passes unchanged, so the fallback path is behavior-identical. CI running on the new head.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/agent/turn_session_test.go (1)

283-321: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Cover failure while opening the switched session.

This tests a ModelSessionSwitcher callback error, but not the distinct branch where it returns a provider whose OpenTurnSession fails. Add coverage verifying the original session remains active and unclosed until teardown, and that the failure note reaches the next request.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/agent/turn_session_test.go` around lines 283 - 321, Add a test
alongside TestRunModelSessionSwitcherErrorIsNonFatal that makes
ModelSessionSwitcher return a provider whose OpenTurnSession fails. Verify Run
remains non-fatal, continues using the original session for the recovery turn,
closes that session only during teardown, and includes the switch-failure note
in the next request.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/agent/turn_session_test.go`:
- Around line 283-321: Add a test alongside
TestRunModelSessionSwitcherErrorIsNonFatal that makes ModelSessionSwitcher
return a provider whose OpenTurnSession fails. Verify Run remains non-fatal,
continues using the original session for the recovery turn, closes that session
only during teardown, and includes the switch-failure note in the next request.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e438824a-68af-4878-8cb4-f4c5e2c0e217

📥 Commits

Reviewing files that changed from the base of the PR and between 96ac868 and 968cd1e.

📒 Files selected for processing (3)
  • internal/agent/loop.go
  • internal/agent/turn_session_test.go
  • internal/agent/types.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/agent/loop.go

@Vasanthdev2004

Copy link
Copy Markdown
Collaborator Author

@coderabbitai approve

@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
✅ Action performed

Comments resolved and changes approved.

@gnanam1990 gnanam1990 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed at 39d0136. No blocking findings. The optimized turn-session handoff and swap-time open-failure handling are sound, with focused regression coverage. Local race tests, vet, build, formatting, and static lint passed; all GitHub checks are green.

@anandh8x anandh8x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed only the commits added since the dismissed approval, through head 39d0136. The new ModelSessionSwitcher preserves optimized turn-session semantics across escalation, and the added error/open-failure paths correctly retain and eventually close the original session. Focused race tests and vet pass for internal/agent, internal/providers, and internal/zeroruntime. No blocking findings.

@Vasanthdev2004
Vasanthdev2004 merged commit 30e2c3f into main Jul 18, 2026
9 checks passed
@Vasanthdev2004
Vasanthdev2004 deleted the perf/provider-turn-session branch July 18, 2026 04:03
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.

3 participants