From 3130907a081604d337ffb31cacb9359fade4ff8b Mon Sep 17 00:00:00 2001 From: amondnet <1964421+amondnet@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:24:48 +0000 Subject: [PATCH] fix: update vendored skills to latest versions --- agent/skills/create-plugin-scaffold/SKILL.md | 68 +++ plugins/ai-sdk/.agents/skills/ai-sdk/SKILL.md | 90 ++-- .../skills/ai-sdk/references/ai-gateway.md | 66 --- .../skills/ai-sdk/references/common-errors.md | 445 ------------------ .../skills/ai-sdk/references/devtools.md | 52 -- .../ai-sdk/references/type-safe-agents.md | 204 -------- plugins/ai-sdk/agent/skills/ai-sdk/SKILL.md | 90 ++-- .../skills/ai-sdk/references/ai-gateway.md | 66 --- .../skills/ai-sdk/references/common-errors.md | 445 ------------------ .../skills/ai-sdk/references/devtools.md | 52 -- .../ai-sdk/references/type-safe-agents.md | 204 -------- plugins/ai-sdk/skills-lock.json | 2 +- plugins/axi/.agents/skills/axi/SKILL.md | 16 + plugins/axi/agent/skills/axi/SKILL.md | 16 + plugins/axi/skills-lock.json | 2 +- .../emulate/.agents/skills/emulate/SKILL.md | 5 +- plugins/emulate/agent/skills/emulate/SKILL.md | 5 +- plugins/emulate/skills-lock.json | 2 +- .../greptile/agent/skills/check-pr/SKILL.md | 273 +++++++++++ .../skills/check-pr/references/gitlab-api.md | 91 ++++ .../check-pr/references/graphql-queries.md | 87 ++++ .../greptile/agent/skills/cli-review/SKILL.md | 86 ++++ .../greptile/agent/skills/greploop/SKILL.md | 422 +++++++++++++++++ .../skills/greploop/references/gitlab-api.md | 93 ++++ .../greploop/references/graphql-queries.md | 49 ++ plugins/lavish/.agents/skills/lavish/SKILL.md | 12 +- plugins/lavish/agent/skills/lavish/SKILL.md | 12 +- plugins/lavish/skills-lock.json | 2 +- .../skills/nuxt-ui/references/layouts/chat.md | 42 +- .../skills/nuxt-ui/references/layouts/chat.md | 42 +- plugins/nuxt-ui/skills-lock.json | 2 +- .../portless/.agents/skills/portless/SKILL.md | 99 ++-- .../portless/agent/skills/portless/SKILL.md | 99 ++-- plugins/portless/skills-lock.json | 2 +- .../.agents/skills/turborepo/SKILL.md | 4 +- .../references/best-practices/structure.md | 4 +- .../references/configuration/RULE.md | 4 +- .../turborepo/references/environment/RULE.md | 2 +- .../references/environment/gotchas.md | 4 +- .../turborepo/agent/skills/turborepo/SKILL.md | 4 +- .../references/best-practices/structure.md | 4 +- .../references/configuration/RULE.md | 4 +- .../turborepo/references/environment/RULE.md | 2 +- .../references/environment/gotchas.md | 4 +- plugins/turborepo/skills-lock.json | 2 +- .../.agents/skills/sandbox/SKILL.md | 32 ++ .../agent/skills/sandbox/SKILL.md | 32 ++ plugins/vercel-sandbox/skills-lock.json | 2 +- plugins/web-design/skills-lock.json | 2 +- .../references/search-replace.md | 2 +- .../references/search-replace.md | 2 +- plugins/wordpress/skills-lock.json | 2 +- plugins/workflow-sdk/skills-lock.json | 6 +- 53 files changed, 1560 insertions(+), 1801 deletions(-) create mode 100644 agent/skills/create-plugin-scaffold/SKILL.md delete mode 100644 plugins/ai-sdk/.agents/skills/ai-sdk/references/ai-gateway.md delete mode 100644 plugins/ai-sdk/.agents/skills/ai-sdk/references/common-errors.md delete mode 100644 plugins/ai-sdk/.agents/skills/ai-sdk/references/devtools.md delete mode 100644 plugins/ai-sdk/.agents/skills/ai-sdk/references/type-safe-agents.md delete mode 100644 plugins/ai-sdk/agent/skills/ai-sdk/references/ai-gateway.md delete mode 100644 plugins/ai-sdk/agent/skills/ai-sdk/references/common-errors.md delete mode 100644 plugins/ai-sdk/agent/skills/ai-sdk/references/devtools.md delete mode 100644 plugins/ai-sdk/agent/skills/ai-sdk/references/type-safe-agents.md create mode 100644 plugins/greptile/agent/skills/check-pr/SKILL.md create mode 100644 plugins/greptile/agent/skills/check-pr/references/gitlab-api.md create mode 100644 plugins/greptile/agent/skills/check-pr/references/graphql-queries.md create mode 100644 plugins/greptile/agent/skills/cli-review/SKILL.md create mode 100644 plugins/greptile/agent/skills/greploop/SKILL.md create mode 100644 plugins/greptile/agent/skills/greploop/references/gitlab-api.md create mode 100644 plugins/greptile/agent/skills/greploop/references/graphql-queries.md diff --git a/agent/skills/create-plugin-scaffold/SKILL.md b/agent/skills/create-plugin-scaffold/SKILL.md new file mode 100644 index 00000000..5c6e66ba --- /dev/null +++ b/agent/skills/create-plugin-scaffold/SKILL.md @@ -0,0 +1,68 @@ +--- +description: "Create a new Cursor plugin scaffold with a valid manifest, component directories, and marketplace wiring. Use when starting a new plugin or adding a plugin to a multi-plugin repository." +--- +# Create plugin scaffold + +## Trigger + +You need to create a new Cursor plugin from scratch and make it ready for local use or marketplace submission. + +## Required Inputs + +- Plugin name (lowercase kebab-case) +- Plugin purpose and target users +- Component set to include (`rules`, `skills`, `agents`, `commands`, `hooks`, `mcpServers`) +- Repository style (`single-plugin` or `multi-plugin marketplace`) + +## Output Location + +By default, create the plugin inside the user's local plugin directory: + +``` +~/.cursor/plugins/local// +``` + +This path makes the plugin immediately available to Cursor without any install step. If the user explicitly asks to create the plugin elsewhere (e.g. inside an existing repo or a specific directory), respect that choice instead. + +## Workflow + +1. Validate plugin name format: lowercase kebab-case, starts and ends with an alphanumeric character. +2. Determine the target directory: + - Default: `~/.cursor/plugins/local//` + - Override: use the path the user specifies, if any. + - Create the directory (and parents) if it does not exist. +3. Create base files inside the target directory: + - `.cursor-plugin/plugin.json` + - `README.md` + - `LICENSE` + - optional `CHANGELOG.md` +4. Populate `plugin.json`: + - Required: `name` + - Recommended: `version`, `description`, `author`, `license`, `keywords` + - Add explicit component paths only when non-default discovery is needed. +5. Create component files with valid frontmatter: + - Rules: `.mdc` with `description`, `alwaysApply`, optional `globs` + - Skills: `skills//SKILL.md` with `name`, `description` + - Agents: `agents/*.md` with `name`, `description` + - Commands: `commands/*.(md|txt)` with `name`, `description` +6. If repository uses `.cursor-plugin/marketplace.json`, add plugin entry: + - `name` + - `source` + - optional metadata (`description`, `keywords`, `category`, `tags`) +7. Ensure all manifest paths are relative, valid, and do not use absolute paths or parent traversal. + +## Guardrails + +- Keep the plugin focused on one use case. +- Prefer concise, actionable skill and rule text over long prose. +- Do not reference files that do not exist. +- Use folder discovery defaults unless custom paths are required. +- Always save to `~/.cursor/plugins/local//` unless the user provides a different path. + +## Output + +- Created file tree for the plugin (with full path to the output directory) +- Final `plugin.json` +- Marketplace entry (if applicable) +- Short validation report of required fields and component metadata +- Confirmation that the plugin is saved under `~/.cursor/plugins/local/` and ready for use diff --git a/plugins/ai-sdk/.agents/skills/ai-sdk/SKILL.md b/plugins/ai-sdk/.agents/skills/ai-sdk/SKILL.md index e0e4064a..038ecd17 100644 --- a/plugins/ai-sdk/.agents/skills/ai-sdk/SKILL.md +++ b/plugins/ai-sdk/.agents/skills/ai-sdk/SKILL.md @@ -3,78 +3,76 @@ name: ai-sdk description: 'Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: "AI SDK", "Vercel AI SDK", "generateText", "streamText", "add AI to my app", "build an agent", "tool calling", "structured output", "useChat".' --- -## Prerequisites +## What the AI SDK Is -This information is for AI SDK 7. Compare to version in `node_modules/ai/package.json`. If the versions don't match, warn the user. +The AI SDK by Vercel (the `ai` package on npm) is a TypeScript toolkit for building AI applications. It provides a unified API across model providers for text generation, structured output, tool calling, agents, embeddings, and framework UI integrations. -Before searching docs, check if `node_modules/ai/docs/` exists. If not, install **only** the `ai` package using the project's package manager (e.g., `pnpm add ai`). +- Repository: https://github.com/vercel/ai +- Documentation: https://ai-sdk.dev/docs -Do not install other packages at this stage. Provider packages (e.g., `@ai-sdk/openai`) and client packages (e.g., `@ai-sdk/react`) should be installed later when needed based on user requirements. +## Critical: Do Not Trust Your Own Memory -## Critical: Do Not Trust Internal Knowledge +Whatever you remember about the AI SDK is likely outdated. The SDK changes frequently across versions - APIs are renamed, removed, and added. Your training data almost certainly contains obsolete APIs, deprecated patterns, and model IDs that no longer exist. UI hooks like `useChat` are among the most frequently changed APIs, so be especially careful with client code. -Everything you know about the AI SDK is outdated or wrong. Your training data contains obsolete APIs, deprecated patterns, and incorrect usage. +**Never write AI SDK code from memory.** Always verify every API, option, and pattern against the documentation and source code for the version that is actually installed in the project. -**When working with the AI SDK:** +## Use the Bundled, Version-Matched Docs -1. Ensure `ai` package is installed (see Prerequisites) -2. Search `node_modules/ai/docs/` and `node_modules/ai/src/` for current APIs -3. If not found locally, search ai-sdk.dev documentation (instructions below) -4. Never rely on memory - always verify against source code or docs -5. **`useChat` has changed significantly** - check [Common Errors](references/common-errors.md) before writing client code -6. When deciding which model and provider to use (e.g. OpenAI, Anthropic, Gemini), use the Vercel AI Gateway provider unless the user specifies otherwise. See [AI Gateway Reference](references/ai-gateway.md) for usage details. -7. **Always fetch current model IDs** - Never use model IDs from memory. Before writing code that uses a model, run `curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("provider/")) | .id] | reverse | .[]'` (replacing `provider` with the relevant provider like `anthropic`, `openai`, or `google`) to get the full list with newest models first. Use the model with the highest version number (e.g., `claude-sonnet-4-5` over `claude-sonnet-4` over `claude-3-5-sonnet`). -8. Run typecheck after changes to ensure code is correct -9. **Be minimal** - Only specify options that differ from defaults. When unsure of defaults, check docs or source rather than guessing or over-specifying. +The `ai` package ships its full documentation and source code inside `node_modules`. These always match the installed version, so trust them over anything you remember. -If you cannot find documentation to support your answer, state that explicitly. +1. Ensure `ai` is installed. If `node_modules/ai/` does not exist, install **only** the `ai` package using the project's package manager (e.g. `pnpm add ai`). Install provider packages (e.g. `@ai-sdk/openai`) and framework packages (e.g. `@ai-sdk/react`) later, when the task requires them. +2. Read and grep the bundled docs at `node_modules/ai/docs/` and the source at `node_modules/ai/src/`. +3. Provider and framework packages bundle their own docs at `node_modules/@ai-sdk//docs/`. +4. If something isn't in the bundled docs, search https://ai-sdk.dev/docs. You can append `.md` to any docs page URL to get its markdown, and search via `https://ai-sdk.dev/api/search-docs?q=your_query`. +5. If you cannot find support for an answer in the docs or source, say so explicitly — do not guess. -## Finding Documentation +## AI Gateway: The Fastest Way to Start -### ai@6.0.34+ +The Vercel AI Gateway is the fastest way to get started with the AI SDK. It provides access to models from OpenAI, Anthropic, Google, and other providers through a single API, without installing provider packages or managing multiple API keys. -Search bundled docs and source in `node_modules/ai/`: +To set it up: -- **Docs**: `grep "query" node_modules/ai/docs/` -- **Source**: `grep "query" node_modules/ai/src/` +1. Authenticate with OIDC (for Vercel deployments) or get an AI Gateway API key. +2. Provide it to your app via the `AI_GATEWAY_API_KEY` environment variable. +3. Reference models with `provider/model` strings. -Provider packages include docs at `node_modules/@ai-sdk//docs/`. +For exact setup, authentication, and usage, read the bundled guide and the AI Gateway docs. -### Earlier versions +### Choosing a Model -1. Search: `https://ai-sdk.dev/api/search-docs?q=your_query` -2. Fetch `.md` URLs from results (e.g., `https://ai-sdk.dev/docs/agents/building-agents.md`) +Never use model IDs from memory — models are released and retired frequently. Fetch the current list before writing code that references a model. Do not truncate the list (e.g. with `head`) so you can find the newest models: -## When Typecheck Fails +```bash +# All available models +curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '.data[].id' -**Before searching source code**, grep [Common Errors](references/common-errors.md) for the failing property or function name. Many type errors are caused by deprecated APIs documented there. +# Filter by provider (e.g. anthropic, openai, google) +curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("anthropic/")) | .id] | reverse | .[]' +``` -If not found in common-errors.md: - -1. Search `node_modules/ai/src/` and `node_modules/ai/docs/` -2. Search ai-sdk.dev (for earlier versions or if not found locally) +When multiple versions of a model exist, prefer the one with the highest version number. ## Building and Consuming Agents -### Creating Agents +Use the SDK's built-in agent abstraction (such as `ToolLoopAgent`) rather than hand-rolling tool-calling loops. For end-to-end type safety, infer the UI message type from your agent definition when consuming it on the client (e.g. with `useChat`). Consuming an agent is framework-specific: check `package.json` to detect the stack, then follow the matching quickstart. + +Look up the current agent, tool, and type-safety APIs in the bundled docs (`node_modules/ai/docs/`, especially the agents section) or at https://ai-sdk.dev/docs. + +## DevTools -Always use the `ToolLoopAgent` pattern. Search `node_modules/ai/docs/` for current agent creation APIs. +AI SDK DevTools captures your AI SDK calls - requests, responses, tool calls, token usage, and multi-step runs - so you can inspect exactly what your agents do. Use it while developing to debug generations. It is a separate package and is intended for local development only. -**File conventions**: See [type-safe-agents.md](references/type-safe-agents.md) for where to save agents and tools. +For setup instructions, read the bundled DevTools documentation. -**Type Safety**: When consuming agents with `useChat`, always use `InferAgentUIMessage` for type-safe tool results. See [reference](references/type-safe-agents.md). +## Keep the SDK Current -### Consuming Agents (Framework-Specific) +Outdated installs are the most common source of errors. Compare the installed version against the latest: -Before implementing agent consumption: +- **Installed:** the `version` field in `node_modules/ai/package.json`. +- **Latest:** run `npm view ai version`. -1. Check `package.json` to detect the project's framework/stack -2. Search documentation for the framework's quickstart guide -3. Follow the framework-specific patterns for streaming, API routes, and client integration +If the installed version is a major version (or more) behind the latest, tell the user they are on an old release, and recommend upgrading before continuing. Migration guides are at https://ai-sdk.dev/docs/migration-guides. -## References +## After Making Changes -- [Common Errors](references/common-errors.md) - Renamed parameters reference (parameters → inputSchema, etc.) -- [AI Gateway](references/ai-gateway.md) - Gateway setup and usage -- [Type-Safe Agents with useChat](references/type-safe-agents.md) - End-to-end type safety with InferAgentUIMessage -- [DevTools](references/devtools.md) - Set up local debugging and observability (development only) +Run the project's type checker. Be minimal — only set options that differ from the defaults, checking docs or source for the defaults rather than over-specifying. Most type errors come from remembered, now-changed APIs; re-check the current docs and source when they occur. diff --git a/plugins/ai-sdk/.agents/skills/ai-sdk/references/ai-gateway.md b/plugins/ai-sdk/.agents/skills/ai-sdk/references/ai-gateway.md deleted file mode 100644 index d0144b17..00000000 --- a/plugins/ai-sdk/.agents/skills/ai-sdk/references/ai-gateway.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Vercel AI Gateway -description: Reference for using Vercel AI Gateway with the AI SDK. ---- - -# Vercel AI Gateway - -The Vercel AI Gateway is the fastest way to get started with the AI SDK. It provides access to models from OpenAI, Anthropic, Google, and other providers through a single API. - -## Authentication - -Authenticate with OIDC (for Vercel deployments) or an [AI Gateway API key](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway%2Fapi-keys&title=AI+Gateway+API+Keys): - -```env filename=".env.local" -AI_GATEWAY_API_KEY=your_api_key_here -``` - -## Usage - -The AI Gateway is the default global provider, so you can access models using a simple string: - -```ts -import { generateText } from 'ai'; - -const { text } = await generateText({ - model: 'anthropic/claude-sonnet-4.5', - prompt: 'What is love?', -}); -``` - -You can also explicitly import and use the gateway provider: - -```ts -// Option 1: Import from 'ai' package (included by default) -import { gateway } from 'ai'; -model: gateway('anthropic/claude-sonnet-4.5'); - -// Option 2: Install and import from '@ai-sdk/gateway' package -import { gateway } from '@ai-sdk/gateway'; -model: gateway('anthropic/claude-sonnet-4.5'); -``` - -## Find Available Models - -**Important**: Always fetch the current model list before writing code. Never use model IDs from memory - they may be outdated. - -List all available models through the gateway API: - -```bash -curl https://ai-gateway.vercel.sh/v1/models -``` - -Filter by provider using `jq`. **Do not truncate with `head`** - always fetch the full list to find the latest models: - -```bash -# Anthropic models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("anthropic/")) | .id] | reverse | .[]' - -# OpenAI models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("openai/")) | .id] | reverse | .[]' - -# Google models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("google/")) | .id] | reverse | .[]' -``` - -When multiple versions of a model exist, use the one with the highest version number (e.g., prefer `anthropic/claude-sonnet-4.6` over `anthropic/claude-sonnet-4.5` over `claude-sonnet-4`). diff --git a/plugins/ai-sdk/.agents/skills/ai-sdk/references/common-errors.md b/plugins/ai-sdk/.agents/skills/ai-sdk/references/common-errors.md deleted file mode 100644 index f2d289aa..00000000 --- a/plugins/ai-sdk/.agents/skills/ai-sdk/references/common-errors.md +++ /dev/null @@ -1,445 +0,0 @@ ---- -title: Common Errors -description: Reference for common AI SDK errors and how to resolve them. ---- - -# Common Errors - -## `maxTokens` → `maxOutputTokens` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - maxTokens: 512, // deprecated: use `maxOutputTokens` instead - prompt: 'Write a short story', -}); - -// ✅ Correct -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - maxOutputTokens: 512, - prompt: 'Write a short story', -}); -``` - -## `maxSteps` → `stopWhen: isStepCount(n)` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - tools: { weather }, - maxSteps: 5, // deprecated: use `stopWhen: isStepCount(n)` instead - prompt: 'What is the weather in NYC?', -}); - -// ✅ Correct -import { generateText, isStepCount } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - tools: { weather }, - stopWhen: isStepCount(5), - prompt: 'What is the weather in NYC?', -}); -``` - -## `parameters` → `inputSchema` (in tool definition) - -```typescript -// ❌ Incorrect -const weatherTool = tool({ - description: 'Get weather for a location', - parameters: z.object({ - // deprecated: use `inputSchema` instead - location: z.string(), - }), - execute: async ({ location }) => ({ location, temp: 72 }), -}); - -// ✅ Correct -const weatherTool = tool({ - description: 'Get weather for a location', - inputSchema: z.object({ - location: z.string(), - }), - execute: async ({ location }) => ({ location, temp: 72 }), -}); -``` - -## `generateObject` → `generateText` with `output` - -`generateObject` is deprecated. Use `generateText` with the `output` option instead. - -```typescript -// ❌ Deprecated -import { generateObject } from 'ai'; // deprecated: use `generateText` with `output` instead - -const result = await generateObject({ - // deprecated function - model: 'anthropic/claude-opus-4.5', - schema: z.object({ - // deprecated: use `Output.object({ schema })` instead - recipe: z.object({ - name: z.string(), - ingredients: z.array(z.string()), - }), - }), - prompt: 'Generate a recipe for chocolate cake', -}); - -// ✅ Correct -import { generateText, Output } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.object({ - schema: z.object({ - recipe: z.object({ - name: z.string(), - ingredients: z.array(z.string()), - }), - }), - }), - prompt: 'Generate a recipe for chocolate cake', -}); - -console.log(result.output); // typed object -``` - -## Manual JSON parsing → `generateText` with `output` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - prompt: `Extract the user info as JSON: { "name": string, "age": number } - - Input: John is 25 years old`, -}); -const parsed = JSON.parse(result.text); - -// ✅ Correct -import { generateText, Output } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.object({ - schema: z.object({ - name: z.string(), - age: z.number(), - }), - }), - prompt: 'Extract the user info: John is 25 years old', -}); - -console.log(result.output); // { name: 'John', age: 25 } -``` - -## Other `output` options - -```typescript -// Output.array - for generating arrays of items -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.array({ - element: z.object({ - city: z.string(), - country: z.string(), - }), - }), - prompt: 'List 5 capital cities', -}); - -// Output.choice - for selecting from predefined options -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.choice({ - options: ['positive', 'negative', 'neutral'] as const, - }), - prompt: 'Classify the sentiment: I love this product!', -}); - -// Output.json - for untyped JSON output -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.json(), - prompt: 'Return some JSON data', -}); -``` - -## `toDataStreamResponse` → `createUIMessageStreamResponse` - -When using `useChat` on the frontend, use `createUIMessageStreamResponse()` with `toUIMessageStream()` instead of `toDataStreamResponse()`. The UI message stream format is designed to work with the chat UI components and handles message state correctly. - -```typescript -// ❌ Incorrect (when using useChat) -const result = streamText({ - // config -}); - -return result.toDataStreamResponse(); // deprecated for useChat: use createUIMessageStreamResponse - -// ✅ Correct -const result = streamText({ - // config -}); - -return createUIMessageStreamResponse({ - stream: toUIMessageStream({ stream: result.stream }), -}); -``` - -## Removed managed input state in `useChat` - -The `useChat` hook no longer manages input state internally. You must now manage input state manually. - -```tsx -// ❌ Deprecated -import { useChat } from '@ai-sdk/react'; - -export default function Page() { - const { - input, // deprecated: manage input state manually with useState - handleInputChange, // deprecated: use custom onChange handler - handleSubmit, // deprecated: use sendMessage() instead - } = useChat({ - api: '/api/chat', // deprecated: use `transport: new DefaultChatTransport({ api })` instead - }); - - return ( -
- - -
- ); -} - -// ✅ Correct -import { useChat } from '@ai-sdk/react'; -import { DefaultChatTransport } from 'ai'; -import { useState } from 'react'; - -export default function Page() { - const [input, setInput] = useState(''); - const { sendMessage } = useChat({ - transport: new DefaultChatTransport({ api: '/api/chat' }), - }); - - const handleSubmit = e => { - e.preventDefault(); - sendMessage({ text: input }); - setInput(''); - }; - - return ( -
- setInput(e.target.value)} /> - -
- ); -} -``` - -## `tool-invocation` → `tool-{toolName}` (typed tool parts) - -When rendering messages with `useChat`, use the typed tool part names (`tool-{toolName}`) instead of the generic `tool-invocation` type. This provides better type safety and access to tool-specific input/output types. - -> For end-to-end type-safety, see [Type-Safe Agents](type-safe-agents.md). - -Typed tool parts also use different property names: - -- `part.args` → `part.input` -- `part.result` → `part.output` - -```tsx -// ❌ Incorrect - using generic tool-invocation -{ - message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return
{part.text}
; - case 'tool-invocation': // deprecated: use typed tool parts instead - return ( -
-            {JSON.stringify(part.toolInvocation, null, 2)}
-          
- ); - } - }); -} - -// ✅ Correct - using typed tool parts (recommended) -{ - message.parts.map(part => { - switch (part.type) { - case 'text': - return part.text; - case 'tool-askForConfirmation': - // handle askForConfirmation tool - break; - case 'tool-getWeatherInformation': - // handle getWeatherInformation tool - break; - } - }); -} - -// ✅ Alternative - using isToolUIPart as a catch-all -import { isToolUIPart } from 'ai'; - -{ - message.parts.map(part => { - if (part.type === 'text') { - return part.text; - } - if (isToolUIPart(part)) { - // handle any tool part generically - return ( -
- {part.toolName}: {part.state} -
- ); - } - }); -} -``` - -## `useChat` state-dependent property access - -Tool part properties are only available in certain states. TypeScript will error if you access them without checking state first. - -```tsx -// ❌ Incorrect - input may be undefined during streaming -// TS18048: 'part.input' is possibly 'undefined' -if (part.type === 'tool-getWeather') { - const location = part.input.location; -} - -// ✅ Correct - check for input-available or output-available -if ( - part.type === 'tool-getWeather' && - (part.state === 'input-available' || part.state === 'output-available') -) { - const location = part.input.location; -} - -// ❌ Incorrect - output is only available after execution -// TS18048: 'part.output' is possibly 'undefined' -if (part.type === 'tool-getWeather') { - const weather = part.output; -} - -// ✅ Correct - check for output-available -if (part.type === 'tool-getWeather' && part.state === 'output-available') { - const location = part.input.location; - const weather = part.output; -} -``` - -## `part.toolInvocation.args` → `part.input` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.input` on typed tool parts instead - const location = part.toolInvocation.args.location; -} - -// ✅ Correct -if ( - part.type === 'tool-getWeather' && - (part.state === 'input-available' || part.state === 'output-available') -) { - const location = part.input.location; -} -``` - -## `part.toolInvocation.result` → `part.output` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.output` on typed tool parts instead - const weather = part.toolInvocation.result; -} - -// ✅ Correct -if (part.type === 'tool-getWeather' && part.state === 'output-available') { - const weather = part.output; -} -``` - -## `part.toolInvocation.toolCallId` → `part.toolCallId` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.toolCallId` on typed tool parts instead - const id = part.toolInvocation.toolCallId; -} - -// ✅ Correct -if (part.type === 'tool-getWeather') { - const id = part.toolCallId; -} -``` - -## Tool invocation states renamed - -```tsx -// ❌ Incorrect -switch (part.toolInvocation.state) { - case 'partial-call': // deprecated: use `input-streaming` instead - return
Loading...
; - case 'call': // deprecated: use `input-available` instead - return
Executing...
; - case 'result': // deprecated: use `output-available` instead - return
Done
; -} - -// ✅ Correct -switch (part.state) { - case 'input-streaming': - return
Loading...
; - case 'input-available': - return
Executing...
; - case 'output-available': - return
Done
; -} -``` - -## `addToolResult` → `addToolOutput` - -```tsx -// ❌ Incorrect -addToolResult({ - // deprecated: use `addToolOutput` instead - toolCallId: part.toolInvocation.toolCallId, - result: 'Yes, confirmed.', // deprecated: use `output` instead -}); - -// ✅ Correct -addToolOutput({ - tool: 'askForConfirmation', - toolCallId: part.toolCallId, - output: 'Yes, confirmed.', -}); -``` - -## `messages` → `uiMessages` in `createAgentUIStreamResponse` - -```typescript -// ❌ Incorrect -return createAgentUIStreamResponse({ - agent: myAgent, - messages, // incorrect: use `uiMessages` instead -}); - -// ✅ Correct -return createAgentUIStreamResponse({ - agent: myAgent, - uiMessages: messages, -}); -``` diff --git a/plugins/ai-sdk/.agents/skills/ai-sdk/references/devtools.md b/plugins/ai-sdk/.agents/skills/ai-sdk/references/devtools.md deleted file mode 100644 index 197e203a..00000000 --- a/plugins/ai-sdk/.agents/skills/ai-sdk/references/devtools.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: AI SDK DevTools -description: Debug AI SDK calls by inspecting captured runs and steps. ---- - -# AI SDK DevTools - -## Why Use DevTools - -DevTools captures all AI SDK calls (`generateText`, `streamText`, `ToolLoopAgent`) to a local JSON file. This lets you inspect LLM requests, responses, tool calls, and multi-step interactions without manually logging. - -## Setup - -Requires AI SDK 6. Install `@ai-sdk/devtools` using your project's package manager. - -Wrap your model with the middleware: - -```ts -import { wrapLanguageModel, gateway } from 'ai'; -import { devToolsMiddleware } from '@ai-sdk/devtools'; - -const model = wrapLanguageModel({ - model: gateway('anthropic/claude-sonnet-4.5'), - middleware: devToolsMiddleware(), -}); -``` - -## Viewing Captured Data - -All runs and steps are saved to: - -``` -.devtools/generations.json -``` - -Read this file directly to inspect captured data: - -```bash -cat .devtools/generations.json | jq -``` - -Or launch the web UI: - -```bash -npx @ai-sdk/devtools -# Open http://localhost:4983 -``` - -## Data Structure - -- **Run**: A complete multi-step interaction grouped by initial prompt -- **Step**: A single LLM call within a run (includes input, output, tool calls, token usage) diff --git a/plugins/ai-sdk/.agents/skills/ai-sdk/references/type-safe-agents.md b/plugins/ai-sdk/.agents/skills/ai-sdk/references/type-safe-agents.md deleted file mode 100644 index 17d7a6fd..00000000 --- a/plugins/ai-sdk/.agents/skills/ai-sdk/references/type-safe-agents.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: Type-Safe useChat with Agents -description: Build end-to-end type-safe agents by inferring UIMessage types from your agent definition. ---- - -# Type-Safe useChat with Agents - -Build end-to-end type-safe agents by inferring `UIMessage` types from your agent definition for type-safe UI rendering with `useChat`. - -## Recommended Structure - -``` -lib/ - agents/ - my-agent.ts # Agent definition + type export - tools/ - weather-tool.ts # Individual tool definitions - calculator-tool.ts -``` - -## Define Tools - -```ts -// lib/tools/weather-tool.ts -import { tool } from 'ai'; -import { z } from 'zod'; - -export const weatherTool = tool({ - description: 'Get current weather for a location', - inputSchema: z.object({ - location: z.string().describe('City name'), - }), - execute: async ({ location }) => { - return { temperature: 72, condition: 'sunny', location }; - }, -}); -``` - -## Define Agent and Export Type - -```ts -// lib/agents/my-agent.ts -import { ToolLoopAgent, InferAgentUIMessage } from 'ai'; -import { weatherTool } from '../tools/weather-tool'; -import { calculatorTool } from '../tools/calculator-tool'; - -export const myAgent = new ToolLoopAgent({ - model: 'anthropic/claude-sonnet-4', - instructions: 'You are a helpful assistant.', - tools: { - weather: weatherTool, - calculator: calculatorTool, - }, -}); - -// Infer the UIMessage type from the agent -export type MyAgentUIMessage = InferAgentUIMessage; -``` - -### With Custom Metadata - -```ts -// lib/agents/my-agent.ts -import { z } from 'zod'; - -const metadataSchema = z.object({ - createdAt: z.number(), - model: z.string().optional(), -}); - -type MyMetadata = z.infer; - -export type MyAgentUIMessage = InferAgentUIMessage; -``` - -## Use with `useChat` - -```tsx -// app/chat.tsx -import { useChat } from '@ai-sdk/react'; -import type { MyAgentUIMessage } from '@/lib/agents/my-agent'; - -export function Chat() { - const { messages } = useChat(); - - return ( -
- {messages.map(message => ( - - ))} -
- ); -} -``` - -## Rendering Parts with Type Safety - -Tool parts are typed as `tool-{toolName}` based on your agent's tools: - -```tsx -function Message({ message }: { message: MyAgentUIMessage }) { - return ( -
- {message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return

{part.text}

; - - case 'tool-weather': - // part.input and part.output are fully typed - if (part.state === 'output-available') { - return ( -
- Weather in {part.input.location}: {part.output.temperature}F -
- ); - } - return
Loading weather...
; - - case 'tool-calculator': - // TypeScript knows this is the calculator tool - return
Calculating...
; - - default: - return null; - } - })} -
- ); -} -``` - -The `part.type` discriminant narrows the type, giving you autocomplete and type checking for `input` and `output` based on each tool's schema. - -## Splitting Tool Rendering into Components - -When rendering many tools, you may want to split each tool into its own component. Use `UIToolInvocation` to derive a typed invocation from your tool and export it alongside the tool definition: - -```ts -// lib/tools/weather-tool.ts -import { tool, UIToolInvocation } from 'ai'; -import { z } from 'zod'; - -export const weatherTool = tool({ - description: 'Get current weather for a location', - inputSchema: z.object({ - location: z.string().describe('City name'), - }), - execute: async ({ location }) => { - return { temperature: 72, condition: 'sunny', location }; - }, -}); - -// Export the invocation type for use in UI components -export type WeatherToolInvocation = UIToolInvocation; -``` - -Then import only the type in your component: - -```tsx -// components/weather-tool.tsx -import type { WeatherToolInvocation } from '@/lib/tools/weather-tool'; - -export function WeatherToolComponent({ - invocation, -}: { - invocation: WeatherToolInvocation; -}) { - // invocation.input and invocation.output are fully typed - if (invocation.state === 'output-available') { - return ( -
- Weather in {invocation.input.location}: {invocation.output.temperature}F -
- ); - } - return
Loading weather for {invocation.input?.location}...
; -} -``` - -Use the component in your message renderer: - -```tsx -function Message({ message }: { message: MyAgentUIMessage }) { - return ( -
- {message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return

{part.text}

; - case 'tool-weather': - return ; - case 'tool-calculator': - return ; - default: - return null; - } - })} -
- ); -} -``` - -This approach keeps your tool rendering logic organized while maintaining full type safety, without needing to import the tool implementation into your UI components. diff --git a/plugins/ai-sdk/agent/skills/ai-sdk/SKILL.md b/plugins/ai-sdk/agent/skills/ai-sdk/SKILL.md index 9ca0a1c0..edb003be 100644 --- a/plugins/ai-sdk/agent/skills/ai-sdk/SKILL.md +++ b/plugins/ai-sdk/agent/skills/ai-sdk/SKILL.md @@ -1,78 +1,76 @@ --- description: "Answer questions about the AI SDK and help build AI-powered features. Use when developers: (1) Ask about AI SDK functions like generateText, streamText, ToolLoopAgent, embed, or tools, (2) Want to build AI agents, chatbots, RAG systems, or text generation features, (3) Have questions about AI providers (OpenAI, Anthropic, Google, etc.), streaming, tool calling, structured output, or embeddings, (4) Use React hooks like useChat or useCompletion. Triggers on: \"AI SDK\", \"Vercel AI SDK\", \"generateText\", \"streamText\", \"add AI to my app\", \"build an agent\", \"tool calling\", \"structured output\", \"useChat\"." --- -## Prerequisites +## What the AI SDK Is -This information is for AI SDK 7. Compare to version in `node_modules/ai/package.json`. If the versions don't match, warn the user. +The AI SDK by Vercel (the `ai` package on npm) is a TypeScript toolkit for building AI applications. It provides a unified API across model providers for text generation, structured output, tool calling, agents, embeddings, and framework UI integrations. -Before searching docs, check if `node_modules/ai/docs/` exists. If not, install **only** the `ai` package using the project's package manager (e.g., `pnpm add ai`). +- Repository: https://github.com/vercel/ai +- Documentation: https://ai-sdk.dev/docs -Do not install other packages at this stage. Provider packages (e.g., `@ai-sdk/openai`) and client packages (e.g., `@ai-sdk/react`) should be installed later when needed based on user requirements. +## Critical: Do Not Trust Your Own Memory -## Critical: Do Not Trust Internal Knowledge +Whatever you remember about the AI SDK is likely outdated. The SDK changes frequently across versions - APIs are renamed, removed, and added. Your training data almost certainly contains obsolete APIs, deprecated patterns, and model IDs that no longer exist. UI hooks like `useChat` are among the most frequently changed APIs, so be especially careful with client code. -Everything you know about the AI SDK is outdated or wrong. Your training data contains obsolete APIs, deprecated patterns, and incorrect usage. +**Never write AI SDK code from memory.** Always verify every API, option, and pattern against the documentation and source code for the version that is actually installed in the project. -**When working with the AI SDK:** +## Use the Bundled, Version-Matched Docs -1. Ensure `ai` package is installed (see Prerequisites) -2. Search `node_modules/ai/docs/` and `node_modules/ai/src/` for current APIs -3. If not found locally, search ai-sdk.dev documentation (instructions below) -4. Never rely on memory - always verify against source code or docs -5. **`useChat` has changed significantly** - check [Common Errors](references/common-errors.md) before writing client code -6. When deciding which model and provider to use (e.g. OpenAI, Anthropic, Gemini), use the Vercel AI Gateway provider unless the user specifies otherwise. See [AI Gateway Reference](references/ai-gateway.md) for usage details. -7. **Always fetch current model IDs** - Never use model IDs from memory. Before writing code that uses a model, run `curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("provider/")) | .id] | reverse | .[]'` (replacing `provider` with the relevant provider like `anthropic`, `openai`, or `google`) to get the full list with newest models first. Use the model with the highest version number (e.g., `claude-sonnet-4-5` over `claude-sonnet-4` over `claude-3-5-sonnet`). -8. Run typecheck after changes to ensure code is correct -9. **Be minimal** - Only specify options that differ from defaults. When unsure of defaults, check docs or source rather than guessing or over-specifying. +The `ai` package ships its full documentation and source code inside `node_modules`. These always match the installed version, so trust them over anything you remember. -If you cannot find documentation to support your answer, state that explicitly. +1. Ensure `ai` is installed. If `node_modules/ai/` does not exist, install **only** the `ai` package using the project's package manager (e.g. `pnpm add ai`). Install provider packages (e.g. `@ai-sdk/openai`) and framework packages (e.g. `@ai-sdk/react`) later, when the task requires them. +2. Read and grep the bundled docs at `node_modules/ai/docs/` and the source at `node_modules/ai/src/`. +3. Provider and framework packages bundle their own docs at `node_modules/@ai-sdk//docs/`. +4. If something isn't in the bundled docs, search https://ai-sdk.dev/docs. You can append `.md` to any docs page URL to get its markdown, and search via `https://ai-sdk.dev/api/search-docs?q=your_query`. +5. If you cannot find support for an answer in the docs or source, say so explicitly — do not guess. -## Finding Documentation +## AI Gateway: The Fastest Way to Start -### ai@6.0.34+ +The Vercel AI Gateway is the fastest way to get started with the AI SDK. It provides access to models from OpenAI, Anthropic, Google, and other providers through a single API, without installing provider packages or managing multiple API keys. -Search bundled docs and source in `node_modules/ai/`: +To set it up: -- **Docs**: `grep "query" node_modules/ai/docs/` -- **Source**: `grep "query" node_modules/ai/src/` +1. Authenticate with OIDC (for Vercel deployments) or get an AI Gateway API key. +2. Provide it to your app via the `AI_GATEWAY_API_KEY` environment variable. +3. Reference models with `provider/model` strings. -Provider packages include docs at `node_modules/@ai-sdk//docs/`. +For exact setup, authentication, and usage, read the bundled guide and the AI Gateway docs. -### Earlier versions +### Choosing a Model -1. Search: `https://ai-sdk.dev/api/search-docs?q=your_query` -2. Fetch `.md` URLs from results (e.g., `https://ai-sdk.dev/docs/agents/building-agents.md`) +Never use model IDs from memory — models are released and retired frequently. Fetch the current list before writing code that references a model. Do not truncate the list (e.g. with `head`) so you can find the newest models: -## When Typecheck Fails +```bash +# All available models +curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '.data[].id' -**Before searching source code**, grep [Common Errors](references/common-errors.md) for the failing property or function name. Many type errors are caused by deprecated APIs documented there. +# Filter by provider (e.g. anthropic, openai, google) +curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("anthropic/")) | .id] | reverse | .[]' +``` -If not found in common-errors.md: - -1. Search `node_modules/ai/src/` and `node_modules/ai/docs/` -2. Search ai-sdk.dev (for earlier versions or if not found locally) +When multiple versions of a model exist, prefer the one with the highest version number. ## Building and Consuming Agents -### Creating Agents +Use the SDK's built-in agent abstraction (such as `ToolLoopAgent`) rather than hand-rolling tool-calling loops. For end-to-end type safety, infer the UI message type from your agent definition when consuming it on the client (e.g. with `useChat`). Consuming an agent is framework-specific: check `package.json` to detect the stack, then follow the matching quickstart. + +Look up the current agent, tool, and type-safety APIs in the bundled docs (`node_modules/ai/docs/`, especially the agents section) or at https://ai-sdk.dev/docs. + +## DevTools -Always use the `ToolLoopAgent` pattern. Search `node_modules/ai/docs/` for current agent creation APIs. +AI SDK DevTools captures your AI SDK calls - requests, responses, tool calls, token usage, and multi-step runs - so you can inspect exactly what your agents do. Use it while developing to debug generations. It is a separate package and is intended for local development only. -**File conventions**: See [type-safe-agents.md](references/type-safe-agents.md) for where to save agents and tools. +For setup instructions, read the bundled DevTools documentation. -**Type Safety**: When consuming agents with `useChat`, always use `InferAgentUIMessage` for type-safe tool results. See [reference](references/type-safe-agents.md). +## Keep the SDK Current -### Consuming Agents (Framework-Specific) +Outdated installs are the most common source of errors. Compare the installed version against the latest: -Before implementing agent consumption: +- **Installed:** the `version` field in `node_modules/ai/package.json`. +- **Latest:** run `npm view ai version`. -1. Check `package.json` to detect the project's framework/stack -2. Search documentation for the framework's quickstart guide -3. Follow the framework-specific patterns for streaming, API routes, and client integration +If the installed version is a major version (or more) behind the latest, tell the user they are on an old release, and recommend upgrading before continuing. Migration guides are at https://ai-sdk.dev/docs/migration-guides. -## References +## After Making Changes -- [Common Errors](references/common-errors.md) - Renamed parameters reference (parameters → inputSchema, etc.) -- [AI Gateway](references/ai-gateway.md) - Gateway setup and usage -- [Type-Safe Agents with useChat](references/type-safe-agents.md) - End-to-end type safety with InferAgentUIMessage -- [DevTools](references/devtools.md) - Set up local debugging and observability (development only) +Run the project's type checker. Be minimal — only set options that differ from the defaults, checking docs or source for the defaults rather than over-specifying. Most type errors come from remembered, now-changed APIs; re-check the current docs and source when they occur. diff --git a/plugins/ai-sdk/agent/skills/ai-sdk/references/ai-gateway.md b/plugins/ai-sdk/agent/skills/ai-sdk/references/ai-gateway.md deleted file mode 100644 index d0144b17..00000000 --- a/plugins/ai-sdk/agent/skills/ai-sdk/references/ai-gateway.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Vercel AI Gateway -description: Reference for using Vercel AI Gateway with the AI SDK. ---- - -# Vercel AI Gateway - -The Vercel AI Gateway is the fastest way to get started with the AI SDK. It provides access to models from OpenAI, Anthropic, Google, and other providers through a single API. - -## Authentication - -Authenticate with OIDC (for Vercel deployments) or an [AI Gateway API key](https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway%2Fapi-keys&title=AI+Gateway+API+Keys): - -```env filename=".env.local" -AI_GATEWAY_API_KEY=your_api_key_here -``` - -## Usage - -The AI Gateway is the default global provider, so you can access models using a simple string: - -```ts -import { generateText } from 'ai'; - -const { text } = await generateText({ - model: 'anthropic/claude-sonnet-4.5', - prompt: 'What is love?', -}); -``` - -You can also explicitly import and use the gateway provider: - -```ts -// Option 1: Import from 'ai' package (included by default) -import { gateway } from 'ai'; -model: gateway('anthropic/claude-sonnet-4.5'); - -// Option 2: Install and import from '@ai-sdk/gateway' package -import { gateway } from '@ai-sdk/gateway'; -model: gateway('anthropic/claude-sonnet-4.5'); -``` - -## Find Available Models - -**Important**: Always fetch the current model list before writing code. Never use model IDs from memory - they may be outdated. - -List all available models through the gateway API: - -```bash -curl https://ai-gateway.vercel.sh/v1/models -``` - -Filter by provider using `jq`. **Do not truncate with `head`** - always fetch the full list to find the latest models: - -```bash -# Anthropic models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("anthropic/")) | .id] | reverse | .[]' - -# OpenAI models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("openai/")) | .id] | reverse | .[]' - -# Google models -curl -s https://ai-gateway.vercel.sh/v1/models | jq -r '[.data[] | select(.id | startswith("google/")) | .id] | reverse | .[]' -``` - -When multiple versions of a model exist, use the one with the highest version number (e.g., prefer `anthropic/claude-sonnet-4.6` over `anthropic/claude-sonnet-4.5` over `claude-sonnet-4`). diff --git a/plugins/ai-sdk/agent/skills/ai-sdk/references/common-errors.md b/plugins/ai-sdk/agent/skills/ai-sdk/references/common-errors.md deleted file mode 100644 index f2d289aa..00000000 --- a/plugins/ai-sdk/agent/skills/ai-sdk/references/common-errors.md +++ /dev/null @@ -1,445 +0,0 @@ ---- -title: Common Errors -description: Reference for common AI SDK errors and how to resolve them. ---- - -# Common Errors - -## `maxTokens` → `maxOutputTokens` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - maxTokens: 512, // deprecated: use `maxOutputTokens` instead - prompt: 'Write a short story', -}); - -// ✅ Correct -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - maxOutputTokens: 512, - prompt: 'Write a short story', -}); -``` - -## `maxSteps` → `stopWhen: isStepCount(n)` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - tools: { weather }, - maxSteps: 5, // deprecated: use `stopWhen: isStepCount(n)` instead - prompt: 'What is the weather in NYC?', -}); - -// ✅ Correct -import { generateText, isStepCount } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - tools: { weather }, - stopWhen: isStepCount(5), - prompt: 'What is the weather in NYC?', -}); -``` - -## `parameters` → `inputSchema` (in tool definition) - -```typescript -// ❌ Incorrect -const weatherTool = tool({ - description: 'Get weather for a location', - parameters: z.object({ - // deprecated: use `inputSchema` instead - location: z.string(), - }), - execute: async ({ location }) => ({ location, temp: 72 }), -}); - -// ✅ Correct -const weatherTool = tool({ - description: 'Get weather for a location', - inputSchema: z.object({ - location: z.string(), - }), - execute: async ({ location }) => ({ location, temp: 72 }), -}); -``` - -## `generateObject` → `generateText` with `output` - -`generateObject` is deprecated. Use `generateText` with the `output` option instead. - -```typescript -// ❌ Deprecated -import { generateObject } from 'ai'; // deprecated: use `generateText` with `output` instead - -const result = await generateObject({ - // deprecated function - model: 'anthropic/claude-opus-4.5', - schema: z.object({ - // deprecated: use `Output.object({ schema })` instead - recipe: z.object({ - name: z.string(), - ingredients: z.array(z.string()), - }), - }), - prompt: 'Generate a recipe for chocolate cake', -}); - -// ✅ Correct -import { generateText, Output } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.object({ - schema: z.object({ - recipe: z.object({ - name: z.string(), - ingredients: z.array(z.string()), - }), - }), - }), - prompt: 'Generate a recipe for chocolate cake', -}); - -console.log(result.output); // typed object -``` - -## Manual JSON parsing → `generateText` with `output` - -```typescript -// ❌ Incorrect -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - prompt: `Extract the user info as JSON: { "name": string, "age": number } - - Input: John is 25 years old`, -}); -const parsed = JSON.parse(result.text); - -// ✅ Correct -import { generateText, Output } from 'ai'; - -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.object({ - schema: z.object({ - name: z.string(), - age: z.number(), - }), - }), - prompt: 'Extract the user info: John is 25 years old', -}); - -console.log(result.output); // { name: 'John', age: 25 } -``` - -## Other `output` options - -```typescript -// Output.array - for generating arrays of items -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.array({ - element: z.object({ - city: z.string(), - country: z.string(), - }), - }), - prompt: 'List 5 capital cities', -}); - -// Output.choice - for selecting from predefined options -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.choice({ - options: ['positive', 'negative', 'neutral'] as const, - }), - prompt: 'Classify the sentiment: I love this product!', -}); - -// Output.json - for untyped JSON output -const result = await generateText({ - model: 'anthropic/claude-opus-4.5', - output: Output.json(), - prompt: 'Return some JSON data', -}); -``` - -## `toDataStreamResponse` → `createUIMessageStreamResponse` - -When using `useChat` on the frontend, use `createUIMessageStreamResponse()` with `toUIMessageStream()` instead of `toDataStreamResponse()`. The UI message stream format is designed to work with the chat UI components and handles message state correctly. - -```typescript -// ❌ Incorrect (when using useChat) -const result = streamText({ - // config -}); - -return result.toDataStreamResponse(); // deprecated for useChat: use createUIMessageStreamResponse - -// ✅ Correct -const result = streamText({ - // config -}); - -return createUIMessageStreamResponse({ - stream: toUIMessageStream({ stream: result.stream }), -}); -``` - -## Removed managed input state in `useChat` - -The `useChat` hook no longer manages input state internally. You must now manage input state manually. - -```tsx -// ❌ Deprecated -import { useChat } from '@ai-sdk/react'; - -export default function Page() { - const { - input, // deprecated: manage input state manually with useState - handleInputChange, // deprecated: use custom onChange handler - handleSubmit, // deprecated: use sendMessage() instead - } = useChat({ - api: '/api/chat', // deprecated: use `transport: new DefaultChatTransport({ api })` instead - }); - - return ( -
- - -
- ); -} - -// ✅ Correct -import { useChat } from '@ai-sdk/react'; -import { DefaultChatTransport } from 'ai'; -import { useState } from 'react'; - -export default function Page() { - const [input, setInput] = useState(''); - const { sendMessage } = useChat({ - transport: new DefaultChatTransport({ api: '/api/chat' }), - }); - - const handleSubmit = e => { - e.preventDefault(); - sendMessage({ text: input }); - setInput(''); - }; - - return ( -
- setInput(e.target.value)} /> - -
- ); -} -``` - -## `tool-invocation` → `tool-{toolName}` (typed tool parts) - -When rendering messages with `useChat`, use the typed tool part names (`tool-{toolName}`) instead of the generic `tool-invocation` type. This provides better type safety and access to tool-specific input/output types. - -> For end-to-end type-safety, see [Type-Safe Agents](type-safe-agents.md). - -Typed tool parts also use different property names: - -- `part.args` → `part.input` -- `part.result` → `part.output` - -```tsx -// ❌ Incorrect - using generic tool-invocation -{ - message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return
{part.text}
; - case 'tool-invocation': // deprecated: use typed tool parts instead - return ( -
-            {JSON.stringify(part.toolInvocation, null, 2)}
-          
- ); - } - }); -} - -// ✅ Correct - using typed tool parts (recommended) -{ - message.parts.map(part => { - switch (part.type) { - case 'text': - return part.text; - case 'tool-askForConfirmation': - // handle askForConfirmation tool - break; - case 'tool-getWeatherInformation': - // handle getWeatherInformation tool - break; - } - }); -} - -// ✅ Alternative - using isToolUIPart as a catch-all -import { isToolUIPart } from 'ai'; - -{ - message.parts.map(part => { - if (part.type === 'text') { - return part.text; - } - if (isToolUIPart(part)) { - // handle any tool part generically - return ( -
- {part.toolName}: {part.state} -
- ); - } - }); -} -``` - -## `useChat` state-dependent property access - -Tool part properties are only available in certain states. TypeScript will error if you access them without checking state first. - -```tsx -// ❌ Incorrect - input may be undefined during streaming -// TS18048: 'part.input' is possibly 'undefined' -if (part.type === 'tool-getWeather') { - const location = part.input.location; -} - -// ✅ Correct - check for input-available or output-available -if ( - part.type === 'tool-getWeather' && - (part.state === 'input-available' || part.state === 'output-available') -) { - const location = part.input.location; -} - -// ❌ Incorrect - output is only available after execution -// TS18048: 'part.output' is possibly 'undefined' -if (part.type === 'tool-getWeather') { - const weather = part.output; -} - -// ✅ Correct - check for output-available -if (part.type === 'tool-getWeather' && part.state === 'output-available') { - const location = part.input.location; - const weather = part.output; -} -``` - -## `part.toolInvocation.args` → `part.input` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.input` on typed tool parts instead - const location = part.toolInvocation.args.location; -} - -// ✅ Correct -if ( - part.type === 'tool-getWeather' && - (part.state === 'input-available' || part.state === 'output-available') -) { - const location = part.input.location; -} -``` - -## `part.toolInvocation.result` → `part.output` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.output` on typed tool parts instead - const weather = part.toolInvocation.result; -} - -// ✅ Correct -if (part.type === 'tool-getWeather' && part.state === 'output-available') { - const weather = part.output; -} -``` - -## `part.toolInvocation.toolCallId` → `part.toolCallId` - -```tsx -// ❌ Incorrect -if (part.type === 'tool-invocation') { - // deprecated: use `part.toolCallId` on typed tool parts instead - const id = part.toolInvocation.toolCallId; -} - -// ✅ Correct -if (part.type === 'tool-getWeather') { - const id = part.toolCallId; -} -``` - -## Tool invocation states renamed - -```tsx -// ❌ Incorrect -switch (part.toolInvocation.state) { - case 'partial-call': // deprecated: use `input-streaming` instead - return
Loading...
; - case 'call': // deprecated: use `input-available` instead - return
Executing...
; - case 'result': // deprecated: use `output-available` instead - return
Done
; -} - -// ✅ Correct -switch (part.state) { - case 'input-streaming': - return
Loading...
; - case 'input-available': - return
Executing...
; - case 'output-available': - return
Done
; -} -``` - -## `addToolResult` → `addToolOutput` - -```tsx -// ❌ Incorrect -addToolResult({ - // deprecated: use `addToolOutput` instead - toolCallId: part.toolInvocation.toolCallId, - result: 'Yes, confirmed.', // deprecated: use `output` instead -}); - -// ✅ Correct -addToolOutput({ - tool: 'askForConfirmation', - toolCallId: part.toolCallId, - output: 'Yes, confirmed.', -}); -``` - -## `messages` → `uiMessages` in `createAgentUIStreamResponse` - -```typescript -// ❌ Incorrect -return createAgentUIStreamResponse({ - agent: myAgent, - messages, // incorrect: use `uiMessages` instead -}); - -// ✅ Correct -return createAgentUIStreamResponse({ - agent: myAgent, - uiMessages: messages, -}); -``` diff --git a/plugins/ai-sdk/agent/skills/ai-sdk/references/devtools.md b/plugins/ai-sdk/agent/skills/ai-sdk/references/devtools.md deleted file mode 100644 index 197e203a..00000000 --- a/plugins/ai-sdk/agent/skills/ai-sdk/references/devtools.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -title: AI SDK DevTools -description: Debug AI SDK calls by inspecting captured runs and steps. ---- - -# AI SDK DevTools - -## Why Use DevTools - -DevTools captures all AI SDK calls (`generateText`, `streamText`, `ToolLoopAgent`) to a local JSON file. This lets you inspect LLM requests, responses, tool calls, and multi-step interactions without manually logging. - -## Setup - -Requires AI SDK 6. Install `@ai-sdk/devtools` using your project's package manager. - -Wrap your model with the middleware: - -```ts -import { wrapLanguageModel, gateway } from 'ai'; -import { devToolsMiddleware } from '@ai-sdk/devtools'; - -const model = wrapLanguageModel({ - model: gateway('anthropic/claude-sonnet-4.5'), - middleware: devToolsMiddleware(), -}); -``` - -## Viewing Captured Data - -All runs and steps are saved to: - -``` -.devtools/generations.json -``` - -Read this file directly to inspect captured data: - -```bash -cat .devtools/generations.json | jq -``` - -Or launch the web UI: - -```bash -npx @ai-sdk/devtools -# Open http://localhost:4983 -``` - -## Data Structure - -- **Run**: A complete multi-step interaction grouped by initial prompt -- **Step**: A single LLM call within a run (includes input, output, tool calls, token usage) diff --git a/plugins/ai-sdk/agent/skills/ai-sdk/references/type-safe-agents.md b/plugins/ai-sdk/agent/skills/ai-sdk/references/type-safe-agents.md deleted file mode 100644 index 17d7a6fd..00000000 --- a/plugins/ai-sdk/agent/skills/ai-sdk/references/type-safe-agents.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -title: Type-Safe useChat with Agents -description: Build end-to-end type-safe agents by inferring UIMessage types from your agent definition. ---- - -# Type-Safe useChat with Agents - -Build end-to-end type-safe agents by inferring `UIMessage` types from your agent definition for type-safe UI rendering with `useChat`. - -## Recommended Structure - -``` -lib/ - agents/ - my-agent.ts # Agent definition + type export - tools/ - weather-tool.ts # Individual tool definitions - calculator-tool.ts -``` - -## Define Tools - -```ts -// lib/tools/weather-tool.ts -import { tool } from 'ai'; -import { z } from 'zod'; - -export const weatherTool = tool({ - description: 'Get current weather for a location', - inputSchema: z.object({ - location: z.string().describe('City name'), - }), - execute: async ({ location }) => { - return { temperature: 72, condition: 'sunny', location }; - }, -}); -``` - -## Define Agent and Export Type - -```ts -// lib/agents/my-agent.ts -import { ToolLoopAgent, InferAgentUIMessage } from 'ai'; -import { weatherTool } from '../tools/weather-tool'; -import { calculatorTool } from '../tools/calculator-tool'; - -export const myAgent = new ToolLoopAgent({ - model: 'anthropic/claude-sonnet-4', - instructions: 'You are a helpful assistant.', - tools: { - weather: weatherTool, - calculator: calculatorTool, - }, -}); - -// Infer the UIMessage type from the agent -export type MyAgentUIMessage = InferAgentUIMessage; -``` - -### With Custom Metadata - -```ts -// lib/agents/my-agent.ts -import { z } from 'zod'; - -const metadataSchema = z.object({ - createdAt: z.number(), - model: z.string().optional(), -}); - -type MyMetadata = z.infer; - -export type MyAgentUIMessage = InferAgentUIMessage; -``` - -## Use with `useChat` - -```tsx -// app/chat.tsx -import { useChat } from '@ai-sdk/react'; -import type { MyAgentUIMessage } from '@/lib/agents/my-agent'; - -export function Chat() { - const { messages } = useChat(); - - return ( -
- {messages.map(message => ( - - ))} -
- ); -} -``` - -## Rendering Parts with Type Safety - -Tool parts are typed as `tool-{toolName}` based on your agent's tools: - -```tsx -function Message({ message }: { message: MyAgentUIMessage }) { - return ( -
- {message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return

{part.text}

; - - case 'tool-weather': - // part.input and part.output are fully typed - if (part.state === 'output-available') { - return ( -
- Weather in {part.input.location}: {part.output.temperature}F -
- ); - } - return
Loading weather...
; - - case 'tool-calculator': - // TypeScript knows this is the calculator tool - return
Calculating...
; - - default: - return null; - } - })} -
- ); -} -``` - -The `part.type` discriminant narrows the type, giving you autocomplete and type checking for `input` and `output` based on each tool's schema. - -## Splitting Tool Rendering into Components - -When rendering many tools, you may want to split each tool into its own component. Use `UIToolInvocation` to derive a typed invocation from your tool and export it alongside the tool definition: - -```ts -// lib/tools/weather-tool.ts -import { tool, UIToolInvocation } from 'ai'; -import { z } from 'zod'; - -export const weatherTool = tool({ - description: 'Get current weather for a location', - inputSchema: z.object({ - location: z.string().describe('City name'), - }), - execute: async ({ location }) => { - return { temperature: 72, condition: 'sunny', location }; - }, -}); - -// Export the invocation type for use in UI components -export type WeatherToolInvocation = UIToolInvocation; -``` - -Then import only the type in your component: - -```tsx -// components/weather-tool.tsx -import type { WeatherToolInvocation } from '@/lib/tools/weather-tool'; - -export function WeatherToolComponent({ - invocation, -}: { - invocation: WeatherToolInvocation; -}) { - // invocation.input and invocation.output are fully typed - if (invocation.state === 'output-available') { - return ( -
- Weather in {invocation.input.location}: {invocation.output.temperature}F -
- ); - } - return
Loading weather for {invocation.input?.location}...
; -} -``` - -Use the component in your message renderer: - -```tsx -function Message({ message }: { message: MyAgentUIMessage }) { - return ( -
- {message.parts.map((part, i) => { - switch (part.type) { - case 'text': - return

{part.text}

; - case 'tool-weather': - return ; - case 'tool-calculator': - return ; - default: - return null; - } - })} -
- ); -} -``` - -This approach keeps your tool rendering logic organized while maintaining full type safety, without needing to import the tool implementation into your UI components. diff --git a/plugins/ai-sdk/skills-lock.json b/plugins/ai-sdk/skills-lock.json index 180a0239..70f032b3 100644 --- a/plugins/ai-sdk/skills-lock.json +++ b/plugins/ai-sdk/skills-lock.json @@ -5,7 +5,7 @@ "source": "vercel/ai", "sourceType": "github", "skillPath": "skills/use-ai-sdk/SKILL.md", - "computedHash": "2fdbb3c2c9c0e19c64f03f2febd4fec134473e2fe7443f7ebe67870eba5b3c75" + "computedHash": "0883204d11b055e968dee697c5858e68064c27dfd4deb6310212895daa65c5ad" } } } diff --git a/plugins/axi/.agents/skills/axi/SKILL.md b/plugins/axi/.agents/skills/axi/SKILL.md index 84cec722..b7c59803 100644 --- a/plugins/axi/.agents/skills/axi/SKILL.md +++ b/plugins/axi/.agents/skills/axi/SKILL.md @@ -120,6 +120,22 @@ help: tasks create --title "..." [--body "..."] Every operation must be completable with flags alone. If a required value is missing, fail immediately with a clear error — don't prompt for it. Suppress prompts from wrapped tools. +### Fail loud on unrecognized input + +Reject unknown flags and arguments — never silently ignore them. A dropped flag is worse than an error: the agent gets plausible-looking output it believes is scoped or filtered, then proceeds confidently on wrong data. This is the same guarantee a CLI already owes for an unknown _command_; extend it to flags. + +``` +$ tasks list --stat closed +error: unknown flag --stat for `list` +help: valid flags for `list`: --state, --assignee, --limit (--help always allowed) +``` + +- **Validate before any dependency call**, with exit code 2 — the same as a missing required flag. Each command declares its own known flags; an unrecognized one is rejected by name and the command's valid flags are listed. +- **`--help` always passes** — it's the one universal flag. Beyond it, a CLI may standardize its own always-allowed globals (e.g. an `--account` selector); whatever the set, those flags pass on every command and are never reported as unknown. +- **Renamed or removed flags get a targeted hint**, not the generic list — point at what replaced them (`--status was renamed; use --state instead`) so the agent self-corrects in one step. +- **Per-subcommand flag sets.** For grouped nouns where one command dispatches to subcommands (a `list` vs a `create` under the same noun), validate against the _subcommand's_ flags — they differ, and only the subcommand layer knows which is in play. +- **Make the error self-correcting in one turn.** The agent's deterministic next move after an unknown-flag error is to run ` --help` (e.g. `tasks list --help`) — so fold that lookup into the error: list the valid flags inline, or print the command's concise `--help` block directly beneath it. Per §4 the expensive cost is the follow-up call, and per §10 per-command help is already concise, so inlining it collapses the two-turn correction into one. + ### Output channels - **stdout**: all structured output the agent consumes — data, errors, suggestions diff --git a/plugins/axi/agent/skills/axi/SKILL.md b/plugins/axi/agent/skills/axi/SKILL.md index a79cad3d..f83de045 100644 --- a/plugins/axi/agent/skills/axi/SKILL.md +++ b/plugins/axi/agent/skills/axi/SKILL.md @@ -116,6 +116,22 @@ help: tasks create --title "..." [--body "..."] Every operation must be completable with flags alone. If a required value is missing, fail immediately with a clear error — don't prompt for it. Suppress prompts from wrapped tools. +### Fail loud on unrecognized input + +Reject unknown flags and arguments — never silently ignore them. A dropped flag is worse than an error: the agent gets plausible-looking output it believes is scoped or filtered, then proceeds confidently on wrong data. This is the same guarantee a CLI already owes for an unknown _command_; extend it to flags. + +``` +$ tasks list --stat closed +error: unknown flag --stat for `list` +help: valid flags for `list`: --state, --assignee, --limit (--help always allowed) +``` + +- **Validate before any dependency call**, with exit code 2 — the same as a missing required flag. Each command declares its own known flags; an unrecognized one is rejected by name and the command's valid flags are listed. +- **`--help` always passes** — it's the one universal flag. Beyond it, a CLI may standardize its own always-allowed globals (e.g. an `--account` selector); whatever the set, those flags pass on every command and are never reported as unknown. +- **Renamed or removed flags get a targeted hint**, not the generic list — point at what replaced them (`--status was renamed; use --state instead`) so the agent self-corrects in one step. +- **Per-subcommand flag sets.** For grouped nouns where one command dispatches to subcommands (a `list` vs a `create` under the same noun), validate against the _subcommand's_ flags — they differ, and only the subcommand layer knows which is in play. +- **Make the error self-correcting in one turn.** The agent's deterministic next move after an unknown-flag error is to run ` --help` (e.g. `tasks list --help`) — so fold that lookup into the error: list the valid flags inline, or print the command's concise `--help` block directly beneath it. Per §4 the expensive cost is the follow-up call, and per §10 per-command help is already concise, so inlining it collapses the two-turn correction into one. + ### Output channels - **stdout**: all structured output the agent consumes — data, errors, suggestions diff --git a/plugins/axi/skills-lock.json b/plugins/axi/skills-lock.json index d02aa0b8..cf1e86d4 100644 --- a/plugins/axi/skills-lock.json +++ b/plugins/axi/skills-lock.json @@ -5,7 +5,7 @@ "source": "kunchenguid/axi", "sourceType": "github", "skillPath": ".agents/skills/axi/SKILL.md", - "computedHash": "e3993d4b3be5c816b83a0957951906d3223dd4e6df2f19869eef6607170b6838" + "computedHash": "07a1364ca8cea05e5d264ee90c669531618e381a82d6976b17108095fcf90366" } } } diff --git a/plugins/emulate/.agents/skills/emulate/SKILL.md b/plugins/emulate/.agents/skills/emulate/SKILL.md index df371f93..1a7223a7 100644 --- a/plugins/emulate/.agents/skills/emulate/SKILL.md +++ b/plugins/emulate/.agents/skills/emulate/SKILL.md @@ -350,10 +350,12 @@ LINEAR_EMULATOR_URL=http://localhost:4012 Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions. -## Next.js Integration (Embedded Mode) +## Framework Integration (Embedded Mode) The `@emulators/adapter-next` package embeds emulators directly into a Next.js app on the same origin. See the **next** skill (`skills/next/SKILL.md`) for full setup, Auth.js configuration, persistence, and font tracing details. +The `@emulators/adapter-nuxt` package embeds emulators directly into a Nuxt app on the same origin. See the **nuxt** skill (`skills/nuxt/SKILL.md`) for the server route, Nuxt config, OAuth configuration, and persistence setup. + ## Persistence By default, all emulator state is in-memory. For persistence across process restarts and serverless cold starts, use a `PersistenceAdapter`. @@ -388,6 +390,7 @@ packages/ @emulators/ core/ # HTTP server, Store, plugin interface, middleware adapter-next/ # Next.js App Router integration + adapter-nuxt/ # Nuxt server route integration vercel/ # Vercel API service plugin github/ # GitHub API service plugin google/ # Google OAuth 2.0 / OIDC plugin diff --git a/plugins/emulate/agent/skills/emulate/SKILL.md b/plugins/emulate/agent/skills/emulate/SKILL.md index 82280506..060f9874 100644 --- a/plugins/emulate/agent/skills/emulate/SKILL.md +++ b/plugins/emulate/agent/skills/emulate/SKILL.md @@ -347,10 +347,12 @@ LINEAR_EMULATOR_URL=http://localhost:4012 Then use these in your app to construct API and OAuth URLs. See each service's skill for SDK-specific override instructions. -## Next.js Integration (Embedded Mode) +## Framework Integration (Embedded Mode) The `@emulators/adapter-next` package embeds emulators directly into a Next.js app on the same origin. See the **next** skill (`skills/next/SKILL.md`) for full setup, Auth.js configuration, persistence, and font tracing details. +The `@emulators/adapter-nuxt` package embeds emulators directly into a Nuxt app on the same origin. See the **nuxt** skill (`skills/nuxt/SKILL.md`) for the server route, Nuxt config, OAuth configuration, and persistence setup. + ## Persistence By default, all emulator state is in-memory. For persistence across process restarts and serverless cold starts, use a `PersistenceAdapter`. @@ -385,6 +387,7 @@ packages/ @emulators/ core/ # HTTP server, Store, plugin interface, middleware adapter-next/ # Next.js App Router integration + adapter-nuxt/ # Nuxt server route integration vercel/ # Vercel API service plugin github/ # GitHub API service plugin google/ # Google OAuth 2.0 / OIDC plugin diff --git a/plugins/emulate/skills-lock.json b/plugins/emulate/skills-lock.json index eaf3a3c1..8f11ecad 100644 --- a/plugins/emulate/skills-lock.json +++ b/plugins/emulate/skills-lock.json @@ -17,7 +17,7 @@ "source": "vercel-labs/emulate", "sourceType": "github", "skillPath": "skills/emulate/SKILL.md", - "computedHash": "a3a65a8488e732ea4bf1c8fc2b4896d4727a45683e205559f973853a53cbcbb2" + "computedHash": "a37ed153c79c6fe337535a1055d08644070186160c5f14c4ad990c1a16537512" }, "github": { "source": "vercel-labs/emulate", diff --git a/plugins/greptile/agent/skills/check-pr/SKILL.md b/plugins/greptile/agent/skills/check-pr/SKILL.md new file mode 100644 index 00000000..6ad11b5a --- /dev/null +++ b/plugins/greptile/agent/skills/check-pr/SKILL.md @@ -0,0 +1,273 @@ +--- +description: "Checks a GitHub, GitLab, or Perforce (p4) pull request (or merge request, or shelved changelist) for unresolved review comments, failing status checks, and incomplete PR descriptions. Waits for pending checks to complete, categorizes issues as actionable or informational, and optionally fixes and resolves them. Use when the user wants to check a PR/MR/CL, address review feedback, or prepare a change for submission.\n" +license: "MIT" +metadata: {"author":"greptileai","version":"1.3"} +--- +# Check PR + +Analyze a pull request (GitHub), merge request (GitLab), or shelved changelist (Perforce) for review comments, status checks, and description completeness, then help address any issues found. + +## Inputs + +- **PR/MR/CL number** (optional): If not provided, detect the PR/MR for the current branch, or the default pending changelist for p4. + +## Instructions + +### 0. Detect platform + +First check if the user is working in a Perforce depot by looking for a `.p4config` file or `P4CLIENT`/`P4PORT` environment variables: + +```bash +# Check for Perforce environment +if p4 info >/dev/null 2>&1; then + VCS="perforce" +else + # Fall back to git remote detection + REMOTE_URL=$(git remote get-url origin) + if echo "$REMOTE_URL" | grep -qi "gitlab"; then + VCS="gitlab" + else + VCS="github" + fi +fi +``` + +For self-hosted GitLab instances whose hostname doesn't contain "gitlab", the user can override by passing `--vcs gitlab` as an input. For Perforce, the user can override by passing `--vcs perforce`. + +### 1. Identify the PR/MR/CL + +If a number was provided, use it. Otherwise, detect it: + +**GitHub:** +```bash +gh pr view --json number -q .number +``` + +**GitLab:** +```bash +glab mr view --output json | jq '.iid' +``` + +**Perforce:** +```bash +# List pending changelists for the current user/client +p4 changes -s pending -u $P4USER -c $P4CLIENT +``` + +Key field differences between platforms: +- GitHub: `number`, `headRefName`, `headRefOid` +- GitLab: `iid`, `source_branch`, `sha` +- Perforce: changelist number (CL), `shelved` files for in-review CLs + +### 2. Fetch PR/MR/CL details + +**GitHub:** +```bash +gh pr view --json title,body,state,reviews,comments,headRefName,statusCheckRollup +gh api repos/{owner}/{repo}/pulls//comments +gh api --paginate "repos/{owner}/{repo}/issues//comments?per_page=100" +``` + +GitHub PRs are also issues, so general PR comments live on the issue comments endpoint. Greptile may edit a single general PR comment on each review cycle instead of creating a new review or comment. Always inspect the latest Greptile-authored general comment by `updated_at`, including any "Prompt to fix all with AI" section, before concluding that the PR is clear. + +**GitLab:** +```bash +glab mr view --output json +# Fetch discussions (inline diff comments are type "DiffNote"; general comments have null type) +glab api "projects/:fullpath/merge_requests//discussions" +``` + +For GitLab, paginate discussions if needed (add `?per_page=100&page=N`). + +**Perforce:** +```bash +# Get changelist description, files, and status +p4 describe -s + +# Get shelved files (for in-review CLs) +p4 describe -S + +# Get the diff of the shelved changelist +p4 diff2 //...@= //...@= + +# List review comments (if using p4 review workflow) +p4 review -c +``` + +Key Perforce CL fields: +- `Change`: changelist number +- `Status`: `pending`, `submitted`, `shelved` +- `Description`: the CL description / commit message +- `Files`: list of files in the CL + +### 3. Wait for pending checks + +Before analyzing, ensure all status checks have completed. If any checks are `PENDING` or `IN_PROGRESS` (GitHub) / `running` or `pending` (GitLab), poll every 30 seconds until all checks reach a terminal state. + +**GitHub:** poll `statusCheckRollup` from `gh pr view`. + +**GitLab:** +```bash +glab api "projects/:fullpath/merge_requests//pipelines" +``` +Pipeline statuses: `running`, `pending`, `success`, `failed`, `canceled`, `skipped`. Poll until no pipeline has `running` or `pending` status. + +**Perforce:** Perforce doesn't have built-in CI checks natively. If the team uses a review tool (Swarm, etc.) or an external CI triggered by shelve events, check the relevant system. Otherwise, proceed to analysis immediately. + +### 4. Analyze the PR/MR + +Once all checks are complete, evaluate these areas: + +#### A. Status Checks + +- Are all CI checks passing? +- If any are failing, identify which ones and the failure reason. + +#### B. PR/MR Description + +- Is the description complete and follows team conventions? +- Are all required sections filled in? +- Are there TODOs or placeholders that need updating? + +#### C. Review Comments + +- Inline code review comments that need addressing +- Look for bot review comments (e.g. from `greptile-apps[bot]` on GitHub, or the Greptile bot user on GitLab, linters, etc.) +- Human reviewer comments +- **Perforce:** review comments from `p4 review` or external review tools + +#### D. General Comments + +- Discussion comments on the PR/MR +- For GitHub, check the issue comments endpoint and use `updated_at` to catch bot comments edited in place. Greptile's latest edited summary can contain actionable items even when there are no new inline comments. +- Bot comments (deploy previews, etc.) — usually informational +- **Perforce:** CL description should include a clear summary, affected files rationale, and testing notes + +### 5. Categorize issues + +For each issue found, categorize as: + +| Category | Meaning | +|---|---| +| **Actionable** | Code changes, test improvements, or fixes needed | +| **Informational** | Verification notes, questions, or FYIs that don't require changes | +| **Already addressed** | Issues that appear to be resolved by subsequent commits | + +### 6. Report findings + +Present a summary table: + +| Area | Issue | Status | Action Needed | +|------|-------|--------|---------------| +| Status Checks | CI build failing | Failing | Fix type error in `src/api.ts` | +| Review | "Add null check" — @reviewer | Actionable | Add guard clause | +| Description | TODO placeholder in test plan | Actionable | Fill in test plan | +| Review | "Looks good" — @teammate | Informational | None | + +### 7. Fix issues (if requested) + +If there are actionable items: + +1. Switch to the PR/MR's branch (git) or ensure files are open in the correct CL (Perforce) if not already. +2. Ask the user if they want to fix the issues. +3. If yes, make the fixes, then: + +**GitHub/GitLab:** commit and push: +```bash +git add +git commit -m "address review feedback" +git push +``` + +**Perforce:** open files for edit, make changes, and re-shelve: +```bash +p4 edit +# make changes +p4 shelve -f -c +``` + +### 8. Resolve review threads + +After addressing comments, resolve the corresponding review threads. + +**Perforce** — Perforce does not have a native "resolve thread" concept. Instead, mark comments as addressed by updating the CL description or by responding in the review tool being used (Swarm, etc.). If using `p4 review`: + +```bash +# Mark files as reviewed after addressing feedback +p4 review -c +``` + +**GitHub** — fetch unresolved thread IDs (paginate if needed — see [the GraphQL reference](references/graphql-queries.md)): + +```bash +gh api graphql -f query=' +query($cursor: String) { + repository(owner: "OWNER", name: "REPO") { + pullRequest(number: PR_NUMBER) { + reviewThreads(first: 100, after: $cursor) { + pageInfo { hasNextPage endCursor } + nodes { + id + isResolved + comments(first: 1) { + nodes { body path } + } + } + } + } + } +}' +``` + +If `hasNextPage` is true, repeat with `-f cursor=ENDCURSOR` to get remaining threads. + +Then resolve threads that have been addressed or are informational: + +```bash +gh api graphql -f query=' +mutation { + resolveReviewThread(input: {threadId: "THREAD_ID"}) { + thread { isResolved } + } +}' +``` + +Batch multiple resolutions into a single mutation using aliases (`t1`, `t2`, etc.). + +**GitLab** — fetch unresolved discussions (see [the GitLab API reference](references/gitlab-api.md)): + +```bash +glab api "projects/:fullpath/merge_requests//discussions?per_page=100" +``` + +Filter for discussions where `"resolved": false`. Collect each discussion's `id`. + +Resolve each discussion individually (GitLab has no batch resolution): + +```bash +glab api --method PUT \ + "projects/:fullpath/merge_requests//discussions/" \ + --field resolved=true +``` + +Repeat for each unresolved discussion ID. + +### 9. Multiple PRs/MRs/CLs + +If checking a chain of PRs/MRs/CLs, process them sequentially. + +**Perforce** — to check multiple changelists at once: +```bash +p4 changes -s pending -u $P4USER -c $P4CLIENT -l +``` + +## Output format + +Summarize: +- PR/MR/CL title or description and current state +- Platform detected (GitHub / GitLab / Perforce) +- Status checks summary (passing/failing/pending) — or N/A for Perforce +- Total issues found +- Actionable items with descriptions +- Items that can be ignored with reasons +- Recommended next steps diff --git a/plugins/greptile/agent/skills/check-pr/references/gitlab-api.md b/plugins/greptile/agent/skills/check-pr/references/gitlab-api.md new file mode 100644 index 00000000..2223f5c9 --- /dev/null +++ b/plugins/greptile/agent/skills/check-pr/references/gitlab-api.md @@ -0,0 +1,91 @@ +# GitLab API Reference + +Useful GitLab REST API calls for working with merge request discussions, using `glab api`. + +`glab api` automatically resolves `:fullpath` to the URL-encoded project path from the local git remote. + +## Fetch MR details + +```bash +glab mr view --output json +``` + +Key fields (compared to GitHub equivalents): +- `iid` — internal MR number (use this, not `id`) +- `source_branch` — equivalent to GitHub's `headRefName` +- `sha` — HEAD commit SHA, equivalent to GitHub's `headRefOid` +- `description` — equivalent to GitHub's `body` + +## Fetch all discussions (inline + general comments) + +```bash +glab api "projects/:fullpath/merge_requests//discussions?per_page=100" +``` + +Paginate with `&page=2`, `&page=3`, etc. until the response array length is less than `per_page`. + +Each discussion object: +- `id` — discussion ID (used for resolution) +- `resolved` — `true` or `false` +- `notes` — array of note objects + +Each note object: +- `type` — `"DiffNote"` for inline diff comments, `null` for general comments +- `author.username` — author's username +- `body` — comment text +- `position.new_path` — file path (for `DiffNote` type) + +## Filter for unresolved inline diff comments + +```bash +glab api "projects/:fullpath/merge_requests//discussions?per_page=100" | \ + jq '[.[] | select(.resolved == false and (.notes[0].type == "DiffNote"))]' +``` + +## Resolve a single discussion + +```bash +glab api --method PUT \ + "projects/:fullpath/merge_requests//discussions/" \ + --field resolved=true +``` + +There is no batch resolution in GitLab — issue one PUT per discussion. + +## Fetch pipeline status for an MR + +```bash +glab api "projects/:fullpath/merge_requests//pipelines" +``` + +Pipeline statuses: `running`, `pending`, `success`, `failed`, `canceled`, `skipped`. + +## Fetch jobs for a specific pipeline + +```bash +glab api "projects/:fullpath/pipelines//jobs" +``` + +Each job has `name`, `status`, `stage`, and `web_url`. + +## Fetch MR notes (general comments and bot reviews) + +```bash +glab api "projects/:fullpath/merge_requests//notes?per_page=100" +``` + +Filter by `author.username` to find Greptile bot comments. The exact bot username depends on the Greptile installation — check the first Greptile comment to identify it. + +## Post a comment on an MR + +```bash +glab mr note --message "your message here" +``` + +Or via API: + +```bash +glab api --method POST \ + "projects/:fullpath/merge_requests//notes" \ + --field body="your message here" +``` diff --git a/plugins/greptile/agent/skills/check-pr/references/graphql-queries.md b/plugins/greptile/agent/skills/check-pr/references/graphql-queries.md new file mode 100644 index 00000000..11e19f79 --- /dev/null +++ b/plugins/greptile/agent/skills/check-pr/references/graphql-queries.md @@ -0,0 +1,87 @@ +# GraphQL Queries Reference + +Useful GitHub GraphQL queries for working with PR review threads. + +## Fetch unresolved review threads (with pagination) + +```graphql +query($cursor: String) { + repository(owner: "OWNER", name: "REPO") { + pullRequest(number: PR_NUMBER) { + reviewThreads(first: 100, after: $cursor) { + pageInfo { + hasNextPage + endCursor + } + nodes { + id + isResolved + comments(first: 3) { + nodes { + body + path + author { login } + createdAt + } + } + } + } + } + } +} +``` + +Pass `-f cursor=ENDCURSOR` on subsequent requests if `hasNextPage` is `true`. + +## Resolve a single review thread + +```graphql +mutation { + resolveReviewThread(input: {threadId: "THREAD_ID"}) { + thread { isResolved } + } +} +``` + +## Batch-resolve multiple threads + +Use GraphQL aliases to resolve several threads in one request: + +```graphql +mutation { + t1: resolveReviewThread(input: {threadId: "THREAD_ID_1"}) { + thread { isResolved } + } + t2: resolveReviewThread(input: {threadId: "THREAD_ID_2"}) { + thread { isResolved } + } + t3: resolveReviewThread(input: {threadId: "THREAD_ID_3"}) { + thread { isResolved } + } +} +``` + +## Fetch PR details (REST) + +```bash +gh pr view --json title,body,state,reviews,comments,headRefName,statusCheckRollup +``` + +## Fetch inline review comments (REST) + +```bash +gh api repos/{owner}/{repo}/pulls//comments +``` + +## Fetch general PR comments edited in place (REST) + +General PR comments are issue comments. Greptile may update one summary comment repeatedly, so select by `updated_at` instead of `created_at`: + +```bash +gh api --paginate "repos/{owner}/{repo}/issues//comments?per_page=100" \ + | jq -s 'add + | map(select(.user.login | test("greptile"; "i"))) + | sort_by(.updated_at) + | last + | {author: .user.login, updated_at, body}' +``` diff --git a/plugins/greptile/agent/skills/cli-review/SKILL.md b/plugins/greptile/agent/skills/cli-review/SKILL.md new file mode 100644 index 00000000..71843b60 --- /dev/null +++ b/plugins/greptile/agent/skills/cli-review/SKILL.md @@ -0,0 +1,86 @@ +--- +description: "Runs a Greptile CLI review for the current local branch, installing or authenticating the CLI when needed, then summarizes JSON findings for the user. Use when the user wants Greptile feedback before opening a PR, outside a hosted PR review flow, or directly from a local checkout.\n" +license: "MIT" +metadata: {"author":"greptileai","version":"1.0"} +--- +# CLI Review + +Run a Greptile review from the local checkout and summarize the findings. + +## Instructions + +### 1. Confirm repository context + +Start from the current repository root: + +```bash +git rev-parse --show-toplevel +``` + +If the command fails, tell the user that the Greptile CLI review must be run from a git repository. + +### 2. Check for the Greptile CLI + +Check whether `greptile` is installed: + +```bash +command -v greptile +``` + +If it is missing, do not install it automatically. Ask the user for permission, then show the recommended install command: + +```bash +npm i -g greptile +``` + +If npm is unavailable, offer the shell installer fallback: + +```bash +curl -fsSL "https://greptile.com/cli/install" | sh +``` + +After installation, re-run `command -v greptile`. + +### 3. Ensure authentication + +Check the signed-in account: + +```bash +greptile whoami +``` + +If the CLI reports that authentication is missing, run: + +```bash +greptile login +``` + +Wait for the user to complete the login flow before continuing. + +### 4. Run the review + +Prefer JSON output: + +```bash +greptile review --json +``` + +If JSON output is unsupported or fails with a usage error, fall back to: + +```bash +greptile review --agent +``` + +Do not hide the raw command failure if both commands fail. Summarize the failing command and the next action the user needs to take. + +### 5. Summarize results + +Parse JSON output when available and report: + +- Review status +- Number of findings +- Highest severity findings first +- Files that need edits +- Suggested next command or fix path + +When output is plain text, preserve the same structure as much as possible. Keep the summary concise and focused on actionable findings. diff --git a/plugins/greptile/agent/skills/greploop/SKILL.md b/plugins/greptile/agent/skills/greploop/SKILL.md new file mode 100644 index 00000000..dbbb2261 --- /dev/null +++ b/plugins/greptile/agent/skills/greploop/SKILL.md @@ -0,0 +1,422 @@ +--- +description: "Iteratively improves a PR (GitHub), MR (GitLab), or shelved changelist (Perforce) until Greptile gives it a 5/5 confidence score with zero unresolved comments. Triggers Greptile review, fixes all actionable comments, pushes/re-shelves, re-triggers review, and repeats. Use when the user wants to fully optimize a PR/MR/CL against Greptile's code review standards.\n" +license: "MIT" +metadata: {"author":"greptileai","version":"1.3"} +--- +# Greploop + +Iteratively fix a PR/MR/CL until Greptile gives a perfect review: 5/5 confidence, zero unresolved comments. + +## Inputs + +- **PR/MR/CL number** (optional): If not provided, detect the PR/MR for the current branch, or the default pending changelist for p4. + +## Instructions + +### 0. Detect platform + +First check for Perforce, then fall back to git remote detection: + +```bash +# Check for Perforce environment +if p4 info >/dev/null 2>&1; then + VCS="perforce" +else + REMOTE_URL=$(git remote get-url origin) + if echo "$REMOTE_URL" | grep -qi "gitlab"; then + VCS="gitlab" + else + VCS="github" + fi +fi +``` + +For self-hosted GitLab instances whose hostname doesn't contain "gitlab", the user can override by passing `--vcs gitlab` as an input. For Perforce, pass `--vcs perforce`. + +### 1. Identify the PR/MR/CL + +**GitHub:** +```bash +gh pr view --json number,headRefName -q '{number: .number, branch: .headRefName}' +``` + +**GitLab:** +```bash +glab mr view --output json | jq '{iid: .iid, branch: .source_branch}' +``` + +Switch to the PR/MR branch if not already on it. + +**Perforce:** +```bash +# List pending changelists for current user/client +p4 changes -s pending -u $P4USER -c $P4CLIENT + +# Describe a specific CL +p4 describe -s +``` + +Ensure the correct workspace (`p4 client`) is set before proceeding. + +Key field differences: +- GitHub: `number`, `headRefName`, `headRefOid` +- GitLab: `iid`, `source_branch`, `sha` +- Perforce: changelist number, `P4CLIENT`, shelved files + +### 2. Loop + +Repeat the following cycle. **Max 5 iterations** to avoid runaway loops. + +#### A. Trigger Greptile review + +Push/shelve the latest changes (if any): + +**GitHub/GitLab:** +```bash +git push +``` + +**Perforce:** +```bash +# Re-shelve to update the shelved files for review +p4 shelve -f -c +``` + +Wait for checks to start after push/shelve: + +```bash +sleep 5 +``` + +**GitHub** — check if Greptile is already running before posting a new trigger comment: + +```bash +GREPTILE_STATE=$(gh pr checks --json name,state | jq -r '.[] | select(.name | test("greptile"; "i")) | .state') +``` + +If Greptile is **not** already running (`PENDING` or `IN_PROGRESS`), request a fresh review: + +```bash +if [ "$GREPTILE_STATE" != "PENDING" ] && [ "$GREPTILE_STATE" != "IN_PROGRESS" ]; then + gh pr comment --body "@greptile review" +fi +``` + +Then poll for the Greptile check run to complete: + +```bash +HEAD_SHA=$(gh pr view --json headRefOid -q .headRefOid) + +while true; do + GREPTILE_CHECK=$(gh api "repos/{owner}/{repo}/commits/$HEAD_SHA/check-runs" \ + --jq '.check_runs[] | select(.name | test("greptile"; "i"))' 2>/dev/null) + + if [ -z "$GREPTILE_CHECK" ]; then + echo "Waiting for Greptile check to appear..." + sleep 5 + continue + fi + + STATUS=$(echo "$GREPTILE_CHECK" | jq -r '.status // "completed"') + CONCLUSION=$(echo "$GREPTILE_CHECK" | jq -r '.conclusion // "pending"') + + if [ "$STATUS" = "completed" ]; then + if [ "$CONCLUSION" = "success" ]; then + echo "Greptile check passed!" + else + echo "Greptile check completed with: $CONCLUSION" + fi + break + fi + + echo "Waiting for Greptile... (status: $STATUS)" + sleep 10 +done +``` + +**GitLab** — check if Greptile is already running before posting a trigger comment: + +```bash +PIPELINES=$(glab api "projects/:fullpath/merge_requests//pipelines") +GREPTILE_RUNNING=$(echo "$PIPELINES" | jq '[.[] | select(.status == "running" or .status == "pending")] | length') +``` + +If no pipeline is running, post a trigger comment: + +```bash +if [ "$GREPTILE_RUNNING" = "0" ]; then + glab mr note --message "@greptile review" +fi +``` + +**Perforce** — Perforce does not have native check runs. If Greptile is integrated via a webhook triggered on `p4 shelve`, wait for it to process. Check your Greptile installation's webhook endpoint or dashboard for the review status. Poll by re-fetching the Greptile review comment on the CL until a score appears. + +Then poll for the Greptile pipeline job to complete (see [GitLab API reference](references/gitlab-api.md)): + +```bash +HEAD_SHA=$(glab mr view --output json | jq -r '.sha') + +while true; do + PIPELINES=$(glab api "projects/:fullpath/merge_requests//pipelines") + # Find the most recent pipeline for this SHA + PIPELINE_ID=$(echo "$PIPELINES" | jq -r --arg sha "$HEAD_SHA" \ + '[.[] | select(.sha == $sha)] | sort_by(.id) | last | .id // empty') + + if [ -z "$PIPELINE_ID" ]; then + echo "Waiting for Greptile pipeline to appear..." + sleep 5 + continue + fi + + JOBS=$(glab api "projects/:fullpath/pipelines/$PIPELINE_ID/jobs") + GREPTILE_JOB=$(echo "$JOBS" | jq '.[] | select(.name | test("greptile"; "i"))') + + if [ -z "$GREPTILE_JOB" ]; then + echo "Waiting for Greptile job to appear..." + sleep 5 + continue + fi + + JOB_STATUS=$(echo "$GREPTILE_JOB" | jq -r '.status') + + if [ "$JOB_STATUS" = "success" ] || [ "$JOB_STATUS" = "failed" ] || [ "$JOB_STATUS" = "canceled" ]; then + echo "Greptile job completed with: $JOB_STATUS" + break + fi + + echo "Waiting for Greptile... (status: $JOB_STATUS)" + sleep 10 +done +``` + +#### B. Fetch Greptile review results + +Greptile may surface its score in several places — check **all** of the relevant sources: + +**GitHub:** + +**1. PR description (body):** +```bash +gh pr view --json body -q '.body' +``` + +**2. General PR comments (issue comments):** +```bash +gh api --paginate "repos/{owner}/{repo}/issues//comments?per_page=100" +``` + +Filter for Greptile-authored comments and use the body from the most recently updated comment (`updated_at`), not the most recently created comment. Greptile may edit the same general PR comment on each review cycle; parse the current body, including the "Prompt to fix all with AI" section, before deciding there are no remaining issues. + +**3. PR reviews:** +```bash +gh api repos/{owner}/{repo}/pulls//reviews +``` + +Look for the most recent entry from `greptile-apps[bot]` or `greptile-apps-staging[bot]`. + +**GitLab:** + +**1. MR description (body):** +```bash +glab mr view --output json | jq -r '.description' +``` + +**2. MR notes (comments):** +```bash +glab api "projects/:fullpath/merge_requests//notes" +``` + +Filter for notes from the Greptile bot user (check the `author.username` field — the exact username may vary per installation; verify on first run). + +**Perforce:** + +**1. CL description:** +```bash +p4 describe -s +``` +Check the description field for a Greptile-appended score block. + +**2. CL comments / review notes:** +If your installation uses a review tool such as Helix Swarm, fetch comments via its API. + +Example (Swarm API): +GET /api/v11/comments?topic=reviews/ + +Response fields of interest typically include: +- user (author username) +- body (comment text) +- flags/state indicating whether the comment is resolved + +Filter to comments authored by the Greptile bot: +- Prefer exact username match if known +- Otherwise, use a heuristic where the author name contains "greptile" (case-insensitive) + +For all platforms, parse the text for: +- **Confidence score**: a pattern like `3/5` or `5/5` (or `Confidence: 3/5`). +- **Comment count**: Number of inline review comments noted in the summary. + +Use whichever source has the **most recently updated** score. For GitHub, prefer `updated_at` from issue comments when comparing an edited Greptile summary against older review entries. + +Also fetch all unresolved inline comments: + +**GitHub:** +```bash +gh api repos/{owner}/{repo}/pulls//comments +``` + +Also carry forward actionable items from the latest Greptile general PR comment, especially the "Prompt to fix all with AI" section, even if the inline comment endpoint returns zero unresolved comments. + +**GitLab:** +```bash +glab api "projects/:fullpath/merge_requests//discussions" +``` + +Filter to `DiffNote` type discussions (`notes[0].type == "DiffNote"`) from Greptile that are on the latest commit and not yet resolved (`"resolved": false`). + +**Perforce:** +If using Swarm: + +# Fetch inline diff comments for the review associated with the CL +GET /api/v11/comments?topic=reviews/ + +Filter to comments from the Greptile bot user that have not been marked as resolved/addressed. + +#### C. Check exit conditions + +Stop the loop if **any** of these are true: + +- Confidence score is **5/5** AND there are **zero unresolved comments** +- Max iterations reached (report current state) + +#### D. Fix actionable comments + +For each unresolved Greptile comment: + +1. Read the file and understand the comment in context. +2. Determine if it's actionable (code change needed) or informational. +3. If actionable, make the fix. +4. If informational or a false positive, note it but still resolve the thread. + +#### E. Resolve threads + +**GitHub** — fetch unresolved review threads and resolve all that have been addressed (see [GraphQL reference](references/graphql-queries.md)): + +```bash +gh api graphql -f query=' +query($cursor: String) { + repository(owner: "OWNER", name: "REPO") { + pullRequest(number: PR_NUMBER) { + reviewThreads(first: 100, after: $cursor) { + pageInfo { hasNextPage endCursor } + nodes { + id + isResolved + comments(first: 1) { + nodes { body path author { login } } + } + } + } + } + } +}' +``` + +Resolve addressed threads: + +```bash +gh api graphql -f query=' +mutation { + t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } } + t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } } +}' +``` + +**GitLab** — fetch unresolved discussions and resolve each one (see [GitLab API reference](references/gitlab-api.md)): + +```bash +glab api "projects/:fullpath/merge_requests//discussions?per_page=100" +``` + +Filter for `"resolved": false` discussions. Then resolve each by its `id`: + +```bash +glab api --method PUT \ + "projects/:fullpath/merge_requests//discussions/" \ + --field resolved=true +``` + +Repeat for each unresolved discussion ID. (GitLab has no batch resolution — loop through each one.) + +#### F. Commit and push / re-shelve + +**GitHub/GitLab:** +```bash +git add -A +git commit -m "address greptile review feedback (greploop iteration N)" +git push +``` + +**Perforce:** +```bash +# Stage changes back into the CL and re-shelve for the next review round +p4 shelve -f -c +``` + +Wait for checks to start after push/shelve: + +```bash +sleep 5 +``` + +Then go back to step **A**. + +### 3. Report + +After exiting the loop, summarize: + +| Field | Value | +| ------------------ | ---------- | +| Platform | GitHub / GitLab / Perforce | +| Iterations | N | +| Final confidence | X/5 | +| Comments resolved | N | +| Remaining comments | N (if any) | + +If the loop exited due to max iterations, list any remaining unresolved comments and suggest next steps. + +## Output format + +``` +Greploop complete. + Platform: GitHub + Iterations: 2 + Confidence: 5/5 + Resolved: 7 comments + Remaining: 0 +``` + +If not fully resolved: + +``` +Greploop stopped after 5 iterations. + Platform: GitLab + Confidence: 4/5 + Resolved: 12 comments + Remaining: 2 + +Remaining issues: + - src/auth.ts:45 — "Consider rate limiting this endpoint" + - src/db.ts:112 — "Missing index on user_id column" +``` + +**Perforce example:** + +``` +Greploop complete. + Platform: Perforce + Changelist: 12345 + Iterations: 3 + Confidence: 5/5 + Resolved: 9 comments + Remaining: 0 +``` diff --git a/plugins/greptile/agent/skills/greploop/references/gitlab-api.md b/plugins/greptile/agent/skills/greploop/references/gitlab-api.md new file mode 100644 index 00000000..bdd7ae74 --- /dev/null +++ b/plugins/greptile/agent/skills/greploop/references/gitlab-api.md @@ -0,0 +1,93 @@ +# GitLab API Reference + +Useful GitLab REST API calls for the greploop workflow, using `glab api`. + +`glab api` automatically resolves `:fullpath` to the URL-encoded project path from the local git remote. + +## Fetch MR details + +```bash +glab mr view --output json +``` + +Key fields: +- `iid` — internal MR number (use this, not `id`) +- `source_branch` — equivalent to GitHub's `headRefName` +- `sha` — HEAD commit SHA +- `description` — MR body (Greptile may update this with the confidence score) + +## Trigger Greptile review + +```bash +glab mr note --message "@greptile review" +``` + +## Fetch pipelines for an MR + +```bash +glab api "projects/:fullpath/merge_requests//pipelines" +``` + +Check `status` field: `running`, `pending`, `success`, `failed`, `canceled`, `skipped`. + +## Fetch jobs for a pipeline (to find the Greptile job) + +```bash +glab api "projects/:fullpath/pipelines//jobs" +``` + +Filter jobs where `name` matches `greptile` (case-insensitive). Terminal statuses: `success`, `failed`, `canceled`. + +## Check if any pipeline is running + +```bash +glab api "projects/:fullpath/merge_requests//pipelines" | \ + jq '[.[] | select(.status == "running" or .status == "pending")] | length' +``` + +Returns `0` if no pipelines are running/pending. + +## Find pipeline for a specific commit SHA + +```bash +glab api "projects/:fullpath/merge_requests//pipelines" | \ + jq -r --arg sha "COMMIT_SHA" '[.[] | select(.sha == $sha)] | sort_by(.id) | last | .id // empty' +``` + +## Fetch MR notes (to find Greptile's confidence score) + +```bash +glab api "projects/:fullpath/merge_requests//notes?per_page=100&sort=desc&order_by=created_at" +``` + +Filter by `author.username` for the Greptile bot. Scan `body` for a confidence pattern like `3/5` or `5/5`. + +The Greptile bot username on GitLab may differ from GitHub's `greptile-apps[bot]` — check the first Greptile comment on the MR to identify the exact username. + +## Fetch unresolved discussions (inline comments) + +```bash +glab api "projects/:fullpath/merge_requests//discussions?per_page=100" +``` + +Paginate with `&page=2`, etc. until response array length < `per_page`. + +Filter for unresolved inline diff comments from Greptile: +```bash +jq '[.[] | select(.resolved == false and (.notes[0].type == "DiffNote") and (.notes[0].author.username == "GREPTILE_BOT_USERNAME"))]' +``` + +Each discussion has: +- `id` — use this for resolution +- `notes[0].body` — the comment text +- `notes[0].position.new_path` — file path + +## Resolve a discussion + +```bash +glab api --method PUT \ + "projects/:fullpath/merge_requests//discussions/" \ + --field resolved=true +``` + +GitLab has no batch resolution — issue one PUT per discussion. diff --git a/plugins/greptile/agent/skills/greploop/references/graphql-queries.md b/plugins/greptile/agent/skills/greploop/references/graphql-queries.md new file mode 100644 index 00000000..b3727c16 --- /dev/null +++ b/plugins/greptile/agent/skills/greploop/references/graphql-queries.md @@ -0,0 +1,49 @@ +# GraphQL Queries Reference + +## Fetch unresolved review threads (paginated) + +```graphql +query($cursor: String) { + repository(owner: "OWNER", name: "REPO") { + pullRequest(number: PR_NUMBER) { + reviewThreads(first: 100, after: $cursor) { + pageInfo { hasNextPage endCursor } + nodes { + id + isResolved + comments(first: 3) { + nodes { + body + path + author { login } + createdAt + } + } + } + } + } + } +} +``` + +## Batch-resolve threads + +```graphql +mutation { + t1: resolveReviewThread(input: {threadId: "ID1"}) { thread { isResolved } } + t2: resolveReviewThread(input: {threadId: "ID2"}) { thread { isResolved } } +} +``` + +## Fetch general PR comments edited in place (REST) + +General PR comments are issue comments. Greptile may update one summary comment repeatedly, so select by `updated_at` instead of `created_at`: + +```bash +gh api --paginate "repos/{owner}/{repo}/issues//comments?per_page=100" \ + | jq -s 'add + | map(select(.user.login | test("greptile"; "i"))) + | sort_by(.updated_at) + | last + | {author: .user.login, updated_at, body}' +``` diff --git a/plugins/lavish/.agents/skills/lavish/SKILL.md b/plugins/lavish/.agents/skills/lavish/SKILL.md index 70b2e7b1..fac4ab56 100644 --- a/plugins/lavish/.agents/skills/lavish/SKILL.md +++ b/plugins/lavish/.agents/skills/lavish/SKILL.md @@ -34,9 +34,10 @@ Use lavish-axi when the user asks for a visual artifact, HTML explainer, interac 3. Run `npx -y lavish-axi poll ` to long-poll for the user's annotations, queued prompts, and browser-reported `layout_warnings`. The poll stays silent until the user acts or the real browser reports fresh layout warnings - leave it running, never kill it. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost. -4. If poll returns `layout_warnings`, fix overflow, clipped text, or overlapping unreadable content and re-check before involving the human. +4. If poll returns `layout_warnings`, follow the returned `next_step`: fix and re-check fresh error-severity findings, but proceed with a note instead of looping when every current warning is persistent or low-severity. 5. Apply human feedback, then poll again with `--agent-reply ""` to reply in the browser and keep the loop going. 6. Run `npx -y lavish-axi end ` when the review is finished. +7. If the user ends the session from the browser instead, `npx -y lavish-axi ` refuses to reopen it and says so - only pass `--reopen` when the user asks for further review or something genuinely important needs their visual attention. Otherwise deliver remaining updates directly in this conversation. ## Visual guidance @@ -44,6 +45,7 @@ Use lavish-axi when the user asks for a visual artifact, HTML explainer, interac - Use visual structure such as sections, cards, tables, diagrams, annotated snippets, and side-by-side comparisons instead of long prose - Choose typography, spacing, color, and layout deliberately so the artifact has a clear point of view - Prevent horizontal overflow at every nesting level: nested grid/flex children also need minmax(0, 1fr) tracks and min-width: 0, especially when badges, labels, or status text use wide pixel or monospace fonts; wrap, truncate, or contain long unbreakable text deliberately +- When the artifact would describe existing or current UI or state, show it instead: capture screenshots of the real pages (run the app read-only if needed) and embed them, rather than explaining the current look in prose; reserve prose for what cannot be shown such as rationale, trade-offs, and open questions ## Playbooks @@ -61,11 +63,13 @@ For flows, architecture, state, or sequence diagrams, do not hand-build boxes-an ## Commands & rules -- Run `npx -y lavish-axi ` to open or resume a Lavish Editor session +- Run `npx -y lavish-axi ` to open or resume a Lavish Editor session. If the user explicitly ended the session from the browser, this refuses to reopen it and explains why instead of reopening uninvited - pass `--reopen` only when the user asks for further review or something important needs their visual attention - Unless the user specifies another location, create HTML artifacts in the current working directory under `.lavish/` - Lavish serves the html file through a local express.js server. If your html needs to reference other filesystem assets such as images, CSS, fonts, and local scripts, copy them into the same directory as the HTML file, then reference them with relative paths from that directory. Never prepend `/` to those asset paths - root paths won't work -- Run `npx -y lavish-axi poll ` to wait for user feedback or browser-reported layout_warnings. It long-polls and stays silent until the user sends feedback, ends the session, or the real browser reports fresh layout_warnings, so leave it running - never kill it. Fix layout_warnings before involving the human. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost -- Run `npx -y lavish-axi end ` to end a session +- Run `npx -y lavish-axi poll ` to wait for user feedback or browser-reported layout_warnings. It long-polls and stays silent until the user sends feedback, ends the session, or the real browser reports fresh layout_warnings, so leave it running - never kill it. Fix and re-check fresh error-severity layout_warnings before involving the human; if the poll says every current warning is persistent or low-severity, proceed with a note instead of looping. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost. When it reports the session ended, stop polling and do not reopen it uninvited - deliver remaining updates in this conversation instead +- Run `npx -y lavish-axi end ` to end a session as the agent - ending it this way still allows a plain reopen later. When the user ends it from the browser instead, a later `npx -y lavish-axi ` refuses to reopen it without `--reopen` +- Run `npx -y lavish-axi export [--out ]` to write a portable copy of the artifact - one HTML file with its LOCAL assets inlined - so it opens with no Lavish server and no sibling files. Remote CDN/font references are left as links, so it needs network to render those. Users can also export from the browser chrome's overflow menu +- Run `npx -y lavish-axi share [--password ] [--token ]` to publish the artifact on ht-ml.app (https://ht-ml.app), a third-party hosting service not part of Lavish, and get back a visitable URL. Shares are PUBLIC by default, so anyone with the link can open them. Pass --password to publish a PRIVATE password-protected page; viewers must supply the password to view. Local assets are inlined; remote refs load over the network. It returns the url plus a secret update_key for managing the page later. Use --token or LAVISH_AXI_HTML_APP_TOKEN only when you have an optional bearer token; it is never required. Users can also publish from the browser chrome's overflow menu - Run `npx -y lavish-axi stop` to shut down the background server (it also self-stops when idle or after the last session ends with nothing connected) - Run `npx -y lavish-axi playbook ` for focused artifact guidance. One artifact often combines several playbooks (for example a plan that includes a comparison and a diagram), so MUST open each matching playbook before writing HTML. - Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and match that project's design system: Tailwind or theme config, shared CSS variables or design tokens, component library, brand assets, or existing styled pages. If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo; (3) only when both steps come up empty, use the Lavish-recommended Tailwind CSS browser runtime v4 + DaisyUI v5, available via CDN - run `npx -y lavish-axi design` for a content-to-playbook router, a copy-pasteable CDN snippet, a Mermaid CDN snippet/init for diagrams, and the DaisyUI component reference, and prefer the Tailwind/DaisyUI CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user. When you deliver the artifact, state which of the three design sources you used and why. diff --git a/plugins/lavish/agent/skills/lavish/SKILL.md b/plugins/lavish/agent/skills/lavish/SKILL.md index 1e9a9469..256f3495 100644 --- a/plugins/lavish/agent/skills/lavish/SKILL.md +++ b/plugins/lavish/agent/skills/lavish/SKILL.md @@ -26,9 +26,10 @@ Use lavish-axi when the user asks for a visual artifact, HTML explainer, interac 3. Run `npx -y lavish-axi poll ` to long-poll for the user's annotations, queued prompts, and browser-reported `layout_warnings`. The poll stays silent until the user acts or the real browser reports fresh layout warnings - leave it running, never kill it. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost. -4. If poll returns `layout_warnings`, fix overflow, clipped text, or overlapping unreadable content and re-check before involving the human. +4. If poll returns `layout_warnings`, follow the returned `next_step`: fix and re-check fresh error-severity findings, but proceed with a note instead of looping when every current warning is persistent or low-severity. 5. Apply human feedback, then poll again with `--agent-reply ""` to reply in the browser and keep the loop going. 6. Run `npx -y lavish-axi end ` when the review is finished. +7. If the user ends the session from the browser instead, `npx -y lavish-axi ` refuses to reopen it and says so - only pass `--reopen` when the user asks for further review or something genuinely important needs their visual attention. Otherwise deliver remaining updates directly in this conversation. ## Visual guidance @@ -36,6 +37,7 @@ Use lavish-axi when the user asks for a visual artifact, HTML explainer, interac - Use visual structure such as sections, cards, tables, diagrams, annotated snippets, and side-by-side comparisons instead of long prose - Choose typography, spacing, color, and layout deliberately so the artifact has a clear point of view - Prevent horizontal overflow at every nesting level: nested grid/flex children also need minmax(0, 1fr) tracks and min-width: 0, especially when badges, labels, or status text use wide pixel or monospace fonts; wrap, truncate, or contain long unbreakable text deliberately +- When the artifact would describe existing or current UI or state, show it instead: capture screenshots of the real pages (run the app read-only if needed) and embed them, rather than explaining the current look in prose; reserve prose for what cannot be shown such as rationale, trade-offs, and open questions ## Playbooks @@ -53,11 +55,13 @@ For flows, architecture, state, or sequence diagrams, do not hand-build boxes-an ## Commands & rules -- Run `npx -y lavish-axi ` to open or resume a Lavish Editor session +- Run `npx -y lavish-axi ` to open or resume a Lavish Editor session. If the user explicitly ended the session from the browser, this refuses to reopen it and explains why instead of reopening uninvited - pass `--reopen` only when the user asks for further review or something important needs their visual attention - Unless the user specifies another location, create HTML artifacts in the current working directory under `.lavish/` - Lavish serves the html file through a local express.js server. If your html needs to reference other filesystem assets such as images, CSS, fonts, and local scripts, copy them into the same directory as the HTML file, then reference them with relative paths from that directory. Never prepend `/` to those asset paths - root paths won't work -- Run `npx -y lavish-axi poll ` to wait for user feedback or browser-reported layout_warnings. It long-polls and stays silent until the user sends feedback, ends the session, or the real browser reports fresh layout_warnings, so leave it running - never kill it. Fix layout_warnings before involving the human. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost -- Run `npx -y lavish-axi end ` to end a session +- Run `npx -y lavish-axi poll ` to wait for user feedback or browser-reported layout_warnings. It long-polls and stays silent until the user sends feedback, ends the session, or the real browser reports fresh layout_warnings, so leave it running - never kill it. Fix and re-check fresh error-severity layout_warnings before involving the human; if the poll says every current warning is persistent or low-severity, proceed with a note instead of looping. If your harness limits how long a foreground command may run, run the poll as a background task; if it gets killed or times out anyway, just re-run it - queued feedback is never lost. When it reports the session ended, stop polling and do not reopen it uninvited - deliver remaining updates in this conversation instead +- Run `npx -y lavish-axi end ` to end a session as the agent - ending it this way still allows a plain reopen later. When the user ends it from the browser instead, a later `npx -y lavish-axi ` refuses to reopen it without `--reopen` +- Run `npx -y lavish-axi export [--out ]` to write a portable copy of the artifact - one HTML file with its LOCAL assets inlined - so it opens with no Lavish server and no sibling files. Remote CDN/font references are left as links, so it needs network to render those. Users can also export from the browser chrome's overflow menu +- Run `npx -y lavish-axi share [--password ] [--token ]` to publish the artifact on ht-ml.app (https://ht-ml.app), a third-party hosting service not part of Lavish, and get back a visitable URL. Shares are PUBLIC by default, so anyone with the link can open them. Pass --password to publish a PRIVATE password-protected page; viewers must supply the password to view. Local assets are inlined; remote refs load over the network. It returns the url plus a secret update_key for managing the page later. Use --token or LAVISH_AXI_HTML_APP_TOKEN only when you have an optional bearer token; it is never required. Users can also publish from the browser chrome's overflow menu - Run `npx -y lavish-axi stop` to shut down the background server (it also self-stops when idle or after the last session ends with nothing connected) - Run `npx -y lavish-axi playbook ` for focused artifact guidance. One artifact often combines several playbooks (for example a plan that includes a comparison and a diagram), so MUST open each matching playbook before writing HTML. - Lavish does not auto-inject any design system - artifacts stay portable so they render identically when opened directly without lavish-axi running. Before writing any HTML, decide the design direction in this strict priority order, and only move to the next step when the current one truly yields nothing: (1) if the user asked for a specific look or named design system, use that; (2) otherwise you must first inspect the project the artifact is about - the subject or product whose content or UI it represents, which may differ from your current working directory - and match that project's design system: Tailwind or theme config, shared CSS variables or design tokens, component library, brand assets, or existing styled pages. If the artifact previews, proposes, or mocks a specific app's UI, render it in that app's own design system so it faithfully shows the product, even when you are running in a different repo; (3) only when both steps come up empty, use the Lavish-recommended Tailwind CSS browser runtime v4 + DaisyUI v5, available via CDN - run `npx -y lavish-axi design` for a content-to-playbook router, a copy-pasteable CDN snippet, a Mermaid CDN snippet/init for diagrams, and the DaisyUI component reference, and prefer the Tailwind/DaisyUI CDN snippet over hand-writing styles unless explicitly instructed otherwise by the user. When you deliver the artifact, state which of the three design sources you used and why. diff --git a/plugins/lavish/skills-lock.json b/plugins/lavish/skills-lock.json index 8c606d84..0f5b5295 100644 --- a/plugins/lavish/skills-lock.json +++ b/plugins/lavish/skills-lock.json @@ -5,7 +5,7 @@ "source": "kunchenguid/lavish-axi", "sourceType": "github", "skillPath": "skills/lavish/SKILL.md", - "computedHash": "7fdc9a25ba80783b336fcd8ffbc9624274ad0647bf383004b5bdd1035a9229f2" + "computedHash": "c3a0299d820bc3b30613d7740718b194511201319047fa9d3075e0ab1e596bde" } } } diff --git a/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md b/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md index 2eb6f690..5ba3b6c8 100644 --- a/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md +++ b/plugins/nuxt-ui/.agents/skills/nuxt-ui/references/layouts/chat.md @@ -60,34 +60,40 @@ html.dark .shiki span { Using [Vercel AI Gateway](https://vercel.com/ai-gateway) (recommended): ```ts [server/api/chat.post.ts] -import { streamText, convertToModelMessages } from 'ai' +import { streamText, convertToModelMessages, toUIMessageStream, createUIMessageStreamResponse } from 'ai' import { gateway } from '@ai-sdk/gateway' export default defineEventHandler(async (event) => { const { messages } = await readBody(event) - return streamText({ - model: gateway('anthropic/claude-sonnet-4.6'), - system: 'You are a helpful assistant.', + const result = streamText({ + model: gateway('anthropic/claude-sonnet-5'), + instructions: 'You are a helpful assistant.', messages: await convertToModelMessages(messages) - }).toUIMessageStreamResponse() + }) + + const stream = toUIMessageStream({ stream: result.stream }) + return createUIMessageStreamResponse({ stream }) }) ``` Or with a direct provider (e.g., `pnpm add @ai-sdk/openai`): ```ts [server/api/chat.post.ts] -import { streamText, convertToModelMessages } from 'ai' +import { streamText, convertToModelMessages, toUIMessageStream, createUIMessageStreamResponse } from 'ai' import { openai } from '@ai-sdk/openai' export default defineEventHandler(async (event) => { const { messages } = await readBody(event) - return streamText({ + const result = streamText({ model: openai('gpt-5-nano'), - system: 'You are a helpful assistant.', + instructions: 'You are a helpful assistant.', messages: await convertToModelMessages(messages) - }).toUIMessageStreamResponse() + }) + + const stream = toUIMessageStream({ stream: result.stream }) + return createUIMessageStreamResponse({ stream }) }) ``` @@ -108,7 +114,7 @@ UDashboardPanel ```vue [pages/chat/[id].vue] @@ -137,7 +143,7 @@ function onSubmit() {