Skip to content

feat(server): add Oh My Pi (omp) as an ACP provider - #9038

Closed
Neon-Wang wants to merge 10 commits into
pingdotgg:mainfrom
Neon-Wang:feat/omp-provider
Closed

feat(server): add Oh My Pi (omp) as an ACP provider#9038
Neon-Wang wants to merge 10 commits into
pingdotgg:mainfrom
Neon-Wang:feat/omp-provider

Conversation

@Neon-Wang

@Neon-Wang Neon-Wang commented Sep 1, 2026

Copy link
Copy Markdown

Summary

Adds Oh My Pi (omp) as a built-in provider, closing #8985. omp is a pi-mono fork with a native, well-maintained ACP server mode (omp acp, stdio), so this rides the existing generic ACP client stack (apps/server/src/provider/acp/) — no new transport.

One deviation from the issue's original sketch: it proposed copying the Grok driver, but live probing showed omp's session/new returns parameterized configOptions (mode/model/thinking selects, 137 models) with no models array — the Cursor shape. The driver therefore follows the Cursor stack (CursorDriver/CursorAdapter/CursorProvider/CursorAcpSupport), not Grok's.

What's in the change

contracts

  • "omp" ProviderDriverKind + display name; OmpSettings (enabled off by default — same conservative posture as Cursor/Grok/OpenCode), wired through providers struct, OmpSettingsPatch, ServerSettingsPatch, and the server-side opt-in restoration (restoreUsedProviders, persisted-defaults, provider-history SQL).

server

  • acp/OmpAcpSupport.ts — spawn omp acp with approval flags per RuntimeMode: Supervised → --approval-mode=always-ask (explicit, so a user-side tools.approvalMode: yolo in ~/.omp can't silently disable prompting), Auto-accept edits → --approval-mode=write, Auto → --auto-approve, Full access → --approval-mode=yolo. Auth is omp's advertised agent method (existing ~/.omp credentials); nothing is managed by T3.
  • Layers/OmpProvider.ts — status probe (omp --version) plus a fully dynamic model catalog: omp is a meta-provider over user-configured upstreams, so a short-lived ACP probe session flattens the model select into the snapshot. Nothing hardcoded. Borrowed from the OpenCode playbook: sub-provider grouping from provider/ id prefixes, alphabetical sort, upstream-count status message, zero-models → warning.
  • Layers/OmpAdapter.ts — session lifecycle on the generic ACP runtime, plus:
    • Model/option application: model config written first, then options re-read — omp re-validates dependent selects per model (e.g. thinking accepts only off/auto under the auto model), so validating against pre-switch options produced rejected writes.
    • Reasoning effort: omp's thought_level-category thinking select maps to T3's reasoning control; the CLI's own currentValue supplies the default.
    • Subagents in the Agents panel: omp dispatches sub-agents through its task tool, which ACP carries as ordinary tool calls. The adapter recognizes task-shaped rawInput (single {task, agent?, effort?} or batch {tasks: [...]}) and emits task.started/task.completed with TaskAgentLinkage (role/effort/title), so omp sub-agents land in the Agents panel with zero new UI. The plain tool row stays in the timeline (Claude parity).
    • Approval prompts: omp's approval wrapper prompts through ACP elicitations in anything short of yolo. Two wire quirks are contained here: omp (official ACP SDK) sends elicitation/create while effect-acp's generated binding still listens on the older session/elicitation name — handled via the unknown-ext-request fallback, responding in the flat {action: "accept", content} shape the official SDK expects; and elicitations are bridged into T3's existing user-input request UI (select/confirm/input → questions).
  • Drivers/OmpDriver.ts + Services/OmpAdapter.ts + textGeneration/OmpTextGeneration.ts; registered in builtInDrivers.ts. Maintenance is manual-only (no guessed update command).

web/mobile — provider card ("Early Access", mirrors Grok), picker entries, Pi-glyph icon (omp is a Pi fork; no omp asset exists), mobile ProviderIcon.

docsdocs/user/install.md provider table, docs/user/permission-modes.md mode→flag mapping, docs/internals/providers.md driver table.

Verification

  • New tests: 47 omp-specific (adapter/provider/acp-support), all green; Cursor + Grok suites re-run clean against the shared, additively-extended mock ACP agent; ProviderRegistry/serverSettings/contracts settings tests updated and green. Typecheck clean for contracts, server, web, mobile.
  • End-to-end on macOS against omp/18.0.6 (screenshots below): enable + version probe, 137-model dynamic catalog with 4 upstream providers, streaming turns, Supervised approval dialog (approve → command ran; deny → graceful refusal), turn cancel ("You stopped after 26s"), subagent in Agents panel ("DoneReporter", role sonic, Completed) alongside the "Ran 1 subagent" timeline row.
Provider enabled + version Dynamic catalog (137 models)
provider models
Supervised approval dialog Subagent in Agents panel
approval agents

Deliberately out of scope (follow-ups)

Model: kimi-code/k3 via Oh My Pi (omp)


Note

Medium Risk
Introduces a new built-in provider on the core ACP session/turn path with non-trivial lifecycle and wire-format quirks; risk is mitigated by broad integration tests but regressions could affect threading, approvals, or streaming for omp threads.

Overview
Adds Oh My Pi (omp) as a first-class provider so T3 can drive the omp acp CLI like other ACP-backed agents.

Server: New OmpDriver wires managed provider snapshots (version probe + dynamic model catalog from ACP configOptions), an OmpAdapter on the shared ACP runtime, and text generation. The adapter maps omp’s mode/model/thinking selects, plan interaction mode, in-session model switches, tool permissions (including snake_case option ids), elicitation/create user-input flows, and task tool calls into Agents panel task.started/task.completed events. It also handles turn steering, cancel-before-prompt, and fixes ACP notification consumption by forking the event consumer into the session scope (so streams survive after startSession returns).

Testing & mocks: acp-mock-agent gains omp-shaped modes/config, elicitation, task-tool, and delayed set_config_option fixtures; large adapter/provider integration suites exercise the above.

Product/docs: README install list and mobile ProviderIcon for omp.

Reviewed by Cursor Bugbot for commit 31a3785. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add Oh My Pi (omp) as an ACP provider across server, web, and contracts

  • Adds the full Oh My Pi provider stack: OmpDriver in the built-in registry, an ACP adapter in OmpAdapter.ts, a text-generation service in OmpTextGeneration.ts, and ACP support helpers in OmpAcpSupport.ts for spawn input, runtime construction, model selection, and permission-mode mapping.
  • Introduces OmpSettings and OmpSettingsPatch schemas in settings.ts with a disabled-by-default enabled flag, a configurable binary path, and hidden custom-model storage; server settings now persist and restore omp usage history.
  • Wires the web UI: the provider picker shows Oh My Pi with a new badge, the add-provider dialog removes the coming-soon Pi Agent entry, and provider settings metadata validates OmpSettings with an Early Access badge.
  • Model discovery runs omp --version then a scoped ACP probe within a 15-second timeout, building a sorted catalog from ACP configuration options with reasoning, context-window, and fast-mode capabilities.
  • Text-generation calls start a scoped unattended ACP session, apply model and thinking selections, enforce a 180-second timeout, and parse streamed agent text as schema-validated JSON for commit messages, PR content, branch names, and thread titles.
  • Updates the ACP mock agent to expose Oh My Pi-shaped configuration, modes, elicitation, and task-tool scenarios for integration tests.
  • Risk: BUILT_IN_DRIVERS now includes OmpDriver between GrokDriver and OpenCodeDriver; any code iterating or indexing this ordered list by position will shift. checkOmpProviderStatus spawns omp --version and an ACP probe process on enabled instances, which adds subprocess startup cost to provider status checks.

Macroscope summarized 31a3785.

Closes pingdotgg#8985

Adds omp (https://github.com/can1357/oh-my-pi) as a built-in provider on top
of the existing generic ACP client stack. omp's ACP sessions expose models
through parameterized configOptions (model/mode/thinking selects), so the
driver follows the Cursor provider stack rather than Grok's session-models
shape.

Highlights:
- contracts: "omp" ProviderDriverKind + OmpSettings (enabled off by default,
  like Cursor/Grok/OpenCode) wired through settings, patch, and server-side
  opt-in restoration
- acp/OmpAcpSupport: spawn omp acp with approval flags per RuntimeMode
  (always-ask / --approval-mode=write / --auto-approve / --approval-mode=yolo);
  Supervised passes always-ask explicitly so a user-side approvalMode: yolo
  in ~/.omp can't silently disable prompting
- OmpProvider: fully dynamic model catalog probed via a short-lived ACP
  session (omp is a meta-provider; nothing is hardcoded), with OpenCode-style
  sub-provider grouping derived from provider/model id prefixes; omp's
  thinking select maps to T3's reasoning effort control
- OmpAdapter: projects omp's task tool calls into Agents-panel lifecycle
  events (task.started/completed with TaskAgentLinkage), and bridges omp's
  elicitation-based approval prompts (omp sends elicitation/create, handled
  via the unknown-ext fallback since effect-acp's generated binding still
  uses the older session/elicitation method name) into T3's user-input UI
- web/mobile: provider registration, icons, and picker entries; docs updated

Verified end-to-end on macOS with omp/18.0.6: provider enable + version
probe, 137-model dynamic catalog, streaming turns, runtime-mode approval
dialog (approve and deny paths), turn cancel, and subagent display in the
Agents panel.

Model: kimi-code/k3 via Oh My Pi (omp)
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XXL 1,000+ changed lines (additions + deletions). labels Sep 1, 2026
Comment thread apps/server/src/provider/Layers/OmpAdapter.test.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
if (!modelOption) {
return [];
}
const capabilities = buildOmpCapabilitiesFromConfigOptions(configOptions);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/OmpProvider.ts:360

Every discovered model receives the capabilities of the probe session's current model, so models with different reasoning options advertise invalid choices or hide valid ones. After switching models, resolveOmpAcpConfigUpdates re-reads the model-specific options and drops unsupported selections, leaving omp's default effort instead. Discover capabilities per model, or avoid assigning the current model's capabilities to the entire catalog.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpProvider.ts around line 360:

Every discovered model receives the capabilities of the probe session's current model, so models with different reasoning options advertise invalid choices or hide valid ones. After switching models, `resolveOmpAcpConfigUpdates` re-reads the model-specific options and drops unsupported selections, leaving `omp`'s default effort instead. Discover capabilities per model, or avoid assigning the current model's capabilities to the entire catalog.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fair point, and it mirrors the Cursor driver this is modeled on: one ACP probe session reads the config options of the CLI current model, and the catalog shares them. Per-model discovery would mean an ACP session spawn per model (~137 spawns per status check), which is not viable. The runtime path is already safe against the mismatch: on model switch the adapter re-reads the post-switch options and drops selections the new model does not advertise (regression-tested), so a stale capability degrades to the CLI default rather than producing a rejected write. Per-model capabilities need a cheaper discovery channel on the omp side; noted as a follow-up in the PR body.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

Comment thread apps/server/src/provider/Layers/OmpProvider.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
Comment thread apps/web/src/components/settings/providerDriverMeta.ts
Comment thread apps/web/src/components/chat/providerIconUtils.ts
Comment thread apps/server/src/textGeneration/OmpTextGeneration.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
@macroscopeapp

macroscopeapp Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds a substantial subprocess-backed ACP provider with dynamic model discovery, approval handling, session lifecycle, subagent events, and text-generation workflows across server, contracts, web, and mobile. The breadth of new runtime behavior, unresolved lifecycle and model-catalog concerns, and product-default/static-analysis changes require human review.

Not approved because:

  • 6 blocking correctness issues found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

- sendTurn: bind activeTurnId synchronously with the in-flight increment so
  a concurrent sendTurn can no longer steer onto the previous turn
- accept omp's "auto" thinking level as a valid reasoning value (auto models
  advertise exactly {off, auto})
- gate subagent projection on an allowlist of omp task-tool input keys so
  unrelated tools carrying a task/tasks field are not misclassified
- text generation: spawn omp acp with --auto-approve; the unattended path
  registers no permission/elicitation handlers and must never wait on one
- web: theme-adaptive mono PiAgentIcon; drop the duplicate piAgent
  coming-soon tile now that omp is selectable

Model: kimi-code/k3 via Oh My Pi (omp)
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
Comment thread apps/server/src/textGeneration/OmpTextGeneration.ts
- sendTurn: emit turn.completed { state: "failed" } when a started turn
  fails mid-prepare or in acp.prompt (previously left without a terminal
  event), still rethrowing so the reactor's failure path stays intact
- interruptTurn now records the active turn id; sendTurn checks the
  cancellation set before turn.started and again before prompting, so a
  turn cancelled during session configuration is never sent to omp
- release per-thread semaphores on session stop/failed start instead of
  retaining them for the adapter lifetime
- text generation no longer advertises form elicitation, so an omp-side
  prompt fails fast with a clear error instead of hanging until timeout

Model: kimi-code/k3 via Oh My Pi (omp)
Comment thread apps/server/src/provider/Layers/OmpAdapter.test.ts
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
The shared ACP runtime dropped agent_thought_chunk notifications entirely.
omp emits them for its thinking stream, so map them to reasoning_text
content deltas and thread the stream kind through all three ACP adapters.

Model: kimi-code/k3 via Oh My Pi (omp)
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts Outdated
- interruptTurn honors its optional turnId: stale interrupts for completed
  turns no longer cancel the thread's active turn
- a cancelled steering turn with multiple in-flight prompts now keeps its
  cancellation marker until the last prompt drains, settling cancelled
  exactly once instead of letting a sibling prompt through
- revert the per-thread semaphore deletion from the previous round:
  deleting a lock while held or queued lets a later startSession run on a
  fresh lock concurrently with waiters on the old one — worse than the
  bounded retention it removed

Model: kimi-code/k3 via Oh My Pi (omp)
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts Outdated
Comment thread apps/server/src/provider/Layers/OmpAdapter.ts
- Interactive approval responses now resolve the optionId by matching the
  decision's ACP kind against the options the agent actually offered
  (omp advertises allow_once-style ids; the hardcoded hyphenated ids were
  rejected as unknown)
- the cancellation finalizer no longer publishes on stopped sessions,
  matching the failure path's guard

Model: kimi-code/k3 via Oh My Pi (omp)
@Neon-Wang

Copy link
Copy Markdown
Author

Hi @t3dotgg @juliusmarminge — gentle nudge on this one when you have a moment. 🙂

State of play: all bot checks are green (Macroscope ×3, Bugbot, CodeRabbit), every review thread has been addressed or answered, and the flow is verified end-to-end locally against omp/18.0.6 (provider enable, 137-model dynamic catalog, streaming, approval dialog in Supervised, cancel, and subagents landing in the Agents panel — screenshots in the description).

It's off-by-default like Cursor/Grok, so it can't affect anyone who doesn't opt in. Happy to rebase, split, or adjust anything that would make it easier to review — just say the word. Thanks!

@t3dotgg

t3dotgg commented Sep 4, 2026

Copy link
Copy Markdown
Member

Note

🤖 GPT-6 Astra (preview) responding on behalf of Theo

This note is part of an automated cleanup pass.

Carry the approval edge cases from #8583 at its head commit into this provider review: an always-allow decision must fall back to a usable allow-once option, blank option IDs must not force cancellation, and no usable option must be handled explicitly. A human comment on that PR also reports that OMP ACP advertises plan through availableModes and changes it through session/set_mode. Verify negotiated modes before describing Plan as unsupported. The separate Z.AI/Claude setup guide in the original PR is optional docs work, not part of the OMP protocol decision.

- drop the duplicate streamKind field the merge stacked in
  makeAcpContentDeltaEvent (upstream added the identical field)
- split stacked omp/antigravity object literals in providerDriverMeta and
  session-logic
- permission responses: match ACP kind against the options the agent
  advertised (allow_always falls back to allow_once, blank ids skipped,
  nothing usable settles cancelled) per the review guidance from pingdotgg#8583

Model: kimi-code/k3 via Oh My Pi (omp)
}
ctx.session = {
...ctx.session,
activeTurnId: turnId,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/OmpAdapter.ts:1351

Completed turns remain marked active: ctx.session.activeTurnId is set to turnId here and neither it nor ctx.activeTurnId is cleared when the prompt settles. As a result, listSessions() reports idle sessions as busy and a later targeted interruptTurn accepts the stale id and calls acp.cancel; clear both active-turn fields when the final prompt settles, including cancellation and failure paths.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpAdapter.ts around line 1351:

Completed turns remain marked active: `ctx.session.activeTurnId` is set to `turnId` here and neither it nor `ctx.activeTurnId` is cleared when the prompt settles. As a result, `listSessions()` reports idle sessions as busy and a later targeted `interruptTurn` accepts the stale id and calls `acp.cancel`; clear both active-turn fields when the final prompt settles, including cancellation and failure paths.

Effect.gen(function* () {
switch (event._tag) {
case "EventStreamBarrier":
yield* Deferred.succeed(event.acknowledge, undefined);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High Layers/OmpAdapter.ts:1073

When the ACP transport/process emits ConnectionTerminated, this switch ignores it, leaving ctx.stopped false and the dead context in sessions. hasSession() therefore continues to report a usable session, so later turns reuse the zombie instead of spawning a new ACP child, and no session.exited error event is emitted. Handle ConnectionTerminated by tearing down/removing the context and publishing the appropriate error exit event.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpAdapter.ts around line 1073:

When the ACP transport/process emits `ConnectionTerminated`, this switch ignores it, leaving `ctx.stopped` false and the dead context in `sessions`. `hasSession()` therefore continues to report a usable session, so later turns reuse the zombie instead of spawning a new ACP child, and no `session.exited` error event is emitted. Handle `ConnectionTerminated` by tearing down/removing the context and publishing the appropriate error exit event.

Comment thread apps/web/src/session-logic.ts
checkedAt,
ompSettings,
version,
discoveredModels: resolvedModels,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟠 High Layers/OmpProvider.ts:719

When ACP discovery returns an empty catalog, this passes [] as discoveredModels, but ProviderRegistry.mergeProviderModels retains the previous non-custom models for Oh My Pi. Removed models therefore remain selectable after refresh and are sent to omp even though they are no longer available. Ensure an empty successful discovery clears prior Oh My Pi models, or exclude Oh My Pi from the missing-model retention rule.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpProvider.ts around line 719:

When ACP discovery returns an empty catalog, this passes `[]` as `discoveredModels`, but `ProviderRegistry.mergeProviderModels` retains the previous non-custom models for Oh My Pi. Removed models therefore remain selectable after refresh and are sent to `omp` even though they are no longer available. Ensure an empty successful discovery clears prior Oh My Pi models, or exclude Oh My Pi from the missing-model retention rule.

@Neon-Wang

Copy link
Copy Markdown
Author

Carried the #8583 approval edge cases into the interactive permission path (31a3785):

  • always-allow fallback: acceptForSession now maps to the agent's allow_always option, falling back to its allow_once when allow_always isn't offered (omp's PERMISSION_OPTIONS always include both, but other ACP agents may not).
  • blank option ids: options with blank/whitespace ids are treated as unusable and skipped during kind matching.
  • no usable option: the request now settles as cancelled instead of answering with a hardcoded id the agent never advertised (the previous fallback). Pure-function unit tests cover all three edges (selectOmpPermissionOptionId), plus a wire-level test asserting the advertised ids are what actually goes back.

On plan mode: agreed — omp advertises plan through availableModes and honors session/set_mode. The adapter maps T3's plan interaction mode onto it (ACP_PLAN_MODE_ALIASES = ["plan"]) rather than claiming it unsupported.

Also rebased onto current main (Antigravity merge included); on the ThoughtDelta front I converged onto your implementation — the adapter now consumes the shared ThoughtDelta event instead of my earlier ContentDelta/streamKind variant.

}
continue;
}
if (typeof raw === "string" && raw.trim().length > 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/OmpAdapter.ts:460

Numeric elicitation answers are sent as strings, so entering 42 for a number or integer property produces { field: "42" } instead of a numeric JSON value and the ACP request cannot satisfy the schema. Convert string answers to numbers before populating content (and reject invalid or non-integer values for the corresponding property type).

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpAdapter.ts around line 460:

Numeric elicitation answers are sent as strings, so entering `42` for a `number` or `integer` property produces `{ field: "42" }` instead of a numeric JSON value and the ACP request cannot satisfy the schema. Convert string answers to numbers before populating `content` (and reject invalid or non-integer values for the corresponding property type).

params: OmpElicitationFormLike,
): ReadonlyArray<UserInputQuestion> {
const fallbackQuestion = params.message?.trim() || "Oh My Pi requests input.";
return Object.entries(params.requestedSchema?.properties ?? {}).map(([key, property]) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Medium Layers/OmpAdapter.ts:393

ompElicitationQuestionsFromForm emits a T3 question for every schema property, so optional omp fields are treated as mandatory by the web/mobile answer builders and the form cannot be accepted unless users fill them or cancel. Filter the emitted questions to the schema's required properties while still allowing omitted optional answers in the response.

🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/OmpAdapter.ts around line 393:

`ompElicitationQuestionsFromForm` emits a T3 question for every schema property, so optional omp fields are treated as mandatory by the web/mobile answer builders and the form cannot be accepted unless users fill them or cancel. Filter the emitted questions to the schema's `required` properties while still allowing omitted optional answers in the response.

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 31a3785. Configure here.

// sendTurn must already see this turn id or it would steer onto the
// previous one.
ctx.promptsInFlight += 1;
ctx.activeTurnId = turnId;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Concurrent sendTurn splits turn identity

Medium Severity

sendTurn decides whether this call is a steer from promptsInFlight, then yields to mint a turn id before incrementing that counter. Two overlapping first sends can both observe an idle session, allocate different turn ids, and each emit turn.started, so steering no longer merges onto one turn.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 31a3785. Configure here.

@juliusmarminge

Copy link
Copy Markdown
Member

Closing as part of the open-PR backlog sweep (wave 2).

Reason: Duplicate OMP provider rebuild after closed #8157/#8183/#8224/#8582; generic ACP path is #9060
Related: #9060

Reopen if this is still wanted and you’re willing to rebase onto current main.

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.

3 participants