document Cloud tools, MCP, and multi-user identity - #813
Merged
Conversation
- SKILL.md: add an OpenUI Cloud capability matrix (Responses-compatible endpoint, out-of-box tools, artifact editing auto-enabled, fct_ storage plane) and trigger keywords for MCP / custom tools / multi-user queries - cloud-integration.md: two new runbook steps — 'Add Tools and MCP' (server-side tool table, remote MCP example, the app-owned function-tool loop contract and its two safety rules) and 'Multi-User and Multi-App Convention' (fct_ scope binding, APP_ID identity, ownership checks, brownfield recipe); mint example now sends app_id; new verify items - oss-to-cloud-migration.md: custom tool execution is now documented as supported via the template loop instead of a hard boundary
…d fixes - ship src/lib/tool-loop.ts (runFunctionToolLoop): executes only declared tool names and skips calls already answered on the stream, so app tools coexist safely with Cloud's server-side tools - add get_weather (Open-Meteo, no key) as the wired reference tool and a commented remote-MCP example in the chat route - typed missing/invalid API key errors in both routes - scaffold identity: create-app generates a stable APP_ID into .env; the frontend-token route sends it as app_id so apps sharing an org key stay isolated - default model to google/gemini-3.5-flash-free; unpin dev/start ports - pnpm.onlyBuiltDependencies for sharp/unrs-resolver (approve-builds no longer interrupts install) - ship template gitignore un-dotted and restore the real name at scaffold time (npm strips nested .gitignore files from published packages) - add default favicon
- allowlist uses Object.hasOwn so prototype-chain names (toString, constructor, ...) can never match a declared tool - round-cap exhaustion settles instead of dropping (mirrors the openai SDK runTools invariant): the last round posts outputs with tool_choice "none", and calls a non-enforcing server lets through are settled in one final forward-only turn - a stored conversation is never left holding an unanswered function_call - chat route: type createParams as ResponseCreateParamsNonStreaming and confine the cast to the Cloud-extension tool entries (artifact, image_search); no more blanket as-any - pnpm-workspace.yaml: carry the allow-build list where pnpm >=10.14 (onlyBuiltDependencies) and >=11 (allowBuilds) actually read it - the package.json pnpm field is ignored there
Both API routes import the openai SDK at request time; move it out of devDependencies so production installs (--prod, deploy platforms that prune dev deps) don't lose it.
Current conditions only — drop the 3-day forecast block and collapse the WMO code table into a small family mapper. Still a real Open-Meteo call so the reference keeps demonstrating fetch + abort signal + error-as-JSON. 130 -> 90 lines.
One regex instead of slug-trim-cap-fallback: collapse every run of non-alphanumerics to a hyphen. Edge names now produce slightly uglier ids (trailing/duplicate hyphens) but stay .env- and query-param-safe, which is the part that matters.
Both API routes carried the same inline 13-line missing-key response and requiredEnv had gone unused. apiKeyOrError() in lib/env.ts now owns the check: routes do a two-line guard, and the helper's doc comment records why this is a structured response instead of a throw (keyless scaffolds are a first-run state; a thrown Error surfaces as an opaque 500).
A keyless browser test showed the structured missing_api_key response never reaches the chat UI: the first failing call is the SDK's frontend-token mint, and its helper throws a status-only error without reading the response body. Until the SDK surfaces error bodies, the requiredEnv throw is the leaner equivalent, so env.ts and both routes go back to it. The chat route keeps its response-driven handling (429 billing message, 401/403 key guidance) — those do render, via getChatErrorMessage.
abhithesys
approved these changes
Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Describe the change and why it is needed.
Changes
Test Plan
Describe how you validated this change.
Checklist