@pythoughts/vue-skills-mcp 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pythoughts/vue-skills-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "type": "module",
5
5
  "description": "MCP server exposing the Vue 3 best-practice skills so any MCP coding agent can fetch them automatically on Vue work.",
6
6
  "author": "Mohamed Elkholy (elkaix)",
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: vue-ai-apps
3
3
  description: "Building AI/LLM and agent apps with Vue 3 and Nuxt: streaming chat UIs, the Vercel AI SDK (`ai` + `@ai-sdk/vue`), `useChat`, tool calling, structured output, and abort/error handling. Load for AI chatbots, assistant UIs, LLM streaming, or agent frontends in Vue or Nuxt."
4
- version: "1.0.0"
4
+ version: "1.1.1"
5
5
  license: MIT
6
6
  author: github.com/Pythoughts-labs
7
7
  ---
@@ -16,14 +16,14 @@ Assumes the foundations in `vue-best-practices` (Composition API, `<script setup
16
16
 
17
17
  - **Keys never reach the client.** The provider API key lives on the server. The browser talks to *your* endpoint, never to the model provider directly.
18
18
  - **Server streams, client consumes.** A server route runs `streamText`/`streamObject` and returns a stream; the Vue component renders it incrementally. Never block on the full response.
19
- - **Render message *parts*, not a content string.** AI SDK v5 messages are `UIMessage[]` made of typed `parts` (text, tool calls, reasoning). Iterate `message.parts`.
19
+ - **Render message *parts*, not a content string.** AI SDK messages are `UIMessage[]` made of typed `parts` (text, tool calls, reasoning). Iterate `message.parts`.
20
20
  - **Drive UI from `status`, not a boolean.** Disabled inputs, spinners, and the stop button key off the `status` state machine.
21
21
 
22
22
  ## 1) Confirm the stack (required)
23
23
 
24
24
  - Packages: `ai` (core), `@ai-sdk/vue` (composables), a provider (`@ai-sdk/openai`, `@ai-sdk/anthropic`, …), `zod` for tool/object schemas.
25
25
  - `useChat` from `@ai-sdk/vue` works against **any** streaming backend. The server snippets here use **Nuxt/Nitro** (`defineEventHandler`, `readBody`); for a non-Nuxt backend, keep the same AI SDK calls in your own route handler.
26
- - AI SDK **v5** is assumed (messages have `parts`; the hook does not manage input; `status` replaces `isLoading`; tool schemas use `inputSchema`). If the project is on v4, these APIs differ — check the installed version first.
26
+ - This skill targets the **v5+ API**, verified against `ai@7` / `@ai-sdk/vue@4`: messages have `parts`; the hook does not manage input; `status` is `'submitted' | 'streaming' | 'ready' | 'error'`; tool schemas use `inputSchema`; `useObject` is exported as `experimental_useObject`. The pre-v5 API (`ai@4`: `message.content`, hook-managed `input`, `isLoading`, `parameters`) differs — check the installed version first.
27
27
 
28
28
  ## 2) Build the streaming chat UI (required for chat features)
29
29
 
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Abort and Error Handling for AI Streams (AI SDK v5)
2
+ title: Abort and Error Handling for AI Streams (AI SDK v5+)
3
3
  impact: HIGH
4
4
  impactDescription: A streaming UI with no stop button and no error surface leaves users stuck on hung or failed requests
5
5
  type: best-practice
6
6
  tags: [vue3, nuxt, ai-sdk, useChat, abort, error-handling, streaming]
7
7
  ---
8
8
 
9
- # Abort and Error Handling for AI Streams (AI SDK v5)
9
+ # Abort and Error Handling for AI Streams (AI SDK v5+)
10
10
 
11
11
  **Impact: HIGH** - LLM streams are long-running and can fail mid-response. `useChat` exposes everything needed — `status`, `stop()`, `error`, `clearError()`, `regenerate()`, and an `onError` option — but none of it is wired up by default. A chat UI is not shippable until the user can stop a runaway generation and recover from an error.
12
12
 
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Streaming Chat UI with useChat (AI SDK v5)
2
+ title: Streaming Chat UI with useChat (AI SDK v5+)
3
3
  impact: HIGH
4
4
  impactDescription: Rendering message.content or managing input inside the hook is the v4 API and silently breaks in v5
5
5
  type: capability
6
6
  tags: [vue3, nuxt, ai-sdk, useChat, streaming, llm, chat]
7
7
  ---
8
8
 
9
- # Streaming Chat UI with useChat (AI SDK v5)
9
+ # Streaming Chat UI with useChat (AI SDK v5+)
10
10
 
11
11
  **Impact: HIGH** - In AI SDK v5 the Vue `useChat` composable no longer manages the input field, exposes `status` instead of `isLoading`, and returns messages as `UIMessage[]` built from typed `parts`. Code written for v4 (`input`, `handleSubmit`, `message.content`, `isLoading`) compiles but renders nothing useful.
12
12
 
@@ -48,7 +48,7 @@ export default defineEventHandler(async (event) => {
48
48
 
49
49
  const result = streamText({
50
50
  model: openai('gpt-4o'),
51
- messages: convertToModelMessages(messages),
51
+ messages: await convertToModelMessages(messages),
52
52
  })
53
53
 
54
54
  // Standard v5 streaming response. (The Nuxt template also shows a
@@ -94,6 +94,7 @@ function send() {
94
94
  - `useChat` returns Vue refs (`messages.value`, `status.value`); templates unwrap them automatically.
95
95
  - `status` values: `'submitted'` (sent, awaiting first token) → `'streaming'` (receiving) → `'ready'` (done) → `'error'`. Treat `submitted` + `streaming` as busy.
96
96
  - `sendMessage` also accepts files/attachments and per-call options; `text` is the common case.
97
+ - `convertToModelMessages` is **async in `ai@7`** (returns `Promise<ModelMessage[]>`); `await` it. It was synchronous in early v5 — copying old code drops the `await` and passes a Promise to `streamText`.
97
98
  - The core `streamText` signature can change between AI SDK minors — verify against the installed version rather than copying blindly.
98
99
 
99
100
  ## Reference
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Streaming Structured Output in Vue (AI SDK v5)
2
+ title: Streaming Structured Output in Vue (AI SDK v5+)
3
3
  impact: MEDIUM
4
4
  impactDescription: Use streamObject + useObject for typed data; the object streams in partial, so the UI must tolerate undefined fields
5
5
  type: capability
6
6
  tags: [vue3, nuxt, ai-sdk, streamObject, useObject, structured-output, zod]
7
7
  ---
8
8
 
9
- # Streaming Structured Output in Vue (AI SDK v5)
9
+ # Streaming Structured Output in Vue (AI SDK v5+)
10
10
 
11
11
  **Impact: MEDIUM** - When the model should return a typed object (a recipe, a form, an extraction) rather than chat, use `streamObject` on the server and the `useObject` composable on the client. The object arrives **incrementally as a deep-partial**, so every field can be `undefined` mid-stream. Templates must guard with optional chaining and `v-if`, or they throw while streaming.
12
12
 
@@ -18,7 +18,7 @@ tags: [vue3, nuxt, ai-sdk, streamObject, useObject, structured-output, zod]
18
18
  - [ ] Return `result.toTextStreamResponse()`
19
19
  - [ ] Drive the UI from `useObject`'s `object`, `submit`, `isLoading`
20
20
  - [ ] Treat every field of `object` as possibly `undefined` while streaming
21
- - [ ] Verify the exact `useObject` export name in your installed `@ai-sdk/vue`
21
+ - [ ] Import it as `experimental_useObject` (aliased to `useObject`) from `@ai-sdk/vue`
22
22
 
23
23
  **Incorrect - assuming the object is complete:**
24
24
  ```vue
@@ -55,10 +55,8 @@ export default defineEventHandler(async (event) => {
55
55
  **Correct - component:**
56
56
  ```vue
57
57
  <script setup lang="ts">
58
- // Verify the export name against the installed @ai-sdk/vue:
59
- // it is exposed as `useObject` (cross-framework convention aliases
60
- // it as `experimental_useObject`).
61
- import { useObject } from '@ai-sdk/vue'
58
+ // @ai-sdk/vue exports this only as `experimental_useObject` alias it on import.
59
+ import { experimental_useObject as useObject } from '@ai-sdk/vue'
62
60
  import { z } from 'zod'
63
61
 
64
62
  const schema = z.object({
@@ -81,7 +79,7 @@ const { object, submit, isLoading } = useObject({ api: '/api/recipe', schema })
81
79
 
82
80
  ## Notes
83
81
 
84
- - `useObject` is experimental and available for React, Svelte, and **Vue**. The reference docs page only prints the React import, so confirm the Vue export name (`useObject` vs `experimental_useObject`) in `node_modules/@ai-sdk/vue` for your version.
82
+ - The composable is experimental; `@ai-sdk/vue` exports it as `experimental_useObject` (no plain `useObject`). Verified against `@ai-sdk/vue@4` (with `ai@7`).
85
83
  - `object` is typed as `DeepPartial<Schema>` — TypeScript already forces the optional-chaining discipline above.
86
84
  - For free-form text streaming use `useChat` (or `useCompletion`); reach for `useObject` only when you need a validated shape.
87
85
 
@@ -1,12 +1,12 @@
1
1
  ---
2
- title: Tool Calling in Vue Chat UIs (AI SDK v5)
2
+ title: Tool Calling in Vue Chat UIs (AI SDK v5+)
3
3
  impact: HIGH
4
4
  impactDescription: Tool calls arrive as typed message parts with a state machine; ignoring the state renders blank or stale UI
5
5
  type: capability
6
6
  tags: [vue3, nuxt, ai-sdk, tools, function-calling, agents, useChat]
7
7
  ---
8
8
 
9
- # Tool Calling in Vue Chat UIs (AI SDK v5)
9
+ # Tool Calling in Vue Chat UIs (AI SDK v5+)
10
10
 
11
11
  **Impact: HIGH** - When the model calls a tool, the result surfaces in the chat as a `parts` entry of type `tool-<name>` with a `state` field. The Vue UI must branch on `part.state` (`input-streaming` → `input-available` → `output-available` / `output-error`) to show progress and results. Rendering the part without checking `state` shows nothing while the tool runs, then throws when accessing `part.output` too early.
12
12
 
@@ -42,7 +42,7 @@ export default defineEventHandler(async (event) => {
42
42
 
43
43
  const result = streamText({
44
44
  model: openai('gpt-4o'),
45
- messages: convertToModelMessages(messages),
45
+ messages: await convertToModelMessages(messages),
46
46
  stopWhen: stepCountIs(5), // let the model use a tool then answer
47
47
  tools: {
48
48
  getWeather: tool({
@@ -80,7 +80,7 @@ export default defineEventHandler(async (event) => {
80
80
 
81
81
  - Part type follows the pattern `tool-${toolName}`; dynamically registered tools use type `dynamic-tool` with `part.toolName`.
82
82
  - Useful accessors: `part.input`, `part.output`, `part.toolCallId`, `part.errorText`.
83
- - **Client-side tools** (a `tool()` with no `execute`) are fulfilled from the UI by calling `addToolResult({ tool, toolCallId, output })` returned by `useChat`.
83
+ - **Client-side tools** (a `tool()` with no `execute`) are fulfilled from the UI by calling `addToolOutput({ tool, toolCallId, output })` returned by `useChat` (`addToolResult` is the deprecated alias).
84
84
  - `stepCountIs` / `stopWhen` and the `tool()` signature are core AI SDK API — confirm against the installed version.
85
85
 
86
86
  ## Reference