Skip to content

feat(platformtools): thread ToolCallEnv + add Slack tools#2327

Merged
danielkov merged 6 commits intomainfrom
daniel/age-1896-platformtools-slack
Apr 21, 2026
Merged

feat(platformtools): thread ToolCallEnv + add Slack tools#2327
danielkov merged 6 commits intomainfrom
daniel/age-1896-platformtools-slack

Conversation

@danielkov
Copy link
Copy Markdown
Contributor

Summary

  • Add toolconfig.ToolCallEnv param to core.PlatformToolExecutor.Call. All existing implementers (logs, triggers) plus the single runtime/service.ExecuteTool caller flip together — atomic to keep compilation green.
  • Add SlackHTTPClient *guardian.HTTPClient field to platformtools.Dependencies and a WithSlackHTTPClient option.
  • Introduce 8 Slack Web API platform tools under server/internal/platformtools/slack/ (read channel / thread / user profile, search channels / messages / users, schedule / send message) registered through the existing registry.go factory list.
  • Tools read OAuthToken from the new env param; pooled guardian.HTTPClient dials via the project's DNS / allowlist guardrails.
  • Unused until the assistants runtime wiring lands.

Linear: https://linear.app/speakeasy/issue/AGE-1896/featplatformtools-thread-toolcallenv-add-slack-tools

✻ Clauded...

Extend the core PlatformToolExecutor.Call interface with a
toolconfig.ToolCallEnv parameter so platform tools can read per-call
OAuthToken, UserConfig, SystemEnv, and GramEmail. The signature change
is atomic: all implementers (logs.SearchLogs, triggers.ListTriggers,
triggers.ConfigureTrigger, new slack.* tools), the single runtime
caller (platformtools/runtime.Service.ExecuteTool) and the
gateway.PlatformExecutor interface consumed by the tool proxy flip
together, because splitting the change breaks compilation.

Add a SlackHTTPClient *guardian.HTTPClient field to the platformtools
Dependencies struct and a matching WithSlackHTTPClient runtime option
so the Slack tools dial through the project's DNS allowlist /
connection pool.

Register 8 Slack Web API tools under server/internal/platformtools/slack/:
read channel / thread / user profile, search channels / messages /
users, schedule message, and send message. Each tool reads its OAuth
token from the threaded env and returns a normalized JSON payload.
Tools are wired through the existing registry.go factory list but
remain unused until the assistants runtime wiring lands in a later
change.

✻ Clauded...
@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 21, 2026

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

Project Deployment Actions Updated (UTC)
gram-docs-redirect Ready Ready Preview, Comment Apr 21, 2026 1:42pm

Request Review

Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@linear
Copy link
Copy Markdown

linear Bot commented Apr 21, 2026

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 21, 2026

🦋 Changeset detected

Latest commit: d76d232

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
dashboard Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

devin-ai-integration[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

…CallEnv.Merged

Slack tools were reading from the process env via os.LookupEnv, mixing
the pod's config with per-call env. Remove the envLookupFunc plumbing
entirely, thread toolconfig.ToolCallEnv through the token lookup, and
wire guardianPolicy.PooledClient() at both platformtoolsruntime.NewService
call sites so the registered Slack tools actually have an HTTP client
at runtime.

Adds ToolCallEnv.Merged() so the UserConfig-over-SystemEnv merge is a
single named helper. Collapses the inline merge at gateway/security.go
and uses it in Slack's token lookup.

Also addresses Devin findings: o11y.NoLogDefer for resp.Body.Close and
t.Context() in tests.

✻ Clauded...
devin-ai-integration[bot]

This comment was marked as resolved.

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 new potential issue.

View 10 additional findings in Devin Review.

Open in Devin Review

Comment on lines +27 to 51
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewReadChannelMessagesTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewReadThreadMessagesTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewReadUserProfileTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewSearchChannelsTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewSearchMessagesAndFilesTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewSearchUsersTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewScheduleMessageTool(deps.SlackHTTPClient)
},
func(deps Dependencies) PlatformToolExecutor {
return platformslack.NewSendMessageTool(deps.SlackHTTPClient)
},
}
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.

🚩 Slack tools are always registered even when no Slack token is configured

All eight Slack tools are unconditionally added to the platform tools registry at server/internal/platformtools/registry.go:27-51, regardless of whether a Slack token is configured. This means ListPlatformTools() and ListTypedTools() will advertise Slack tools to clients even when no token exists, and calling them will produce a runtime error ('slack token not configured'). This is consistent with how trigger tools behave (they're registered even when TriggerApp is nil and return errors at call time), so this appears to be a deliberate pattern — but it could lead to a poor UX where AI agents repeatedly attempt to use Slack tools that will always fail.

Open in Devin Review

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

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.

I recommend splitting this up to tool_read_channel_messages{,_test}.go, tool_search_channels{,_test}.go, etc... since it makes tools apparent to agents via the filesystem.

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.

in line with other comment rename this file to tool_search_logs.go and ultimately we'll be able to tell agents to look for tool_*.go to quickly locate platform tools.

Address review feedback: one `tool_*.go` file per Slack tool, rename
`logs/search_logs.go` to follow the same convention, and simplify the
changeset for customer-facing release notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@danielkov danielkov merged commit dc4b0f3 into main Apr 21, 2026
26 checks passed
@danielkov danielkov deleted the daniel/age-1896-platformtools-slack branch April 21, 2026 13:51
@github-actions github-actions Bot locked and limited conversation to collaborators Apr 21, 2026
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