Skip to content

feat(modal): add Modal Labs integration - #6896

Merged
icecrasher321 merged 2 commits into
stagingfrom
feat/modal-integration
Aug 20, 2026
Merged

feat(modal): add Modal Labs integration#6896
icecrasher321 merged 2 commits into
stagingfrom
feat/modal-integration

Conversation

@icecrasher321

Copy link
Copy Markdown
Collaborator

Adds a Modal block with three operations: Call Function, Chat Completion, and List Models.

Why only three operations

Modal has no public REST control plane. The Python, JS, and Go SDKs all speak gRPC to api.modal.com, and their complete docs (llms-full.txt) contain no REST API section — so Sandboxes, Apps, Volumes, and the rest of Modal's primitives simply aren't reachable from an HTTP-only tool. What is reachable is deployed Web Functions/Servers, and the OpenAI-compatible Endpoints API. That's what this covers.

Operation Endpoint
Call Function your deployed Web Function / Server URL
Chat Completion {endpoint}/v1/chat/completions
List Models {endpoint}/v1/models (defaults to the Shared Endpoint host)

Notes for review

Auth sends the proxy-token pair as Modal-Key / Modal-Secret rather than the equivalent combined Authorization: Bearer wk-….ws-…. That leaves Authorization free for a Web Function that validates its own bearer token. Required for Endpoints (always authenticated), optional for Web Functions (unauthenticated by default).

Both URL fields require https. Modal terminates TLS for .modal.run, .modal.direct, and custom domains alike, so a cleartext URL is always a misconfiguration — and one that would put the proxy token on the wire in the clear.

request.modelInput is on Chat Completion only. The system prompt and user message provably reach a model, so they project to canonical placeholders before egress. Call Function deliberately has no provenance hook: a Web Function runs arbitrary user code, and nothing proves its body reaches a model. Adding one there would be inference, not evidence.

One thing I could not verify. Modal's docs show the /v1/models curl and say it lists "model IDs", but never print the response body. data[].id is directly supported by that wording; object, created, and owned_by are inferred from OpenAI compatibility, so they're marked optional. Happy to tighten them against a live payload if someone has a token.

Behaviour worth knowing

  • A body typed for POST and then switched to GET is dropped at the tool layer, so a stale value can't ride along.
  • A function that labels its body application/json but returns something else surfaces as raw text instead of failing the call with a bare SyntaxError — that's the user's bug to see, not a reason to lose the response.
  • All three response reads are capped at 10 MiB.

Testing

38 tests across the block mapping, the URL/auth/body helpers, and call_function's response handling. The two tests covering the behaviours above were each reverted once and watched go red.

Full audit suite (32 checks), lint, and type-check all pass; generated artifacts regenerated and their diffs reviewed — every hunk is additive.

🤖 Generated with Claude Code

Modal has no public REST control plane — the Python/JS/Go SDKs all speak
gRPC — so this covers the two surfaces that are reachable over HTTP:
deployed Web Functions/Servers, and the OpenAI-compatible Endpoints API.

Three operations: call a deployed function with proxy-token auth, generate
a chat completion on an Endpoint, and list the models a token can reach.

Auth sends the token pair as Modal-Key/Modal-Secret rather than the
combined bearer form, so a Web Function that validates its own bearer
token keeps the Authorization header free. Both URL fields require https
since Modal terminates TLS everywhere, and a cleartext URL would leak the
token.

Chat completion declares request.modelInput so the system prompt and user
message project to canonical placeholders before egress. Call Function
deliberately does not — a Web Function runs arbitrary user code, and
nothing proves its body reaches a model.

/v1/models fields beyond `id` are inferred from OpenAI compatibility
rather than printed in Modal's docs, so they are marked optional.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 20, 2026 8:08pm

Request Review

@cursor

cursor Bot commented Aug 20, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
New outbound HTTP integration that stores proxy tokens and calls user-supplied HTTPS URLs. Auth and URL validation are scoped to this tool, not core product auth.

Overview
Adds a Modal tools block so workflows can reach serverless compute already running on Modal: invoke a deployed Web Function/Server over HTTPS, generate chat completions on a Modal Endpoint, and list models a proxy token can reach.

Auth uses the Modal-Key / Modal-Secret proxy-token pair (optional for Web Functions, required for Endpoints) so Authorization stays free for the function’s own bearer token. URLs must be HTTPS; endpoint calls default to https://inference.us-west.modal.direct when the URL is left blank.

Call Function drops bodies on GET/HEAD, parses JSON only when the response is labelled as such (mislabelled bodies surface as text), and caps response reads at 10 MiB. Chat Completion maps sampling params onto the OpenAI-compatible /v1 API and projects system/user messages as modelInput. Docs, icon mapping, registry, and tests land with the block.

Reviewed by Cursor Bugbot for commit 3312181. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a Modal integration supporting deployed function calls and OpenAI-compatible chat and model-listing endpoints.

  • Registers the Modal block and three tools across the block, tool, icon, documentation, and deployment registries.
  • Adds URL, authentication, request-body, response-mapping, and size-limit helpers with focused tests.
  • Replaces the previously reported explicit any payload mappings with named wire types and unknown-based request values.

Confidence Score: 5/5

The PR appears safe to merge.

The previously reported explicit-any issue is fixed at the current head, and no blocking failure remains within the eligible follow-up scope.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/modal.ts Defines and registers the Modal block’s three operations, conditional inputs, parameter mapping, outputs, templates, and skills.
apps/sim/tools/modal/call_function.ts Implements configurable HTTPS function calls with optional proxy authentication and bounded JSON-or-text response handling.
apps/sim/tools/modal/chat_completion.ts Implements OpenAI-compatible chat completions with typed response mapping and model-input provenance.
apps/sim/tools/modal/list_models.ts Implements authenticated model listing and maps Modal wire models into normalized output records.
apps/sim/tools/modal/types.ts Supplies the named request, response, and wire payload types that resolve the previous explicit-any finding.
apps/sim/tools/modal/utils.ts Centralizes HTTPS URL handling, proxy-auth headers, table conversion, and model mapping.
apps/sim/blocks/blocks/modal.test.ts Verifies operation registration, parameter mapping, defaults, conditional requirements, and stale-body handling.

Sequence Diagram

sequenceDiagram
  participant Workflow
  participant ModalBlock as Modal Block
  participant Tool as Modal Tool
  participant Endpoint as Modal HTTPS Endpoint
  Workflow->>ModalBlock: Operation and inputs
  ModalBlock->>Tool: Map operation parameters
  Tool->>Tool: Validate HTTPS URL and add proxy auth
  Tool->>Endpoint: Call function or /v1 endpoint
  Endpoint-->>Tool: Capped HTTP response
  Tool-->>Workflow: Normalized operation output
Loading

Reviews (2): Last reviewed commit: "fix(modal): type the wire payloads and d..." | Re-trigger Greptile

Comment thread apps/sim/tools/modal/chat_completion.ts Outdated
Comment thread apps/sim/blocks/blocks/modal.ts Outdated
…point

Chat Completion required an endpoint URL and passed a blank one straight
into modalOpenAiUrl, which throws — while List Models already fell back to
the shared inference host and the generate-on-modal-endpoint skill tells
agents to leave the field empty for Shared Endpoints. Skill-driven chat
calls against the shared host failed instead of using that default. Chat
now falls back the same way and the block field is no longer required.

Replaces every `any` in the Modal tools with declared wire types for the
OpenAI-compatible /v1 payloads. Fields stay optional because the shape
comes from whichever inference engine backs the endpoint, so the readers
keep their defensive `??` guards — the types exist so a future change to
that mapping fails the compiler instead of shipping.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@greptile

@icecrasher321

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor 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.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3312181. Configure here.

@icecrasher321
icecrasher321 merged commit 97c1688 into staging Aug 20, 2026
30 checks passed
@icecrasher321
icecrasher321 deleted the feat/modal-integration branch August 20, 2026 20:12
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