Skip to content

ref(chat): Consolidate assistant status handling#164

Merged
dcramer merged 8 commits intomainfrom
dcramer/ref/consolidate-assistant-status
Apr 8, 2026
Merged

ref(chat): Consolidate assistant status handling#164
dcramer merged 8 commits intomainfrom
dcramer/ref/consolidate-assistant-status

Conversation

@dcramer
Copy link
Copy Markdown
Member

@dcramer dcramer commented Apr 7, 2026

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.setStatus expires. 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_messages payloads, and rendering rules easier to reason about and maintain.

Refs getsentry/junior-prod#22

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>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
junior-docs Ready Ready Preview, Comment Apr 8, 2026 3:31pm

Request Review

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>
Copy link
Copy Markdown

@cursor cursor bot left a comment

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 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.

Create PR

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>
Copy link
Copy Markdown

@cursor cursor bot left a comment

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 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 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);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

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

@dcramer dcramer merged commit 9c7e408 into main Apr 8, 2026
14 checks passed
@dcramer dcramer deleted the dcramer/ref/consolidate-assistant-status branch April 8, 2026 15:45
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.

1 participant