feat: add Slack canvas tools to the agent#38
Conversation
Add canvasRead, canvasWrite, canvasList, and canvasDelete agent tools so the
bot can create, read, list, and delete Slack canvases (rich, persistent docs)
for meeting notes, decisions, specs, and runbooks.
Tools use slack.webClient.apiCall and follow the existing tool conventions
({ success, error?, summary? }, errorMessage() + logger.warn on failure).
Declares the canvases:read / canvases:write scopes in slack-manifest.json.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a new ChangesSlack Canvas AI Tool Integration
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
apps/bot/src/lib/ai/tools/canvas.ts (2)
130-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueCollapse the duplicated
changesternary.Both branches are identical except for the
operationstring, which already equalseditOperation.♻️ Simplify
- changes: [ - editOperation === 'replace' - ? { document_content: documentContent, operation: 'replace' } - : { - document_content: documentContent, - operation: 'insert_at_end', - }, - ], + changes: [ + { document_content: documentContent, operation: editOperation }, + ],🤖 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 `@apps/bot/src/lib/ai/tools/canvas.ts` around lines 130 - 137, The duplicated ternary in the `changes` array construction inside `canvas.ts` should be collapsed because both branches only differ by the `operation` value. Update the `editOperation === 'replace'` logic in the `changes` assignment to build a single object using `editOperation` directly for `operation`, while keeping `document_content: documentContent` unchanged.
118-118: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAvoid
as conston thetypediscriminant.
type: 'markdown' as constusesas conston a discriminant field. AnnotatedocumentContentwith the Slack SDK type fordocument_contentinstead.As per coding guidelines: "Do not use
as conston discriminants; annotate with the SDK type instead."🤖 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 `@apps/bot/src/lib/ai/tools/canvas.ts` at line 118, The `documentContent` object in `canvas.ts` is using `as const` on the `type` discriminant, which should be replaced with an explicit Slack SDK `document_content` type annotation. Update the `documentContent` declaration so it is typed with the appropriate SDK type instead of relying on `type: 'markdown' as const`, keeping the `markdown` payload and discriminant shape intact.Source: Coding guidelines
🤖 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 `@apps/bot/src/lib/ai/tools/canvas.ts`:
- Around line 259-261: Bound the Slack file download in canvas.ts so the
request-path fetch cannot hang indefinitely; update the fetch call in the canvas
download logic to use a timeout via AbortSignal.timeout(...) or an
AbortController, and make sure the timeout is applied around the existing
info.file.url_private_download request with the Authorization header. If the
timeout triggers, handle the abort cleanly so the tool can fail fast instead of
blocking execution.
- Around line 56-61: The Slack files.list request in the canvas tool is using
the wrong filter value, so it won’t match canvas files. Update the `canvas.ts`
logic in the code that calls `slack.webClient.apiCall('files.list', ...)` to use
the singular `types: 'canvas'` instead of `canvases`, keeping the rest of the
`filesListSchema.parse` flow unchanged.
---
Nitpick comments:
In `@apps/bot/src/lib/ai/tools/canvas.ts`:
- Around line 130-137: The duplicated ternary in the `changes` array
construction inside `canvas.ts` should be collapsed because both branches only
differ by the `operation` value. Update the `editOperation === 'replace'` logic
in the `changes` assignment to build a single object using `editOperation`
directly for `operation`, while keeping `document_content: documentContent`
unchanged.
- Line 118: The `documentContent` object in `canvas.ts` is using `as const` on
the `type` discriminant, which should be replaced with an explicit Slack SDK
`document_content` type annotation. Update the `documentContent` declaration so
it is typed with the appropriate SDK type instead of relying on `type:
'markdown' as const`, keeping the `markdown` payload and discriminant shape
intact.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 50737e6c-91f1-4a82-92d5-64307374c896
📒 Files selected for processing (3)
apps/bot/src/lib/ai/tools/canvas.tsapps/bot/src/lib/ai/toolset.tsslack-manifest.json
| const result = filesListSchema.parse( | ||
| await slack.webClient.apiCall('files.list', { | ||
| channel: channelId, | ||
| types: 'canvases', | ||
| }) | ||
| ); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major
🧩 Analysis chain
🌐 Web query:
Slack files.list API types parameter accepted values for canvases
💡 Result:
To retrieve Slack canvases using the files.list API, you use the "canvas" value for the types parameter [1]. An example API call would look like: https://slack.com/api/files.list?types=canvas [1]. Slack treats standalone canvases as file objects [2], allowing them to be indexed and listed via the files.list endpoint when this specific filter is applied [1].
Citations:
- 1: https://docs.slack.dev/surfaces/canvases
- 2: Enhancement: scan Slack Canvases for secrets and PII PaperMtn/slack-watchman#112
Use types: 'canvas' here. Slack’s files.list canvas filter is singular, so canvases won’t target canvas files.
🤖 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 `@apps/bot/src/lib/ai/tools/canvas.ts` around lines 56 - 61, The Slack
files.list request in the canvas tool is using the wrong filter value, so it
won’t match canvas files. Update the `canvas.ts` logic in the code that calls
`slack.webClient.apiCall('files.list', ...)` to use the singular `types:
'canvas'` instead of `canvases`, keeping the rest of the `filesListSchema.parse`
flow unchanged.
| const response = await fetch(info.file.url_private_download, { | ||
| headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` }, | ||
| }); |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Add a timeout to the canvas download fetch.
This fetch runs on the request path with no timeout, so a slow/hung Slack file endpoint can block the tool execution indefinitely. Use AbortSignal.timeout(...) (or an AbortController) to bound it.
🛡️ Proposed fix
- const response = await fetch(info.file.url_private_download, {
- headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` },
- });
+ const response = await fetch(info.file.url_private_download, {
+ headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` },
+ signal: AbortSignal.timeout(15_000),
+ });📝 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.
| const response = await fetch(info.file.url_private_download, { | |
| headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` }, | |
| }); | |
| const response = await fetch(info.file.url_private_download, { | |
| headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` }, | |
| signal: AbortSignal.timeout(15_000), | |
| }); |
🤖 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 `@apps/bot/src/lib/ai/tools/canvas.ts` around lines 259 - 261, Bound the Slack
file download in canvas.ts so the request-path fetch cannot hang indefinitely;
update the fetch call in the canvas download logic to use a timeout via
AbortSignal.timeout(...) or an AbortController, and make sure the timeout is
applied around the existing info.file.url_private_download request with the
Authorization header. If the timeout triggers, handle the abort cleanly so the
tool can fail fast instead of blocking execution.
|
LGTM |
There was a problem hiding this comment.
Can we split this into multiple files, canvas/read.ts, canvas/write.ts, etc. Share schema w/utils.ts or smth
Summary
Adds four agent tools so Gorkie can work with Slack canvases (rich, persistent documents) — useful for meeting notes, decisions, specs, and runbooks.
canvasRead— read an existing canvas by file idcanvasWrite— create a channel/standalone canvas, or edit an existing onecanvasList— list canvases in the current channelcanvasDelete— delete a canvas by id (permanent; only on explicit request)Implementation
apps/bot/src/lib/ai/tools/canvas.ts, registered inapps/bot/src/lib/ai/toolset.ts.slack.webClient.apiCall(...)and follow existing conventions ({ success, error?, summary? },errorMessage()+logger.warnon failure).canvases:read/canvases:writescopes inslack-manifest.json.🤖 Generated with Claude Code
Summary by CodeRabbit