Skip to content

feat(opencode): add plan mode, reasoning effort, and status telemetry#688

Open
swear01 wants to merge 3 commits into
tiann:mainfrom
swear01:feat/opencode-plan-mode
Open

feat(opencode): add plan mode, reasoning effort, and status telemetry#688
swear01 wants to merge 3 commits into
tiann:mainfrom
swear01:feat/opencode-plan-mode

Conversation

@swear01
Copy link
Copy Markdown

@swear01 swear01 commented May 25, 2026

Summary

  • add real OpenCode plan mode support so the existing web option affects runtime behavior
  • wire OpenCode reasoning effort through the CLI, hub, and web flow so it can be shown and changed from the settings panel
  • bridge OpenCode ACP usage into the existing token-count pipeline so the web status bar can show ctx and cache

Test plan

  • bun run test -- src/agent/messageConverter.test.ts src/agent/backends/acp/AcpSdkBackend.test.ts in cli
  • bun run typecheck in cli
  • bun run test -- src/chat/normalize.test.ts in web
  • bun run typecheck in web
  • Manual verification in an isolated hub + runner environment for OpenCode session controls and status telemetry

Issues

Notes

  • Also includes OpenCode web status telemetry (ctx / cache) so ACP usage data is visible in the existing composer/status bar without introducing an agent-specific UI path.

Made with Cursor

swear01 and others added 3 commits May 25, 2026 10:55
Bridge OpenCode ACP usage updates into the existing token-count pipeline so the web status bar can show live context and cache information without a separate UI path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Findings

  • [Major] OpenCode plan mode is exposed to local sessions without local enforcement — adding plan to the shared OpenCode modes makes CLI/API paths accept it for local OpenCode sessions, but the enforcement added in this PR lives in the remote launcher/ACP permission handler. The local launcher only mirrors permission.* hook events, so local plan mode can still execute tools, defeating the mode's safety expectation. Evidence shared/src/modes.ts:29.
    Suggested fix:

    if (flavor === 'opencode' && mode === 'plan' && sessionResult.session.agentState?.controlledByUser === true) {
        return c.json({ error: 'OpenCode plan mode is only supported for remote sessions' }, 409)
    }
  • [Major] Failed OpenCode effort switches remain persisted — the config RPC stores the requested effort and reports it as applied before the remote launcher successfully calls session/set_config_option; if OpenCode rejects the value or method, the catch path only mutates the current batch and sends a message, leaving hub/session state on the rejected value and causing later turns to retry it. Evidence cli/src/opencode/runOpencode.ts:147.
    Suggested fix:

    const fallbackEffort = this.currentBackendEffort;
    batch.mode.modelReasoningEffort = fallbackEffort;
    session.setModelReasoningEffort(fallbackEffort);
    session.pushKeepAlive();
    this.onReasoningEffortRollback?.(fallbackEffort);

Questions

  • None.

Summary

  • Review mode: initial
  • Two issues found: remote-only plan enforcement is exposed to local OpenCode sessions, and failed OpenCode reasoning-effort switches can leave persisted state out of sync with the backend.

Testing

  • Not run (automation; static review only).

HAPI Bot

Comment thread shared/src/modes.ts
export type KimiPermissionMode = typeof KIMI_PERMISSION_MODES[number]

export const OPENCODE_PERMISSION_MODES = ['default', 'yolo'] as const
export const OPENCODE_PERMISSION_MODES = ['default', 'plan', 'yolo'] as const
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MAJOR] This exposes plan as an OpenCode mode for every path, including the default local hapi opencode --permission-mode plan flow and web permission-mode updates on controlled-by-user sessions. The PR only enforces plan in the remote launcher/ACP permission handler; opencodeLocalLauncher just mirrors permission.* hook events, so local plan mode can still run tools.

Suggested fix:

if (flavor === 'opencode' && mode === 'plan' && sessionResult.session.agentState?.controlledByUser === true) {
    return c.json({ error: 'OpenCode plan mode is only supported for remote sessions' }, 409)
}

Also reject terminal local startup unless --hapi-starting-mode remote:

if (options.permissionMode === 'plan' && options.startingMode !== 'remote') {
    throw new Error('OpenCode plan mode is only supported in remote mode')
}

if (config.model !== undefined) {
sessionModel = config.model;
}
if (config.modelReasoningEffort !== undefined) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[MAJOR] This records the requested effort as applied before the remote launcher has successfully called session/set_config_option. If OpenCode rejects the value or the method, the catch path only mutates the current batch and sends a message; the hub/session state still says the rejected effort is active, and future messages are queued with the same stale sessionModelReasoningEffort.

Suggested fix:

const fallbackEffort = this.currentBackendEffort;
batch.mode.modelReasoningEffort = fallbackEffort;
session.setModelReasoningEffort(fallbackEffort);
session.pushKeepAlive();
this.onReasoningEffortRollback?.(fallbackEffort);

Wire onReasoningEffortRollback to update sessionModelReasoningEffort before the next queued turn.

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.

OpenCode: model reasoning effort setting fails with 400 OpenCode: support plan mode

1 participant