feat(grok): Grok Build workflows, usage, rewind — supersedes #6383 - #7070
feat(grok): Grok Build workflows, usage, rewind — supersedes #6383#7070maslinedwin wants to merge 28 commits into
Conversation
Grok already advertised reasoning effort and rewind over ACP. T3 dropped the metadata and forced a new thread for model changes. Map the live effort menu into composer options, send session/set_model _meta.reasoningEffort, probe login, roll back turns through _x.ai/rewind, and emit thread token usage. Made with Grok 4.6.
exactOptionalPropertyTypes rejected passing string | undefined into the optional effort fields, which also leaked unknown into the adapter Effect error channel. Made with Grok 4.6.
Do not carry an old effort onto a new model. Count steered prompts when rewinding. Lock rollback against a replaced session. Keep one default effort in the composer menu. Made with Grok 4.6.
pingdotgg#6383 wired effort, rewind, and a thin usage parser. Grok Build already streams workflow_updated over x.ai/session_notification and bills through PromptUsage totals. T3 dropped both. Map workflow runs onto local_workflow / subagent tasks, fold child tokens into thread usage, and accept the official cached_read_tokens shape.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
ApprovabilityVerdict: Skipped Macroscope did not run approvability analysis for this PR. Macroscope could not determine whether this PR modifies its approvability configuration, so the PR was not approved automatically. A PR that may change the rules that govern approval is never approved automatically. Not approved because:
|
Claude stamps workflow members with parentAgentId, timelineBypass, and a stable slot id. Codex does the same for collab children and keeps child tokens on typedUsage. The first Grok ingest used agentId and overwrote the thread context window with the child token sum. Extract a pure mapper, complete first-seen terminal runs, skip unchanged member ticks, and ingest Grok's standalone subagent ACP updates on that same path.
|
Follow-up `1d45fdb2` after auditing this against how T3 actually integrates Claude and Codex. What T3 expects (and the first ingest got wrong)
What this commit does
58 Grok tests passing (workflow mapper, adapter, extension, support). |
Pass spawn-time effort before ACP discovery. Hide Reasoning on models that do not support it, and keep the fallback menu only when support is advertised without choices. Key workflow members by agent_id, clear stale maxTokens on model switch, and keep duration/tool-use on subagent finish.
…okens Rewind now stops the live ACP prompt first so a late session/prompt cannot re-append a discarded turn. Tool-only subagent ticks reuse the last known token count instead of publishing totalTokens: 0.
The Effect.ensuring path already kept the prompt result after sendTurn was interrupted. It now publishes thread.token-usage.updated the same way the happy path does.
…ssues Map the product slug grok-build onto a live ACP model before session/set_model (pingdotgg#6075). If Always allow has no allow_always option, fall back to allow_once instead of cancelling the turn (pingdotgg#6502). Skip ACP startup on provider probe when there is no XAI_API_KEY or ~/.grok/auth.json, so a background check cannot open a login browser (pingdotgg#5852, pingdotgg#4983). Bound high-churn tool_call_update payloads so a redrawing terminal does not flood ingestion (pingdotgg#6556).
There was a problem hiding this comment.
Reviewed the Grok ACP changes against the Effect service conventions. Three findings in apps/server/src/provider/Layers/GrokAdapter.ts; the new pure modules (GrokAcpWorkflow.ts, GrokAcpToolUpdates.ts, XAiAcpExtension.ts) and the new FileSystem/Path acquisition in GrokProvider.ts follow the conventions (namespace subpath imports, dependencies acquired from the environment, requirements surfaced in the signature).
Posted via Macroscope — Effect Service Conventions
…d rewind Drop the incomplete auth-file pre-check so GROK_HOME and provider-command credentials still reach ACP; keep CI/NO_BROWSER on the probe. Read the tool-update clock through Effect Clock, fingerprint more than content length, and bound aggregate tool payloads. Replay session notifications that arrive during acp.start, delete the permission-option wrapper, and keep rewind errors as cause rather than wire detail.
…ough aliases Cancelled Grok prompts can still appear in rewind points. Targeting from the end of that list kept an earlier turn on the provider while local history dropped it. Pick the first point after the prompts we are keeping so a ghost cancelled prompt is discarded with the rest. grok-build is a product slug. Effort menus are keyed by live ACP ids, so sendTurn treated the menu as empty and either dropped live-only efforts or sent spawnable levels the aliased model does not advertise. Resolve the slug onto the session model before reading the menu.
The usage page only knew Claude and Codex. Grok already writes PromptUsage on turn_completed in ~/.grok/sessions/**/updates.jsonl, including cache-read tokens and costUsdTicks. Parse those rows, add grok to the usage contract, and show Grok Build next to Claude and Codex. Incomplete bills stay token-only and never become $0.
Live Grok extras arrive on `_x.ai/session/update`, not only `x.ai/session_notification`. Auto-compact, hooks, recap, background shells, and complete PromptUsage costUsdTicks were dropped. Parse those updates onto the same compact, hook.*, metadata, local_bash, and token-usage events Claude already uses. Incomplete bills stay token-only.
The Grok composer hid Plan/Default even though ACP advertises architect and code modes, and sendTurn never called set_mode. Turn the toggle on and map Plan onto the advertised plan/architect mode and Default onto code/agent, the same way Cursor does. ACP plan entries already update the turn plan list.
Pause, resume, and stop still lived only in the Grok TUI, and T3 had no way to launch a named Rhai workflow without reimplementing the host. Surface `/workflow pause|resume|stop` plus `~/.grok/workflows` and project `.grok/workflows` scripts as Grok slash commands. Selecting one sends that text as a prompt. Project scripts override user scripts of the same name.
Grok emits `_x.ai/queue/changed` when prompts wait behind the current turn. T3 already kept the JSON-RPC path alive but dropped the payload. Map a length change onto session.state.changed and thread metadata so the existing session surface can show that work is queued, without a third queue UI.
There was a problem hiding this comment.
One finding: adding grok to PROVIDER_ORDER makes the hardcoded colSpan={5} in the Usage cost breakdown table's empty row short by one column. Details inline.
Posted via Macroscope — UI Consistency
| grok: { | ||
| label: "Grok Build", | ||
| color: "#8884d8", | ||
| mark: GrokIcon, | ||
| }, |
There was a problem hiding this comment.
Adding a third provider here widens every PROVIDER_ORDER-driven table, but the cost breakdown's empty row in UsagePage.tsx still hardcodes its span:
// apps/web/src/components/usage/UsagePage.tsx:393
<td colSpan={5} className="py-6 text-center text-muted-foreground">
No activity in this window.
</td>That header row is now Day + 3 providers + Total + Tokens = 6 columns, so the "No activity in this window." cell no longer spans the table and its centered text is offset by the leftover cell. Consider deriving the span from the order so it stays correct as providers are added:
- <td colSpan={5} className="py-6 text-center text-muted-foreground">
+ <td
+ colSpan={PROVIDER_ORDER.length + 3}
+ className="py-6 text-center text-muted-foreground"
+ >Posted via Macroscope — UI Consistency
| } | ||
|
|
||
| if (provider === "grok") { | ||
| if (!mightCarryUsage(line, provider)) continue; |
There was a problem hiding this comment.
🟡 Medium usage/usageTranscriptReader.ts:134
Camel-case Grok completion events are dropped before parsing, so transcripts with sessionUpdate: "turnCompleted" contribute no usage to the dashboard. parseGrokLine accepts both spellings, but mightCarryUsage only matches turn_completed; include turnCompleted in this prefilter.
| if (!mightCarryUsage(line, provider)) continue; | |
| if (!mightCarryUsage(line, provider) && !line.includes("turnCompleted")) continue; |
Also found in 1 other location(s)
apps/server/src/usage/UsageService.ts:134
The new Grok reader prefilters with
mightCarryUsagebefore callingparseGrokLine.parseGrokLineexplicitly accepts bothturn_completedandturnCompleted, butmightCarryUsageonly searches forturn_completed; therefore every camel-caseturnCompletedtranscript record is silently skipped and its usage is omitted from the dashboard.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/usage/usageTranscriptReader.ts around line 134:
Camel-case Grok completion events are dropped before parsing, so transcripts with `sessionUpdate: "turnCompleted"` contribute no usage to the dashboard. `parseGrokLine` accepts both spellings, but `mightCarryUsage` only matches `turn_completed`; include `turnCompleted` in this prefilter.
Also found in 1 other location(s):
- apps/server/src/usage/UsageService.ts:134 -- The new Grok reader prefilters with `mightCarryUsage` before calling `parseGrokLine`. `parseGrokLine` explicitly accepts both `turn_completed` and `turnCompleted`, but `mightCarryUsage` only searches for `turn_completed`; therefore every camel-case `turnCompleted` transcript record is silently skipped and its usage is omitted from the dashboard.
There was a problem hiding this comment.
Effect service conventions review of the Grok parity changes. Earlier findings (Date.now() in the tool-update gate, the redundant selectPermissionOptionId wrapper, unbounded rewind detail, and the string-matched auth-failure classifier) are resolved in this head. One new finding on ambient environment access in GrokProvider.ts.
Posted via Macroscope — Effect Service Conventions
Usage empty rows still spanned five columns after Grok joined the table. Transcript parsing dropped nested PromptUsage totals, camelCase turnCompleted lines, and later turns that shared a session id as the dedupe key. Failed Grok turns left lastCompleteCostUsd on the session. Queue updates before startSession were dropped. Auto-compact never left waiting. Rewind truncated local turns when Grok had no matching point. Workflow discovery read ambient HOME/cwd and whole oversized Rhai files. Derive the cost-table span from PROVIDER_ORDER, parse both usage shapes, consume cost on every terminal turn, buffer queue/changed until the session exists, emit running after compact, refuse rewind without a target, and discover workflows from injected home and project roots with a bounded read.
The health check scanned project .grok/workflows, but the pending snapshot did not. Composer /workflow was missing those scripts until ACP discovery finished. Pass the same injected project root into the initial snapshot.
Server typecheck failed because optional projectRoot, homeDir, and usage counts were passed as T | undefined into exact-optional bags. Allow undefined on those fields and stop comparing workflow events to a thread usage type they cannot have. The usage chart test still expected only Codex and Claude bands after Grok joined PROVIDER_ORDER. Include the zero Grok band.
|
@t3dotgg would love to have Grok more native. could you review this PR please. |
There was a problem hiding this comment.
One Effect-convention issue in the new Grok provider code: filesystem discovery for workflow slash commands is done with imperative sync node:fs behind a plain function, so the dependency never appears in the Effect environment of the provider-snapshot effects that call it. Details inline.
Posted via Macroscope — Effect Service Conventions
Macroscope flagged readGrokWorkflowSlashCommands as blocking node:fs behind a plain function, so snapshot effects never declared the filesystem they used. Scan ~/.grok/workflows and project scripts with FileSystem and Path, and thread that requirement through the initial snapshot and health check.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
There are 5 total unresolved issues (including 3 from previous reviews).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 899ffa2. Configure here.
Bugbot: a model-map miss wrote undefined into ctx.maxTokens and dropped the context ceiling. Rewind only trimmed turns, so usage, cost, queue, workflow, and tool gates stayed pre-undo. Compact complete always emitted session running, even with no live turn. Assign maxTokens only when the map has a number. After a successful rewind, clear those derived fields. Compact complete is ready unless a prompt is in flight or the session is already running.
There was a problem hiding this comment.
One finding: the Grok driver reads the project root from the process.cwd() module global instead of the ServerConfig service that is already declared in GrokDriverEnv.
Posted via Macroscope — Effect Service Conventions
Bugbot: Effect discovery loaded whole .rhai files then sliced, and skipped ~/.grok/workflows unless HOME was set. Windows uses USERPROFILE. GrokDriver still took project scripts from process.cwd() even though ServerConfig was already in its environment. Read only the 64 KiB prefix through FileSystem.open/readAlloc. Resolve the user workflow directory from HOME or USERPROFILE. Discover project scripts from ServerConfig.cwd.
Check failed: initialSnapshot and checkProvider still required FileSystem and Path after workflow discovery moved onto Effect, and TextDecoder rejected the 'utf8' label. Provide those services the same way Claude does. Decode the capped prefix with the default utf-8 decoder.
| continue; | ||
| } | ||
| const command = grokWorkflowSlashCommandFromMeta(meta); | ||
| byName.set(command.name, command); |
There was a problem hiding this comment.
🟡 Medium acp/GrokWorkflowCommands.ts:109
A discovered script can replace a built-in command, so a valid pause.rhai causes the advertised workflow pause command to launch the script instead of pausing the active run. byName already contains the built-ins before scripts are read, but this unconditional set overwrites them; preserve reserved built-in names while continuing to allow project scripts to override user scripts.
- byName.set(command.name, command);
+ if (!GROK_WORKFLOW_CONTROL_COMMANDS.some(({ name }) => name === command.name)) {
+ byName.set(command.name, command);
+ }🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/acp/GrokWorkflowCommands.ts around line 109:
A discovered script can replace a built-in command, so a valid `pause.rhai` causes the advertised `workflow pause` command to launch the script instead of pausing the active run. `byName` already contains the built-ins before scripts are read, but this unconditional `set` overwrites them; preserve reserved built-in names while continuing to allow project scripts to override user scripts.

Supersedes #6383.
#6383 wired effort, login, rewind, and a thin token parse. Grok Build was already streaming workflows, subagents, PromptUsage, compact, hooks, and queue over ACP. T3 dropped those notifications, so a Rhai workflow still looked like one chat turn.
This PR rebases the useful #6383 commits onto current
mainand maps the live Grok wire onto surfaces T3 already has. No Rhai host. No third Agents UI.Rule
Complexity stays at the adapter. Claude workflow members use
parentAgentId+timelineBypass. Codex collab children do the same. Grok uses that shape. Child tokens stay ontypedUsage. They never replace the thread context window.What you get
session/set_model_meta.reasoningEffort. No new thread. Product sluggrok-buildis an alias for the current model — T3 does not send it.session/set_modeonto advertisedplan/architectvscode/agent. ACPplanentries already fill the turn plan list./workflow pause|resume|stopand named scripts~/.grok/workflowsand<project>/.grok/workflows. Picking one sends that slash text as a prompt. The Grok CLI runs it. Project scripts override user scripts.x.ai/session_notification/_x.ai/session/updateworkflow_updated→local_workflow+ childsubagentrows.agent()subagent_spawned/progress/finished→ the same child-task path.cached_read_tokens, incomplete flag). Usage page scans~/.grok/sessions/**/updates.jsonl. Contract v5 addsgrok.costUsdTicksonly (1e10 = $1). Incomplete bills stay token-only. Never $0._x.ai/rewind. Target from remaining history so a cancelled in-flight prompt cannot ghost. Local turns trim only after execute succeeds.hook.*, session queue length, thread metadata,local_bash.Login:
grok loginorXAI_API_KEY. Probe reports unauthenticated vs missing CLI.From #6383
Theo's three commits (effort menu,
set_modeleffort, rewind, auth probe, in-thread model change) are cherry-picked. Author stays Theo. This branch is the one to review.Not this PR
Plugins and marketplace updates are accepted and ignored. T3 has no plugin surface. Grok TUI
/usageis still the CLI's own screen; T3's Usage page is the transcript scan.Tests
Adapter, workflow mapper, extras, slash-command discovery, usage transcripts, usage chart. CI Check failed on
exactOptionalPropertyTypes(T \| undefinedinto optional bags). CI Test failed because the usage chart now emits a zero Grok band. Both fixed.Made with Grok 4.6.
Note
High Risk
Touches the Grok adapter’s session/turn lifecycle, rewind, permissions, and usage contract v5 (older clients miss Grok usage). Permission fallback to allow_once can change auto-approval when Grok omits allow_always.
Overview
Grok Build now uses the same composer, Agents, usage, and undo surfaces as Claude/Codex instead of dropping ACP extras as a single chat turn.
The adapter maps live
x.aisession notifications onto existing events: workflows andagent()aslocal_workflow/subagenttasks (parentAgentId+timelineBypass), plus compact, hooks, queue, recap, and background shells. Reasoning effort and plan/code modes go throughsession/set_model_metaandsession/set_mode;grok-buildaliases the live model so in-thread switches work. Undo uses_x.ai/rewindafter cancelling in-flight prompts. Workflow.rhaiscripts from home/project.grok/workflowsbecome slash commands.Usage contract v5 adds
grok: prompt usage and completecostUsdTickson the thread, plus scanning~/.grok/sessions/**/updates.jsonlfor the Usage page. Tool-call ticks are rate-limited and truncated. PermissionacceptForSessionfalls back toallow_oncewhen Grok omitsallow_always. Auth probe distinguishes login vs missing CLI.Reviewed by Cursor Bugbot for commit 1a3608f. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add Grok Build provider workflows, usage, and rewind support
updates.jsonltranscripts and bumpingUSAGE_CONTRACT_VERSIONto 5._x.ai/rewind/pointsand_x.ai/rewind/executeRPC methods, including active prompt cancellation and state trimming.grok-buildmodel.USAGE_CONTRACT_VERSIONin usage.ts; clients must negotiate version 5 to report Grok usage.Macroscope summarized 1a3608f.