Skip to content

fix: include recent Slack notifications in agent context#2147

Merged
yottahmd merged 4 commits into
mainfrom
fix-slack-recent-event-context
May 14, 2026
Merged

fix: include recent Slack notifications in agent context#2147
yottahmd merged 4 commits into
mainfrom
fix-slack-recent-event-context

Conversation

@yottahmd
Copy link
Copy Markdown
Collaborator

@yottahmd yottahmd commented May 14, 2026

Summary

  • add dynamic agent system context so volatile gateway facts can be injected per request without persisting chat history
  • record the five newest Slack DAG notification events per channel and include them as escaped recent-event context
  • cover create/enqueue agent paths, Slack context injection, retention, and escaping behavior with regression tests

Changes

  • add per-request dynamic system context plumbing for agent sessions and loops
  • include recent Slack DAG notification events in gateway agent requests
  • keep the Slack recent-event buffer capped at five events per channel with sanitization and strict truncation
  • harden regression tests for stale context clearing, event ordering, retention, and escaping

Related Issues

None.

Testing

  • go test ./internal/service/chatbridge ./internal/service/slack ./internal/agent -count=1
  • golangci-lint run ./internal/service/slack/...
  • git diff --check

Checklist

  • Code follows the project style guidelines
  • Self-review of the code has been performed
  • Tests have been added or updated as needed
  • Documentation has been updated as needed
  • Changes have been tested locally

Summary by CodeRabbit

  • New Features

    • Agent sessions accept dynamic per-request system context that is merged into system prompts at runtime and can be updated mid-session.
    • Slack bot captures up to five recent gateway events per channel and injects a sanitized, truncated recent-notification block into the agent system context.
  • Tests

    • Added tests verifying dynamic system context propagation, updates, and recent-event handling in session flows.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6ddb8e0d-aac4-4912-b47d-2d794edd4ebe

📥 Commits

Reviewing files that changed from the base of the PR and between db50acc and ae7446f.

📒 Files selected for processing (2)
  • internal/service/slack/bot_test.go
  • internal/service/slack/recent_events.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • internal/service/slack/bot_test.go
  • internal/service/slack/recent_events.go

📝 Walkthrough

Walkthrough

This PR injects per-request dynamic system-context providers into agent sessions, composes base+dynamic system prompts per LLM request, threads the provider through session creation/reactivation, and adds Slack bot code to record recent gateway events and attach them as dynamic system context for incoming Slack messages.

Changes

Dynamic System Context Infrastructure

Layer / File(s) Summary
Dynamic context contract and helpers
internal/agent/contextkeys.go
New DynamicSystemContextFunc type and exported WithDynamicSystemContext and GetDynamicSystemContext helpers to inject and retrieve per-request context providers.
Loop dynamic-context integration
internal/agent/loop.go
Loop now accepts a DynamicSystemContext provider, composes currentSystemPrompt(ctx) merging base prompt and dynamic output, and passes ctx into buildMessages.
SessionManager wiring and runtime propagation
internal/agent/session.go
SessionManager stores/initializes dynamicSystemCtx, exposes SetDynamicSystemContext, and wires the provider into created loops.
API integration and request context propagation
internal/agent/api.go
Threads request context into buildSessionManagerConfig at session creation/reactivation and applies dynamic context via mgr.SetDynamicSystemContext(GetDynamicSystemContext(ctx)) when preparing runtimes.
Dynamic context tests
internal/agent/loop_test.go, internal/agent/api_test.go
Adds tests for message building with dynamic context and API tests verifying CreateSession/EnqueueChatMessage propagate and update dynamic system context.

Slack Recent Gateway Events

Layer / File(s) Summary
Recent gateway events tracking and formatting
internal/service/slack/recent_events.go
New module with per-channel capped (5-event) notification history, conversion from batches to internal records, DAG status summarization, sanitized field rendering, and XML-like formatting for LLM inclusion.
Slack bot event recording and context injection
internal/service/slack/bot.go, internal/service/slack/monitor.go
Add recentGatewayEvents storage and mutex to Bot; record events during channel thread flush and wrap incoming contexts with withRecentGatewayEventsContext before session/message dispatch.
Slack tests and fake agent service updates
internal/service/slack/bot_test.go
Extend fakeSlackAgentService to capture dynamic-context strings and add tests validating recent-events XML block contents, ordering, truncation, and HTML-escaping.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 9.52% 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 summarizes the main change: adding recent Slack notifications as context for the agent, which is the primary feature across all modified files.
Description check ✅ Passed The description covers all required template sections: Summary (explaining the three main objectives), Changes (listing implementation and testing details), Related Issues, Testing command, and a completed Checklist.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-slack-recent-event-context

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.

❤️ Share

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

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: 1

🧹 Nitpick comments (2)
internal/agent/api_test.go (1)

700-733: ⚡ Quick win

Add a no-context follow-up assertion to prevent stale dynamic context regressions.

After the run-2 enqueue, enqueue once more with plain context.Background() and assert run-2 is not present in the next system message. This will lock in the intended “per-request volatile” behavior.

🤖 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 `@internal/agent/api_test.go` around lines 700 - 733, Add a second enqueue
using plain context.Background() after the existing run-2 test to verify dynamic
system context is per-request: call api.EnqueueChatMessage(context.Background(),
sessionID, user, ChatRequest{Message: "もう一度"}), wait for the next provider
request via waitForRequest(reqCh,...), then assert req.Messages[0].Role is
llm.RoleSystem and that req.Messages[0].Content does NOT contain "run-2" (and
does NOT contain "<recent_gateway_events>"); this ensures
TestAPI_EnqueueChatMessage_UpdatesDynamicSystemContext, api.EnqueueChatMessage,
reqCh and waitForRequest cover the no-context follow-up case and prevent stale
dynamic context regressions.
internal/service/slack/recent_events.go (1)

143-154: 💤 Low value

Consider clarifying truncation semantics.

The maxRunes parameter suggests a strict limit, but when truncation occurs the function returns maxRunes + 3 runes (to accommodate "..."). For the large limits used (80–240), this is acceptable, but consider either:

  • Renaming to maxRunesBeforeEllipsis for clarity, or
  • Subtracting 3 from maxRunes before slicing to enforce a strict post-ellipsis limit.
🤖 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 `@internal/service/slack/recent_events.go` around lines 143 - 154,
sanitizeRecentGatewayField currently treats maxRunes as the number of runes to
slice before adding "..." which makes the returned string length maxRunes+3;
update the implementation or signature to clarify semantics: either rename the
parameter to maxRunesBeforeEllipsis (and update all call sites to match) to
document that the ellipsis is appended after slicing, or enforce a strict
post-ellipsis limit by subtracting 3 from maxRunes before creating the slice in
sanitizeRecentGatewayField so the final returned rune count never exceeds
maxRunes; reference the function sanitizeRecentGatewayField and parameter
maxRunes when making the change.
🤖 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 `@internal/agent/session.go`:
- Around line 287-297: The SetDynamicSystemContext method currently returns
early when fn is nil, preventing callers from clearing a previously set
provider; change it to accept nil to clear sm.dynamicSystemCtx and propagate the
nil to the active loop by setting sm.dynamicSystemCtx = fn (even if fn == nil)
under the mutex and then calling loop.SetDynamicSystemContext(fn) if loop != nil
so future GetDynamicSystemContext(ctx) calls will observe the cleared provider;
update SessionManager.SetDynamicSystemContext and ensure
loop.SetDynamicSystemContext is invoked with nil to remove stale per-request
context.

---

Nitpick comments:
In `@internal/agent/api_test.go`:
- Around line 700-733: Add a second enqueue using plain context.Background()
after the existing run-2 test to verify dynamic system context is per-request:
call api.EnqueueChatMessage(context.Background(), sessionID, user,
ChatRequest{Message: "もう一度"}), wait for the next provider request via
waitForRequest(reqCh,...), then assert req.Messages[0].Role is llm.RoleSystem
and that req.Messages[0].Content does NOT contain "run-2" (and does NOT contain
"<recent_gateway_events>"); this ensures
TestAPI_EnqueueChatMessage_UpdatesDynamicSystemContext, api.EnqueueChatMessage,
reqCh and waitForRequest cover the no-context follow-up case and prevent stale
dynamic context regressions.

In `@internal/service/slack/recent_events.go`:
- Around line 143-154: sanitizeRecentGatewayField currently treats maxRunes as
the number of runes to slice before adding "..." which makes the returned string
length maxRunes+3; update the implementation or signature to clarify semantics:
either rename the parameter to maxRunesBeforeEllipsis (and update all call sites
to match) to document that the ellipsis is appended after slicing, or enforce a
strict post-ellipsis limit by subtracting 3 from maxRunes before creating the
slice in sanitizeRecentGatewayField so the final returned rune count never
exceeds maxRunes; reference the function sanitizeRecentGatewayField and
parameter maxRunes when making the change.
🪄 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

Run ID: 15612f61-276c-440a-8014-deca031ff2f4

📥 Commits

Reviewing files that changed from the base of the PR and between 5669305 and d174465.

📒 Files selected for processing (10)
  • internal/agent/api.go
  • internal/agent/api_test.go
  • internal/agent/contextkeys.go
  • internal/agent/loop.go
  • internal/agent/loop_test.go
  • internal/agent/session.go
  • internal/service/slack/bot.go
  • internal/service/slack/bot_test.go
  • internal/service/slack/monitor.go
  • internal/service/slack/recent_events.go

Comment thread internal/agent/session.go
@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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.

🧹 Nitpick comments (1)
internal/service/slack/bot_test.go (1)

434-434: 💤 Low value

Consider a more explicit ordering check.

The current approach using strings.Index assumes both strings are present (which is verified by earlier assertions) but is slightly fragile if the output format changes. Consider using a more structured approach or adding explicit index checks.

💡 Example alternative approach
-	assert.Less(t, strings.Index(text, "dag: dag-5"), strings.Index(text, "dag: dag-4"))
+	idx5 := strings.Index(text, "dag: dag-5")
+	idx4 := strings.Index(text, "dag: dag-4")
+	require.GreaterOrEqual(t, idx5, 0, "dag-5 should be present")
+	require.GreaterOrEqual(t, idx4, 0, "dag-4 should be present")
+	assert.Less(t, idx5, idx4, "dag-5 should appear before dag-4")
🤖 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 `@internal/service/slack/bot_test.go` at line 434, The assertion using
assert.Less(strings.Index(...)) is fragile; update the test in bot_test.go to
explicitly verify presence and ordering by first computing idx5 :=
strings.Index(text, "dag: dag-5") and idx4 := strings.Index(text, "dag: dag-4"),
assert both idx5 and idx4 are >= 0 (presence) and then assert idx5 < idx4
(ordering) or alternatively split text into lines and assert the line index of
"dag-5" comes before "dag-4"; use the existing assert functions
(assert.GreaterOrEqual/assert.Less) around idx5 and idx4 to make the checks
explicit and robust.
🤖 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.

Nitpick comments:
In `@internal/service/slack/bot_test.go`:
- Line 434: The assertion using assert.Less(strings.Index(...)) is fragile;
update the test in bot_test.go to explicitly verify presence and ordering by
first computing idx5 := strings.Index(text, "dag: dag-5") and idx4 :=
strings.Index(text, "dag: dag-4"), assert both idx5 and idx4 are >= 0 (presence)
and then assert idx5 < idx4 (ordering) or alternatively split text into lines
and assert the line index of "dag-5" comes before "dag-4"; use the existing
assert functions (assert.GreaterOrEqual/assert.Less) around idx5 and idx4 to
make the checks explicit and robust.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 146c104e-a35e-4015-9081-5a4d65fbbaac

📥 Commits

Reviewing files that changed from the base of the PR and between d174465 and db50acc.

📒 Files selected for processing (4)
  • internal/agent/api_test.go
  • internal/agent/session.go
  • internal/service/slack/bot_test.go
  • internal/service/slack/recent_events.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • internal/agent/session.go
  • internal/agent/api_test.go
  • internal/service/slack/recent_events.go

@yottahmd
Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@yottahmd yottahmd merged commit d7a644d into main May 14, 2026
10 checks passed
@yottahmd yottahmd deleted the fix-slack-recent-event-context branch May 14, 2026 10:21
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