ref(chat): Consolidate assistant status handling#164
Conversation
Centralize Slack assistant status transport and rendering so normal turns and OAuth resume share one implementation. Preserve semantic status hints while rendering playful Slack-visible copy, and remove the duplicate tool-start status emission path so the behavior is easier to maintain. Refs getsentry/junior-prod#22 Co-Authored-By: Codex <noreply@openai.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Add a larger playful prefix set for rendered Slack assistant statuses and update the oauth callback logging mock so the shared status transport can warn safely during tests. This also verifies the full package test entrypoint passes, matching the CI job that failed on the PR. Refs getsentry/junior-prod#22 Co-Authored-By: Codex <noreply@openai.com>
Replace inferred assistant status rendering with an explicit status builder based on stable kinds and optional context. This removes the free-form string parsing path for runtime-owned statuses, keeps rotation scoped to each status kind, and moves tool and sandbox progress updates onto the same typed contract. Refs getsentry/junior-prod#22 Co-Authored-By: Codex <noreply@openai.com>
Fix the stale sandbox status callback type that was still constrained to raw strings so docs type generation matches the new assistant status spec contract. Also restore provider-specific search tool context and update the local formatter regression to keep the status builder output explicit. Co-Authored-By: Codex <noreply@openai.com>
Reuse the normalized string status value in the progress reporter instead of recomputing it for presentation and queueing. This keeps the status path simpler without changing behavior. Co-Authored-By: Codex <noreply@openai.com>
Finish the assistant status cleanup by removing the raw string escape hatch and using typed status specs across the runtime. This keeps status rendering aligned with the declared kind constants and moves the remaining sandbox setup phases onto the same typed path. Co-Authored-By: Codex <noreply@openai.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Unused test constant never referenced in assertions
- Removed the unused constant secondPlayfulStatus which was never referenced in any test assertion and would never match actual output given the test configuration.
Or push these changes by commenting:
@cursor push 23bb2b9098
Preview (23bb2b9098)
diff --git a/packages/junior/tests/unit/progress-reporter.test.ts b/packages/junior/tests/unit/progress-reporter.test.ts
--- a/packages/junior/tests/unit/progress-reporter.test.ts
+++ b/packages/junior/tests/unit/progress-reporter.test.ts
@@ -62,7 +62,6 @@
}
const firstPlayfulStatus = "Thinking task";
-const secondPlayfulStatus = "Reasoning task";
const secondSearchingStatus = "Searching sources";
const secondReadingStatus = "Reading source files";
const secondReviewingStatus = "Reviewing results";This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 6cc6c0b. Configure here.
The "thinking" kind used "task" as its defaultContext, producing unnatural text like "Thinking task" or "Reasoning task". Changed to an ellipsis so it renders as "Thinking …" instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| if (waitMs <= 0) { | ||
| clearPending(); | ||
| void postStatus(truncated); | ||
| void postRenderedStatus(status); |
There was a problem hiding this comment.
Bug: A race condition exists where setStatus uses a fire-and-forget promise. This can cause a stale status to be posted after stop() has already cleared the status message.
Severity: MEDIUM
Suggested Fix
Await the postRenderedStatus call within setStatus to ensure status updates are fully processed before the function returns. This will prevent stop() from executing before the status update has been added to the promise queue, eliminating the race condition.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: packages/junior/src/chat/runtime/progress-reporter.ts#L181
Potential issue: The `setStatus` function calls `postRenderedStatus` without awaiting it
(`void postRenderedStatus(...)`). This allows the function to return immediately. If the
agent turn completes and `progress.stop()` is called before the `postRenderedStatus`
promise executes its own internal `postStatus` call, a race condition occurs. The
`stop()` function will clear the status, but the pending `postRenderedStatus` will
subsequently execute and post a stale status message, overwriting the cleared state.
This leaves incorrect visual feedback (e.g., a "Thinking" message) in the Slack thread
after the turn has ended.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
False positive — postStatus serializes all updates through inflightStatusUpdate (line 92-98). Each call chains behind the previous one via await previous. When stop() calls await postStatus(""), it awaits the prior in-flight update before sending the empty status, so ordering is guaranteed. The void just avoids blocking the caller, not the queue.
— Claude Code


Consolidate Slack assistant status handling behind a single runtime path that owns semantic hint normalization, playful status rendering, periodic refresh, and Slack transport behavior.
This change fixes the long-running status timeout issue by keeping the real phase text in the runtime while refreshing the Slack-visible status before
assistant.threads.setStatusexpires. It also removes the duplicate tool-start emission path and reuses the same progress reporter for normal turns and OAuth resume so the behavior does not drift.I considered leaving the recent fix in place and only adding more targeted patches around OAuth resume or tool execution, but that would keep the status pipeline split across multiple layers and transports. Centralizing the status contract makes the Slack timeout behavior,
loading_messagespayloads, and rendering rules easier to reason about and maintain.Refs getsentry/junior-prod#22