Skip to content
This repository was archived by the owner on Jul 7, 2026. It is now read-only.

feat: add Slack canvas tools to the agent#38

Closed
Devansh-awat wants to merge 2 commits into
imdevarsh:mainfrom
Devansh-awat:feat/canvas-tools
Closed

feat: add Slack canvas tools to the agent#38
Devansh-awat wants to merge 2 commits into
imdevarsh:mainfrom
Devansh-awat:feat/canvas-tools

Conversation

@Devansh-awat

@Devansh-awat Devansh-awat commented Jun 24, 2026

Copy link
Copy Markdown

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 id
  • canvasWrite — create a channel/standalone canvas, or edit an existing one
  • canvasList — list canvases in the current channel
  • canvasDelete — delete a canvas by id (permanent; only on explicit request)

Implementation

  • New apps/bot/src/lib/ai/tools/canvas.ts, registered in apps/bot/src/lib/ai/toolset.ts.
  • Tools use slack.webClient.apiCall(...) and follow existing conventions ({ success, error?, summary? }, errorMessage() + logger.warn on failure).
  • Declares canvases:read / canvases:write scopes in slack-manifest.json.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Slack bot can now list, create, edit, read, and delete canvas content directly from a thread.
    • Canvas content can be retrieved as markdown for easier review and reuse.
  • Bug Fixes
    • Improved validation and failure handling for canvas operations, returning clearer success/error results when an action can’t be completed.

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>
@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 373d0582-4dec-4985-8e3e-5da503d2dbb2

📥 Commits

Reviewing files that changed from the base of the PR and between ae970a8 and b659d03.

📒 Files selected for processing (1)
  • apps/bot/src/lib/ai/toolset.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/bot/src/lib/ai/toolset.ts

📝 Walkthrough

Walkthrough

Adds a new canvas.ts module with four AI tool functions for Slack Canvas operations. These tools are registered in buildTools(), and the Slack manifest adds canvases:read and canvases:write OAuth scopes.

Changes

Slack Canvas AI Tool Integration

Layer / File(s) Summary
Canvas tool schemas and operations
apps/bot/src/lib/ai/tools/canvas.ts
Defines Zod response schemas, a Thread-to-channel-id helper, and the four exported tool functions. canvasListTool calls files.list; canvasWriteTool branches on mode to call canvases.edit, conversations.canvases.create, or canvases.create; canvasDeleteTool calls canvases.delete; canvasReadTool calls files.info then fetches the markdown content using the bot token.
Toolset registration and OAuth scopes
apps/bot/src/lib/ai/toolset.ts, slack-manifest.json
Imports the four canvas tool constructors and adds canvasRead, canvasWrite, canvasList, canvasDelete to the buildTools() return object. Adds canvases:read and canvases:write to the bot OAuth scopes in the Slack manifest.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop hop, a canvas grew,
I list, I write, I read it too.
With scopes added and tools aligned,
Slack canvases now bunny-shined.

🚥 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change by adding Slack canvas tools to the agent.
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 unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
apps/bot/src/lib/ai/tools/canvas.ts (2)

130-137: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Collapse the duplicated changes ternary.

Both branches are identical except for the operation string, which already equals editOperation.

♻️ 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 value

Avoid as const on the type discriminant.

type: 'markdown' as const uses as const on a discriminant field. Annotate documentContent with the Slack SDK type for document_content instead.

As per coding guidelines: "Do not use as const on 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

📥 Commits

Reviewing files that changed from the base of the PR and between b9809ed and ae970a8.

📒 Files selected for processing (3)
  • apps/bot/src/lib/ai/tools/canvas.ts
  • apps/bot/src/lib/ai/toolset.ts
  • slack-manifest.json

Comment on lines +56 to +61
const result = filesListSchema.parse(
await slack.webClient.apiCall('files.list', {
channel: channelId,
types: 'canvases',
})
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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


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.

Comment on lines +259 to +261
const response = await fetch(info.file.url_private_download, {
headers: { Authorization: `Bearer ${env.SLACK_BOT_TOKEN}` },
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

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

@techwithanirudh

Copy link
Copy Markdown
Collaborator

LGTM

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we split this into multiple files, canvas/read.ts, canvas/write.ts, etc. Share schema w/utils.ts or smth

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants