Skip to content

fix: resolve #825 — slack-primitive: persist askQuestion exchanges to workflow run record#834

Open
SlncTrZ wants to merge 2 commits into
AgentWorkforce:mainfrom
SlncTrZ:CntrB/feat/extend-workflowrunrecord-schema-to-persi
Open

fix: resolve #825 — slack-primitive: persist askQuestion exchanges to workflow run record#834
SlncTrZ wants to merge 2 commits into
AgentWorkforce:mainfrom
SlncTrZ:CntrB/feat/extend-workflowrunrecord-schema-to-persi

Conversation

@SlncTrZ
Copy link
Copy Markdown

@SlncTrZ SlncTrZ commented May 10, 2026

Summary

fix: resolve #825 — slack-primitive: persist askQuestion exchanges to workflow run record

Problem

Severity: High | File: packages/runner/src/types/workflow-run-record.ts

Add an optional askQuestionExchanges array field to the workflow run record. Each element corresponds to one askQuestion step execution, storing channel, question timestamp, question text, replier user ID, reply text, reply timestamp, matched choices/regex groups, and timeout outcome. This enables post-mortem inspection without relying on Slack's message retention.

Solution

Changes

  • packages/runner/src/types/workflow-run-record.ts (new)
  • packages/runner/src/execution/slack-ask-question-handler.ts (new)

Testing

  • Existing tests pass
  • Manual review completed
  • No new warnings/errors introduced"

SlncTrZ added 2 commits May 11, 2026 01:42
…n exchanges to workflow run record

Fixes AgentWorkforce#825

Signed-off-by: Dinh Truong (SlncTrZ) <46520299+SlncTrZ@users.noreply.github.com>
…n exchanges to workflow run record

Fixes AgentWorkforce#825

Signed-off-by: Dinh Truong (SlncTrZ) <46520299+SlncTrZ@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 10, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds persistence for Slack ask-question exchanges to workflow run records. It introduces two TypeScript interfaces defining the run record and exchange schemas, and implements a handler that waits for Slack replies, constructs exchange objects with question/reply/metadata, and persists them to storage.

Changes

Slack Ask-Question Exchange Persistence

Layer / File(s) Summary
Data Contracts
packages/runner/src/types/workflow-run-record.ts
Defines WorkflowRunRecord with optional askQuestionExchanges array, and AskQuestionExchange capturing channel, question text/timestamp, optional reply user/text/timestamp, matched results, and timeout outcome.
Handler Implementation
packages/runner/src/execution/slack-ask-question-handler.ts
Implements handleSlackAskQuestion to wait for step reply with timeout, map result into exchange record, and persist via updateRunAskQuestionExchanges.

🎯 2 (Simple) | ⏱️ ~8 minutes


🐰 A question posed to humans so fair,
Their answers recorded with utmost care,
Exchanges persist through the runner's domain,
No Slack message lost, the data will remain,
The workflow remembers what humans declare! 🎯

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly references the linked issue and accurately describes the main change: adding persistence for askQuestion exchanges.
Description check ✅ Passed The description provides a clear problem statement and lists changed files, but lacks a detailed solution section and test plan specifics.
Linked Issues check ✅ Passed The pull request implements all required fields for askQuestion persistence: channel, questionTs, questionText, replierUserId, replyText, replyTs, matched groups, and timeout outcome.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #825 scope: new type definitions and handler for persisting askQuestion exchanges to the workflow run record.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines +11 to +16
const exchange = {
question: step.input.question,
timestamp: new Date(),
reply: result.reply,
timeout: result.timeout === true
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Exchange object fields don't match the AskQuestionExchange interface from the same PR

The exchange object constructed in handleSlackAskQuestion uses field names and types that are completely misaligned with the AskQuestionExchange interface defined in packages/runner/src/types/workflow-run-record.ts:10-20:

  • question → should be questionText
  • timestamp (Date) → should be questionTimestamp (string)
  • reply → should be replyText
  • timeout (boolean) → should be timeoutOutcome ('timeout' | 'cancelled' | null)
  • Missing required field channel

Since updateRunAskQuestionExchanges doesn't exist yet (the persistence module is unimplemented), there is no compile-time type constraint on this object — the mismatch will silently persist until the persistence layer is wired up, at which point either this code will break or the wrong data will be stored.

Prompt for agents
The exchange object built at slack-ask-question-handler.ts:11-16 uses field names (question, timestamp, reply, timeout) that don't match the AskQuestionExchange interface defined at workflow-run-record.ts:10-20 (questionText, questionTimestamp, replyText, timeoutOutcome, channel). The handler should import AskQuestionExchange and construct an object conforming to it. Specifically: (1) rename 'question' to 'questionText', (2) rename 'timestamp' to 'questionTimestamp' and convert it to a string, (3) rename 'reply' to 'replyText', (4) replace the boolean 'timeout' with 'timeoutOutcome' using the correct union type ('timeout' | 'cancelled' | null), (5) add the required 'channel' field (likely from step.input or step.config). The import of AskQuestionExchange should come from '../types/workflow-run-record'.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/runner/src/execution/slack-ask-question-handler.ts`:
- Around line 9-20: Remove the no-op try/catch wrapper around the await calls:
delete the try { ... } catch (error) { throw error; } block and leave the two
awaits as-is so errors from step.waitForReply(timeoutMs) and
updateRunAskQuestionExchanges(runId, exchange) propagate naturally; keep
construction of the exchange object (question, timestamp, reply, timeout) and
preserve existing variable names (step, timeoutMs, exchange, runId).
- Around line 11-17: The persisted exchange object currently created in
slack-ask-question-handler (variable exchange) uses
question/timestamp/reply/timeout which doesn't match the AskQuestionExchange
schema; update construction to populate the schema fields expected by
updateRunAskQuestionExchanges: set channel from the Slack context (e.g.,
step.input.channel or handler context), questionTimestamp to the original
timestamp (new Date() or step.input.timestamp if available), questionText from
step.input.question, replyText from result.reply, replyTimestamp from
result.replyTimestamp or now when reply arrived, and timeoutOutcome from
result.timeout (map boolean to the enum/value expected); ensure the object you
pass to updateRunAskQuestionExchanges uses these property names (channel,
questionTimestamp, questionText, replyText, replyTimestamp, timeoutOutcome) so
typing and persisted forensic fields are complete.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ce907ad5-ffa5-4f1a-b510-b36412368bb7

📥 Commits

Reviewing files that changed from the base of the PR and between bffd6b2 and 7134cc9.

📒 Files selected for processing (2)
  • packages/runner/src/execution/slack-ask-question-handler.ts
  • packages/runner/src/types/workflow-run-record.ts

Comment on lines +9 to +20
try {
const result = await step.waitForReply(timeoutMs);
const exchange = {
question: step.input.question,
timestamp: new Date(),
reply: result.reply,
timeout: result.timeout === true
};
await updateRunAskQuestionExchanges(runId, exchange);
} catch (error) {
throw error;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify useless catch/rethrow patterns in TS files
ast-grep --lang ts --pattern $'try { $$$BODY } catch ($ERR) { throw $ERR; }'

Repository: AgentWorkforce/relay

Length of output: 1143


Remove the no-op catch/rethrow wrapper.

The try-catch block at lines 9–20 catches and immediately rethrows the error unchanged, which violates the no-useless-catch rule and adds unnecessary noise. Remove the entire try-catch and let the error propagate naturally.

🧰 Tools
🪛 ESLint

[error] 9-20: Unnecessary try/catch wrapper.

(no-useless-catch)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/runner/src/execution/slack-ask-question-handler.ts` around lines 9 -
20, Remove the no-op try/catch wrapper around the await calls: delete the try {
... } catch (error) { throw error; } block and leave the two awaits as-is so
errors from step.waitForReply(timeoutMs) and
updateRunAskQuestionExchanges(runId, exchange) propagate naturally; keep
construction of the exchange object (question, timestamp, reply, timeout) and
preserve existing variable names (step, timeoutMs, exchange, runId).

Comment on lines +11 to +17
const exchange = {
question: step.input.question,
timestamp: new Date(),
reply: result.reply,
timeout: result.timeout === true
};
await updateRunAskQuestionExchanges(runId, exchange);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Persisted exchange payload does not match the new run-record schema.

On Line 11–16, the object uses question/timestamp/reply/timeout, but the new AskQuestionExchange schema expects fields like channel, questionTimestamp, questionText, replyText, replyTimestamp, and timeoutOutcome. This will either fail typing upstream or persist incomplete data that misses #825’s required forensic fields.

Suggested mapping update
+import type { AskQuestionExchange } from '../types/workflow-run-record';

-    const exchange = {
-      question: step.input.question,
-      timestamp: new Date(),
-      reply: result.reply,
-      timeout: result.timeout === true
-    };
+    const exchange: AskQuestionExchange = {
+      channel: step.input.channel,
+      questionTimestamp: step.input.questionTs,
+      questionText: step.input.question,
+      replierUserId: result.replierUserId,
+      replyText: result.reply,
+      replyTimestamp: result.replyTs,
+      matchedChoices: result.matchedChoices,
+      matchedRegexGroups: result.matchedRegexGroups,
+      timeoutOutcome: result.timeout ? 'timeout' : null,
+    };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const exchange = {
question: step.input.question,
timestamp: new Date(),
reply: result.reply,
timeout: result.timeout === true
};
await updateRunAskQuestionExchanges(runId, exchange);
import type { AskQuestionExchange } from '../types/workflow-run-record';
const exchange: AskQuestionExchange = {
channel: step.input.channel,
questionTimestamp: step.input.questionTs,
questionText: step.input.question,
replierUserId: result.replierUserId,
replyText: result.reply,
replyTimestamp: result.replyTs,
matchedChoices: result.matchedChoices,
matchedRegexGroups: result.matchedRegexGroups,
timeoutOutcome: result.timeout ? 'timeout' : null,
};
await updateRunAskQuestionExchanges(runId, exchange);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/runner/src/execution/slack-ask-question-handler.ts` around lines 11
- 17, The persisted exchange object currently created in
slack-ask-question-handler (variable exchange) uses
question/timestamp/reply/timeout which doesn't match the AskQuestionExchange
schema; update construction to populate the schema fields expected by
updateRunAskQuestionExchanges: set channel from the Slack context (e.g.,
step.input.channel or handler context), questionTimestamp to the original
timestamp (new Date() or step.input.timestamp if available), questionText from
step.input.question, replyText from result.reply, replyTimestamp from
result.replyTimestamp or now when reply arrived, and timeoutOutcome from
result.timeout (map boolean to the enum/value expected); ensure the object you
pass to updateRunAskQuestionExchanges uses these property names (channel,
questionTimestamp, questionText, replyText, replyTimestamp, timeoutOutcome) so
typing and persisted forensic fields are complete.

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.

slack-primitive: persist askQuestion exchanges to workflow run record

1 participant