Skip to content

feat: remove pi-embedded.ts stub barrel and clean up call sites (#76)#77

Merged
alexey-pelykh merged 1 commit intomainfrom
remove-pi-embedded-stubs
Feb 28, 2026
Merged

feat: remove pi-embedded.ts stub barrel and clean up call sites (#76)#77
alexey-pelykh merged 1 commit intomainfrom
remove-pi-embedded-stubs

Conversation

@alexey-pelykh
Copy link
Copy Markdown

Summary

  • Delete src/agents/pi-embedded.ts stub barrel (4 types, 9 no-op functions) left behind by PR feat: gut pi-embedded execution engine core (#74) #75
  • Replace all pi-embedded call sites across ~15 production files with literal return values
  • Deep-clean ~25 test files: rename mocks (piEmbeddedMockbridgeMock/agentMock), remove dead mock functions/getters/types, update assertions for gutted abort/wait behavior
  • Remove embeddedRunMock infrastructure from gateway test helpers
  • Convert llm-task extension to dependency injection for agent runner
  • Remove dead shouldSteer/isStreaming variables and coverage exclusion for deleted file

Closes #76

Test plan

  • pnpm tsgo — typecheck clean (only pre-existing errors in agent.test.ts and audit-extra.sync.ts)
  • pnpm test — all 1372 test files pass (146 extensions + 1133 unit + 93 gateway), 0 failures
  • Grep for remaining pi-embedded functional references — all remaining are comments/historical context only

🤖 Generated with Claude Code

Delete the pi-embedded stub barrel (4 types, 9 no-op functions) and
clean up all consumer call sites across production code and tests.

Production changes:
- Replace pi-embedded calls with literals (resolveEmbeddedSessionLane → "default",
  getActiveEmbeddedRunCount → 0, isEmbeddedPiRunActive → false, etc.)
- Remove abort/wait/queue blocks from abort, subagent-announce, get-reply-run,
  commands-compact, commands-session, action-kill, action-send, agent-runner
- Remove abort/wait logic from gateway session cleanup (sessions.reset/delete
  always succeed now)
- Remove dead shouldSteer/isStreaming variables left by literal replacements

Test changes:
- Rename piEmbeddedMock → bridgeMock/agentMock, runEmbeddedPiAgent → runAgent,
  makeEmbeddedTextResult → makeAgentTextResult across ~25 test files
- Remove dead mock functions (abortEmbeddedPiRun, queueEmbeddedPiMessage,
  waitForEmbeddedPiRunEnd, compactEmbeddedPiSession) from hoisted mocks
- Remove dead getter exports and legacy type aliases
- Remove embeddedRunMock infrastructure from gateway test helpers
- Update abort and gateway session tests for gutted abort/wait behavior
- Convert llm-task extension tests to dependency injection

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@alexey-pelykh alexey-pelykh enabled auto-merge (squash) February 28, 2026 04:30
@alexey-pelykh alexey-pelykh merged commit b27cecc into main Feb 28, 2026
2 checks passed
@alexey-pelykh alexey-pelykh deleted the remove-pi-embedded-stubs branch February 28, 2026 04:40
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…inate CLI subprocesses (#2344)

The subagent `kill` and `steer` actions (exposed via the `subagents`
agent tool and `/subagents kill` / `/subagents steer` chat commands)
lost their subprocess-termination semantics during the pi-embedded gut
(`b27cecc795`, #76/#77). Kill marked the registry entry as terminated
and cleared queues but the CLI subprocess kept running until natural
completion; steer queued a replacement run but left the existing run
to finish first (via `agent.wait` settlement) instead of interrupting
it.

Fix: call `killSessionRun` from `src/agents/session-run-registry.ts`
before the queue-clear / settlement logic at all four affected call
sites. The registry is already populated by `ChannelBridge` (register
at `channel-bridge.ts:160` in a `try`, unregister at `:349` in a
`finally`), and `killSessionRun` dispatches either
`abortController.abort()` or `process.kill(pid, "SIGTERM")`. It is
idempotent (returns `false` on unknown/already-aborted keys — safe
no-op) and cannot throw (internal `try/catch` around `process.kill`).

Changes:
- `src/agents/tools/subagents-tool.ts`:
  - Import `killSessionRun` from `../session-run-registry.js`.
  - `killSubagentRun` (kill path): replace `const aborted = false;`
    dead var with `const aborted = killSessionRun(childSessionKey);`.
    The outer `killed` aggregate (`marked > 0 || aborted || cleared...`)
    now correctly reflects when a kill signal was dispatched. Previously
    `aborted` was a no-op disjunct; this only ADDS truthy cases, so no
    previously-true scenario regresses.
  - Steer path (line ~624): insert
    `killSessionRun(resolved.entry.childSessionKey);` between the
    `sessionId` resolution and `clearSessionQueues`, so the existing
    run is aborted before the `agent.wait` settle-timeout polls. The
    existing `agent.wait` stays as a 5-second settlement window.
  - `cascadeKillChildren` propagates automatically — it delegates to
    `killSubagentRun`.
- `src/auto-reply/reply/commands-subagents/action-kill.ts`: import +
  `killSessionRun(childKey);` inserted between `loadSubagentSessionEntry`
  and `clearSessionQueues`.
- `src/auto-reply/reply/commands-subagents/action-send.ts`: import +
  `killSessionRun(targetResolution.entry.childSessionKey);` in the
  `steerRequested` branch between `markSubagentRunForSteerRestart` and
  `clearSessionQueues`.

Key-type correctness: `childSessionKey` (from `SubagentRunRecord`) is
the canonical ChannelBridge sessionKey that the registry keys on.
`entry.sessionId` (Pi-era UUID) is NOT used for registry lookups —
preserved for `clearSessionQueues` and `loadSubagentSessionEntry` only.

Out of scope (separate issues per #2344 body):
- `abort.ts::stopSubagentsForRequester` carries the same
  `const aborted = false;` dead-var pattern — tracked under the `/abort`
  user command + gateway `sessions.reset` sub-issue.
- Auto-reply queue mode and `abortEmbeddedPiRun` test-mock cleanup —
  separate sub-issues.
- `pi-embedded.ts` stub barrel deletion — tracked under #2089 cascade
  sweep.

Verification:
- `pnpm check` (format + tsgo + lint + project-specific lints) → exit 0
- `pnpm test` (full parallel suite) → **800 files / 7010 passed /
  3 skipped** — no regression
- Rescan: `git grep "killSessionRun"` returns registry definition +
  registry tests + the 3 files in this PR; no stale/unwired references
- Rescan: `git grep "abortEmbeddedPiRun"` returns only test-mock
  contexts (`reply.block-streaming.test.ts`, `reply/abort.test.ts`) —
  production paths have no stray references
- Adversarial validation (fresh-context subclaude): CLEAN verdict on
  6 AC + 11 adversarial checks — confirms `killSessionRun` is LIVE
  (abortController/SIGTERM), key-type match correct, no double-kill in
  `action-kill.ts → stopSubagentsForRequester` path (latter targets
  grandchildren, not the killed session), order `mark → kill → clear →
  wait` is race-free (all sync within a tick)

Closes #2344

Refs: #2089

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…inate CLI subprocesses (#2344) (#2461)

The subagent `kill` and `steer` actions (exposed via the `subagents`
agent tool and `/subagents kill` / `/subagents steer` chat commands)
lost their subprocess-termination semantics during the pi-embedded gut
(`b27cecc795`, #76/#77). Kill marked the registry entry as terminated
and cleared queues but the CLI subprocess kept running until natural
completion; steer queued a replacement run but left the existing run
to finish first (via `agent.wait` settlement) instead of interrupting
it.

Fix: call `killSessionRun` from `src/agents/session-run-registry.ts`
before the queue-clear / settlement logic at all four affected call
sites. The registry is already populated by `ChannelBridge` (register
at `channel-bridge.ts:160` in a `try`, unregister at `:349` in a
`finally`), and `killSessionRun` dispatches either
`abortController.abort()` or `process.kill(pid, "SIGTERM")`. It is
idempotent (returns `false` on unknown/already-aborted keys — safe
no-op) and cannot throw (internal `try/catch` around `process.kill`).

Changes:
- `src/agents/tools/subagents-tool.ts`:
  - Import `killSessionRun` from `../session-run-registry.js`.
  - `killSubagentRun` (kill path): replace `const aborted = false;`
    dead var with `const aborted = killSessionRun(childSessionKey);`.
    The outer `killed` aggregate (`marked > 0 || aborted || cleared...`)
    now correctly reflects when a kill signal was dispatched. Previously
    `aborted` was a no-op disjunct; this only ADDS truthy cases, so no
    previously-true scenario regresses.
  - Steer path (line ~624): insert
    `killSessionRun(resolved.entry.childSessionKey);` between the
    `sessionId` resolution and `clearSessionQueues`, so the existing
    run is aborted before the `agent.wait` settle-timeout polls. The
    existing `agent.wait` stays as a 5-second settlement window.
  - `cascadeKillChildren` propagates automatically — it delegates to
    `killSubagentRun`.
- `src/auto-reply/reply/commands-subagents/action-kill.ts`: import +
  `killSessionRun(childKey);` inserted between `loadSubagentSessionEntry`
  and `clearSessionQueues`.
- `src/auto-reply/reply/commands-subagents/action-send.ts`: import +
  `killSessionRun(targetResolution.entry.childSessionKey);` in the
  `steerRequested` branch between `markSubagentRunForSteerRestart` and
  `clearSessionQueues`.

Key-type correctness: `childSessionKey` (from `SubagentRunRecord`) is
the canonical ChannelBridge sessionKey that the registry keys on.
`entry.sessionId` (Pi-era UUID) is NOT used for registry lookups —
preserved for `clearSessionQueues` and `loadSubagentSessionEntry` only.

Out of scope (separate issues per #2344 body):
- `abort.ts::stopSubagentsForRequester` carries the same
  `const aborted = false;` dead-var pattern — tracked under the `/abort`
  user command + gateway `sessions.reset` sub-issue.
- Auto-reply queue mode and `abortEmbeddedPiRun` test-mock cleanup —
  separate sub-issues.
- `pi-embedded.ts` stub barrel deletion — tracked under #2089 cascade
  sweep.

Verification:
- `pnpm check` (format + tsgo + lint + project-specific lints) → exit 0
- `pnpm test` (full parallel suite) → **800 files / 7010 passed /
  3 skipped** — no regression
- Rescan: `git grep "killSessionRun"` returns registry definition +
  registry tests + the 3 files in this PR; no stale/unwired references
- Rescan: `git grep "abortEmbeddedPiRun"` returns only test-mock
  contexts (`reply.block-streaming.test.ts`, `reply/abort.test.ts`) —
  production paths have no stray references
- Adversarial validation (fresh-context subclaude): CLEAN verdict on
  6 AC + 11 adversarial checks — confirms `killSessionRun` is LIVE
  (abortController/SIGTERM), key-type match correct, no double-kill in
  `action-kill.ts → stopSubagentsForRequester` path (latter targets
  grandchildren, not the killed session), order `mark → kill → clear →
  wait` is race-free (all sync within a tick)

Closes #2344

Refs: #2089

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…ctually terminate CLI subprocesses (#2343)

Replace three dead `const aborted = false` / `const ended = true`
placeholders left behind by the Pi-embedded gut (`b27cecc795`, #76/#77)
with real calls to `killSessionRun` / `waitForSessionRunEnd` from
`src/agents/session-run-registry.ts`:

- `abort.ts::stopSubagentsForRequester` inner loop — `killSessionRun(childKey)`
  now flows into the `killed` aggregate, so the loop actually counts
  subagent runs whose subprocesses were signaled.
- `abort.ts::tryFastAbortFromMessage` — `killSessionRun(resolvedTargetKey)`
  returned in the `aborted` field (previously always `false`). User-facing
  `/abort` now terminates the running CLI subprocess for non-ACP sessions;
  ACP cancellation path remains separate.
- `sessions.ts::ensureSessionRuntimeCleanup` — replaces the `const ended = true`
  placeholder with `killSessionRun(canonicalKey)` + `waitForSessionRunEnd`
  (15s timeout). Returns `UNAVAILABLE` on timeout, restoring the pre-gut
  contract that `sessions.reset` / `sessions.delete` surface the error
  when a subprocess refuses to end.

Also removes the `if (!params.sessionId) return undefined;` early-exit
in `ensureSessionRuntimeCleanup`: `sessionId` is used only to extend the
queue-key set; termination operates on `canonicalKey`, which is always
present. Callers with no `sessionId` now correctly attempt termination
(`waitForSessionRunEnd` short-circuits to `true` when no run is
registered, so the wait has no cost when there's nothing to wait for).

Polish: extracted `15_000` to `SESSION_RUN_TERMINATION_TIMEOUT_MS`,
grouped with the sibling `ACP_RUNTIME_CLEANUP_TIMEOUT_MS` constant.

Issue body lists three regression sites; only two apply. The third
(`commands-session.ts::applyAbortTarget`) does not exist in the current
tree — `git grep applyAbortTarget` returns zero hits. The `/session
abort` pathway was consolidated into `tryFastAbortFromMessage` at some
earlier point, so no duplicate wiring is needed. AC3 marked N/A.

Verification:
- `pnpm check` → exit 0
- `pnpm test` (full parallel suite) → 800 files / 7010 passed /
  3 skipped — no regression
- Rescan: `git grep "const aborted = false"` → zero hits across the
  whole tree (combined sweep of #2344 subagent kill/steer + #2343
  abort/subagent-cascade/fastAbort)
- Rescan: `git grep "abortEmbeddedPiRun"` → only test-mock contexts;
  production has no remaining references (test-mock cleanup tracked
  under #2089 sweep)
- Adversarial validation (fresh-context subclaude): CLEAN on 7 AC +
  9 adversarial checks — confirms waitForSessionRunEnd is LIVE (50ms
  poll tick, max 15s wall-clock), `ensureSessionRuntimeCleanup` callers
  always pass a valid `canonicalKey`, and no test asserts `aborted ===
  false` on the fast-abort path

Closes #2343

Refs: #2089, #2344, #2460, #2461

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…ctually terminate CLI subprocesses (#2343) (#2462)

Replace three dead `const aborted = false` / `const ended = true`
placeholders left behind by the Pi-embedded gut (`b27cecc795`, #76/#77)
with real calls to `killSessionRun` / `waitForSessionRunEnd` from
`src/agents/session-run-registry.ts`:

- `abort.ts::stopSubagentsForRequester` inner loop — `killSessionRun(childKey)`
  now flows into the `killed` aggregate, so the loop actually counts
  subagent runs whose subprocesses were signaled.
- `abort.ts::tryFastAbortFromMessage` — `killSessionRun(resolvedTargetKey)`
  returned in the `aborted` field (previously always `false`). User-facing
  `/abort` now terminates the running CLI subprocess for non-ACP sessions;
  ACP cancellation path remains separate.
- `sessions.ts::ensureSessionRuntimeCleanup` — replaces the `const ended = true`
  placeholder with `killSessionRun(canonicalKey)` + `waitForSessionRunEnd`
  (15s timeout). Returns `UNAVAILABLE` on timeout, restoring the pre-gut
  contract that `sessions.reset` / `sessions.delete` surface the error
  when a subprocess refuses to end.

Also removes the `if (!params.sessionId) return undefined;` early-exit
in `ensureSessionRuntimeCleanup`: `sessionId` is used only to extend the
queue-key set; termination operates on `canonicalKey`, which is always
present. Callers with no `sessionId` now correctly attempt termination
(`waitForSessionRunEnd` short-circuits to `true` when no run is
registered, so the wait has no cost when there's nothing to wait for).

Polish: extracted `15_000` to `SESSION_RUN_TERMINATION_TIMEOUT_MS`,
grouped with the sibling `ACP_RUNTIME_CLEANUP_TIMEOUT_MS` constant.

Issue body lists three regression sites; only two apply. The third
(`commands-session.ts::applyAbortTarget`) does not exist in the current
tree — `git grep applyAbortTarget` returns zero hits. The `/session
abort` pathway was consolidated into `tryFastAbortFromMessage` at some
earlier point, so no duplicate wiring is needed. AC3 marked N/A.

Verification:
- `pnpm check` → exit 0
- `pnpm test` (full parallel suite) → 800 files / 7010 passed /
  3 skipped — no regression
- Rescan: `git grep "const aborted = false"` → zero hits across the
  whole tree (combined sweep of #2344 subagent kill/steer + #2343
  abort/subagent-cascade/fastAbort)
- Rescan: `git grep "abortEmbeddedPiRun"` → only test-mock contexts;
  production has no remaining references (test-mock cleanup tracked
  under #2089 sweep)
- Adversarial validation (fresh-context subclaude): CLEAN on 7 AC +
  9 adversarial checks — confirms waitForSessionRunEnd is LIVE (50ms
  poll tick, max 15s wall-clock), `ensureSessionRuntimeCleanup` callers
  always pass a valid `canonicalKey`, and no test asserts `aborted ===
  false` on the fast-abort path

Closes #2343

Refs: #2089, #2344, #2460, #2461

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…as 1+2+4 of #2336

Partial execution of #2336's full sweep. Covers Areas 1 (`/think` directive
removal), 2 (`thinking.ts` helper deletion), and 4 (`thinkLevel` passthrough
plumbing) plus an adjacent cleanup of `onModelSelected` callback and its
`ModelSelectedContext` type. Areas 3, 5, 6, 7, 8 remain for follow-ups (see
the end of this commit message).

**Rationale**: thinking level and model selection are CLI-runtime concerns
per the Middleware Boundary Principle — CLI runtimes (Claude, Gemini, Codex,
OpenCode) own those decisions. Anything in the fork that resolves, gates,
or stores thinking level / selected model is vestigial from upstream
OpenClaw and was already no-op'd after PR #2335. `AgentRuntime.execute`
(src/middleware/types.ts) accepts none of these fields — confirmed.

## Area 1: `/think` directive end-to-end removal

- `src/auto-reply/reply/directive-handling.parse.ts`: removed
  `hasThinkDirective` and `thinkLevel` fields from `InlineDirectives`.
- `src/tui/tui-command-handlers.ts`: deleted the `/think` command handler;
  removed `formatThinkingLevels` import; removed `opts.thinking` passthrough
  from `sendChat`.
- `src/gateway/server-methods/chat.ts`: deleted the `injectThinking`-based
  `/think ${p.thinking} ${parsedMessage}` body rewrite and the `p.thinking`
  param.
- `src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts`:
  deleted the `thinkCases` block that asserted `/think:high` stripping
  (behavior replaced by no-op since directive parser is gone).
- `src/cli/tui-cli.ts`: removed `--thinking <level>` CLI option.
- `src/tui/gateway-chat.ts`, `src/tui/tui-types.ts`: removed `thinking`
  option / `ChatSendOptions.thinking` field.

## Area 2: `thinking.ts` helper deletion

- `src/auto-reply/thinking.ts`: deleted `normalizeThinkLevel`,
  `supportsXHighThinking`, `formatXHighModelHint`, `listThinkingLevelLabels`,
  `formatThinkingLevels`, `resolveThinkingDefaultForModel`,
  `isBinaryThinkingProvider`, `XHIGH_MODEL_*` constants, `CLAUDE_46_MODEL_RE`,
  `ThinkingCatalogEntry` and `ThinkLevel` types. Kept and simplified
  `listThinkingLevels` (returns the static level list). Kept
  `normalizeVerboseLevel`, `normalizeNoticeLevel`, `normalizeUsageDisplay`,
  `normalizeElevatedLevel`, `resolveElevatedMode`, `normalizeReasoningLevel`,
  `normalizeFastMode` — these are RemoteClaw's own directive-normalization
  helpers (not thinking-specific) and are load-bearing for display/security
  layers.
- `src/commands/agent/session.ts`: removed `normalizeThinkLevel` import,
  `persistedThinking` field, and its `ThinkLevel`-typed call on
  `sessionEntry.thinkingLevel`.

## Area 4: `thinkLevel` dead passthrough + adjacent cleanup

- `src/auto-reply/reply/queue/types.ts`: removed `thinkLevel?: unknown`
  from `FollowupRun.run`.
- `src/auto-reply/reply/agent-runner-utils.ts`: dropped `thinkLevel`
  from `buildEmbeddedRunBaseParams`' returned object (function itself
  is dead Pi-embedded plumbing — tracked for follow-up).
- `src/auto-reply/reply/agent-runner-execution.ts`: deleted the
  `onModelSelected({provider, model, thinkLevel: undefined})` callback
  call and the now-unused `const model = params.followupRun.run.model`
  declaration.
- `src/auto-reply/reply/get-reply-run.ts`: removed `resolvedThinkLevel`
  field from `RunPreparedReplyParams` and the `thinkLevel:
  resolvedThinkLevel` assignment in the `followupRun.run` builder.
- `src/auto-reply/reply/get-reply.ts`, `get-reply-inline-actions.ts`,
  `get-reply-directives.ts`, `commands-types.ts`: dropped
  `resolvedThinkLevel` fields + passthrough destructures.
- `src/auto-reply/types.ts`: deleted the whole `ModelSelectedContext`
  type and `GetReplyOptions.onModelSelected` callback (these echoed
  configured-value `provider`/`model`/`thinkLevel` — not actual
  CLI-reported selection; meaningful only when the Pi-embedded runtime
  owned dynamic fallback, which was gutted in #76/#77).
- `src/channels/reply-prefix.ts`: replaced the mutation-based
  `onModelSelected` callback with a static read from
  `resolveAgentEffectiveModelPrimary(cfg, agentId)` at context-creation
  time. Response-prefix template interpolation (`{model}`,
  `{provider}`, `{modelFull}`) still works with configured values.
  `ResponsePrefixContext.thinkingLevel` dropped.
- Removed `{ onModelSelected, ...rest } = createReplyPrefixOptions(...)`
  destructures and `onModelSelected` property spreads across ~16
  channel integrations: bluebubbles, feishu, googlechat, matrix,
  mattermost (monitor + slash-http), msteams, twitch, zalo, zalouser,
  discord (agent-components + message-handler + native-command),
  gateway/chat, imessage, line, plugin-sdk/inbound-reply-dispatch,
  signal, slack (monitor/dispatch + slash), telegram (bot-message +
  native-commands), tui (command-handlers + gateway-chat), web
  (auto-reply/process-message). Plus 3 test fixtures
  (`get-reply-run.media-only.test.ts` — 2 stale think-hint tests
  deleted; `get-reply-inline-actions.skip-when-config-empty.test.ts`,
  `get-reply.reset-hooks-fallback.test.ts`; `agent-runner-utils.test.ts`
  — stale `toMatchObject` keys; `test-helpers.ts`, `agent-runner.*.test.ts`
  fixtures; `slack/monitor/slash.test-harness.ts` mock return value).

## Areas deferred to follow-up issues

- **Area 3** (`SessionEntry.thinkingLevel` field removal + gateway
  schema + session.ts `persistedThinking`): still live in the session
  store, surfaced by TUI / status / Telegram / ACP / gateway session
  APIs. Mechanical but touches wire-format / session migration.
- **Area 5** (directive handling model-state internals — `aliasIndex`,
  `allowedModelKeys`, `resetModelOverride`, `defaultProvider` /
  `defaultModel`, `initialModelLabel`, `formatModelSwitchEvent`): 4
  files, significant refactoring.
- **Area 6** (docs): `/think` references in slash-commands.md,
  context.md, tui.md, group-messages.md.
- **Area 7** (display-layer audit): Android, iOS, macOS, web UI
  display references to `thinkingLevel`. Per-file judgment required
  (pass-through display = KEEP, state driver = REMOVE). Issue #2336
  explicitly flagged: "Do NOT touch native apps without confirming".
- **Area 8** (test-layer hardening): delete the global `runPreparedReply`
  shield mock at `get-reply.test-mocks.ts:39-40`; add regression test
  exercising the real resolveReplyDirectives → runPreparedReply chain.

## Additional finding (filed as follow-up)

The `buildEmbeddedRunBaseParams` / `buildEmbeddedContextFromTemplate` /
`buildEmbeddedRunContexts` / `buildTemplateSenderContext` /
`resolveRunAuthProfile` / `resolveEnforceFinalTag` /
`resolveProviderScopedAuthProfile` / `resolveModelFallbackOptions` /
`buildThreadingToolContext` cluster in
`src/auto-reply/reply/agent-runner-utils.ts` has zero production
callers — dead Pi-embedded plumbing that threads verboseLevel /
reasoningLevel / elevatedLevel / bashElevated / execOverrides for
nothing. Tracked as a separate follow-up.

## Verification

- `pnpm check` (format + tsgo + oxlint + project-specific lints) → exit 0.
- `pnpm test` (full parallel suite) → **800 files / 7010 passed /
  3 skipped** — no regression.
- Rescan: `git grep "/think\|hasThinkDirective\|thinkLevel\|supportsXHighThinking\|normalizeThinkLevel\|formatXHighModelHint"`
  in `src/` / `extensions/` returns only: `thinkingLevel` (stored in
  session, Area 3 deferred), display-layer native-app references
  (Area 7 deferred), and docs mentions (Area 6 deferred) — all scoped
  to follow-ups.

Refs: #2336, #2334, #2335, #2089

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
alexey-pelykh added a commit that referenced this pull request Apr 22, 2026
…as 1+2+4 of #2336 (#2463)

Partial execution of #2336's full sweep. Covers Areas 1 (`/think` directive
removal), 2 (`thinking.ts` helper deletion), and 4 (`thinkLevel` passthrough
plumbing) plus an adjacent cleanup of `onModelSelected` callback and its
`ModelSelectedContext` type. Areas 3, 5, 6, 7, 8 remain for follow-ups (see
the end of this commit message).

**Rationale**: thinking level and model selection are CLI-runtime concerns
per the Middleware Boundary Principle — CLI runtimes (Claude, Gemini, Codex,
OpenCode) own those decisions. Anything in the fork that resolves, gates,
or stores thinking level / selected model is vestigial from upstream
OpenClaw and was already no-op'd after PR #2335. `AgentRuntime.execute`
(src/middleware/types.ts) accepts none of these fields — confirmed.

## Area 1: `/think` directive end-to-end removal

- `src/auto-reply/reply/directive-handling.parse.ts`: removed
  `hasThinkDirective` and `thinkLevel` fields from `InlineDirectives`.
- `src/tui/tui-command-handlers.ts`: deleted the `/think` command handler;
  removed `formatThinkingLevels` import; removed `opts.thinking` passthrough
  from `sendChat`.
- `src/gateway/server-methods/chat.ts`: deleted the `injectThinking`-based
  `/think ${p.thinking} ${parsedMessage}` body rewrite and the `p.thinking`
  param.
- `src/auto-reply/reply.triggers.trigger-handling.targets-active-session-native-stop.e2e.test.ts`:
  deleted the `thinkCases` block that asserted `/think:high` stripping
  (behavior replaced by no-op since directive parser is gone).
- `src/cli/tui-cli.ts`: removed `--thinking <level>` CLI option.
- `src/tui/gateway-chat.ts`, `src/tui/tui-types.ts`: removed `thinking`
  option / `ChatSendOptions.thinking` field.

## Area 2: `thinking.ts` helper deletion

- `src/auto-reply/thinking.ts`: deleted `normalizeThinkLevel`,
  `supportsXHighThinking`, `formatXHighModelHint`, `listThinkingLevelLabels`,
  `formatThinkingLevels`, `resolveThinkingDefaultForModel`,
  `isBinaryThinkingProvider`, `XHIGH_MODEL_*` constants, `CLAUDE_46_MODEL_RE`,
  `ThinkingCatalogEntry` and `ThinkLevel` types. Kept and simplified
  `listThinkingLevels` (returns the static level list). Kept
  `normalizeVerboseLevel`, `normalizeNoticeLevel`, `normalizeUsageDisplay`,
  `normalizeElevatedLevel`, `resolveElevatedMode`, `normalizeReasoningLevel`,
  `normalizeFastMode` — these are RemoteClaw's own directive-normalization
  helpers (not thinking-specific) and are load-bearing for display/security
  layers.
- `src/commands/agent/session.ts`: removed `normalizeThinkLevel` import,
  `persistedThinking` field, and its `ThinkLevel`-typed call on
  `sessionEntry.thinkingLevel`.

## Area 4: `thinkLevel` dead passthrough + adjacent cleanup

- `src/auto-reply/reply/queue/types.ts`: removed `thinkLevel?: unknown`
  from `FollowupRun.run`.
- `src/auto-reply/reply/agent-runner-utils.ts`: dropped `thinkLevel`
  from `buildEmbeddedRunBaseParams`' returned object (function itself
  is dead Pi-embedded plumbing — tracked for follow-up).
- `src/auto-reply/reply/agent-runner-execution.ts`: deleted the
  `onModelSelected({provider, model, thinkLevel: undefined})` callback
  call and the now-unused `const model = params.followupRun.run.model`
  declaration.
- `src/auto-reply/reply/get-reply-run.ts`: removed `resolvedThinkLevel`
  field from `RunPreparedReplyParams` and the `thinkLevel:
  resolvedThinkLevel` assignment in the `followupRun.run` builder.
- `src/auto-reply/reply/get-reply.ts`, `get-reply-inline-actions.ts`,
  `get-reply-directives.ts`, `commands-types.ts`: dropped
  `resolvedThinkLevel` fields + passthrough destructures.
- `src/auto-reply/types.ts`: deleted the whole `ModelSelectedContext`
  type and `GetReplyOptions.onModelSelected` callback (these echoed
  configured-value `provider`/`model`/`thinkLevel` — not actual
  CLI-reported selection; meaningful only when the Pi-embedded runtime
  owned dynamic fallback, which was gutted in #76/#77).
- `src/channels/reply-prefix.ts`: replaced the mutation-based
  `onModelSelected` callback with a static read from
  `resolveAgentEffectiveModelPrimary(cfg, agentId)` at context-creation
  time. Response-prefix template interpolation (`{model}`,
  `{provider}`, `{modelFull}`) still works with configured values.
  `ResponsePrefixContext.thinkingLevel` dropped.
- Removed `{ onModelSelected, ...rest } = createReplyPrefixOptions(...)`
  destructures and `onModelSelected` property spreads across ~16
  channel integrations: bluebubbles, feishu, googlechat, matrix,
  mattermost (monitor + slash-http), msteams, twitch, zalo, zalouser,
  discord (agent-components + message-handler + native-command),
  gateway/chat, imessage, line, plugin-sdk/inbound-reply-dispatch,
  signal, slack (monitor/dispatch + slash), telegram (bot-message +
  native-commands), tui (command-handlers + gateway-chat), web
  (auto-reply/process-message). Plus 3 test fixtures
  (`get-reply-run.media-only.test.ts` — 2 stale think-hint tests
  deleted; `get-reply-inline-actions.skip-when-config-empty.test.ts`,
  `get-reply.reset-hooks-fallback.test.ts`; `agent-runner-utils.test.ts`
  — stale `toMatchObject` keys; `test-helpers.ts`, `agent-runner.*.test.ts`
  fixtures; `slack/monitor/slash.test-harness.ts` mock return value).

## Areas deferred to follow-up issues

- **Area 3** (`SessionEntry.thinkingLevel` field removal + gateway
  schema + session.ts `persistedThinking`): still live in the session
  store, surfaced by TUI / status / Telegram / ACP / gateway session
  APIs. Mechanical but touches wire-format / session migration.
- **Area 5** (directive handling model-state internals — `aliasIndex`,
  `allowedModelKeys`, `resetModelOverride`, `defaultProvider` /
  `defaultModel`, `initialModelLabel`, `formatModelSwitchEvent`): 4
  files, significant refactoring.
- **Area 6** (docs): `/think` references in slash-commands.md,
  context.md, tui.md, group-messages.md.
- **Area 7** (display-layer audit): Android, iOS, macOS, web UI
  display references to `thinkingLevel`. Per-file judgment required
  (pass-through display = KEEP, state driver = REMOVE). Issue #2336
  explicitly flagged: "Do NOT touch native apps without confirming".
- **Area 8** (test-layer hardening): delete the global `runPreparedReply`
  shield mock at `get-reply.test-mocks.ts:39-40`; add regression test
  exercising the real resolveReplyDirectives → runPreparedReply chain.

## Additional finding (filed as follow-up)

The `buildEmbeddedRunBaseParams` / `buildEmbeddedContextFromTemplate` /
`buildEmbeddedRunContexts` / `buildTemplateSenderContext` /
`resolveRunAuthProfile` / `resolveEnforceFinalTag` /
`resolveProviderScopedAuthProfile` / `resolveModelFallbackOptions` /
`buildThreadingToolContext` cluster in
`src/auto-reply/reply/agent-runner-utils.ts` has zero production
callers — dead Pi-embedded plumbing that threads verboseLevel /
reasoningLevel / elevatedLevel / bashElevated / execOverrides for
nothing. Tracked as a separate follow-up.

## Verification

- `pnpm check` (format + tsgo + oxlint + project-specific lints) → exit 0.
- `pnpm test` (full parallel suite) → **800 files / 7010 passed /
  3 skipped** — no regression.
- Rescan: `git grep "/think\|hasThinkDirective\|thinkLevel\|supportsXHighThinking\|normalizeThinkLevel\|formatXHighModelHint"`
  in `src/` / `extensions/` returns only: `thinkingLevel` (stored in
  session, Area 3 deferred), display-layer native-app references
  (Area 7 deferred), and docs mentions (Area 6 deferred) — all scoped
  to follow-ups.

Refs: #2336, #2334, #2335, #2089

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

Remove pi-embedded.ts stub barrel and clean up no-op call sites

1 participant