@standardagents/vue

Vue SDK for Standard Agents
29,444
Install
npm install @standardagents/vue
Latest Version:0.43.1
Vue:3
License:Proprietary
Last Updated:Oct 19, 2026
Links: npm
Maintainer: lnguyen-braid

@standardagents/vue

Vue 3 composables and components for Standard Agents - connect to AI agent threads with real-time updates, send messages, manage files, and listen for custom events.

Installation

npm install @standardagents/vue
# or
pnpm add @standardagents/vue
# or
yarn add @standardagents/vue

Requirements: Vue 3.3+

Quick Start

// main.ts
import { createApp } from 'vue'
import { StandardAgentsPlugin } from '@standardagents/vue'
import App from './App.vue'

const app = createApp(App)
app.use(StandardAgentsPlugin, { endpoint: 'https://api.example.com' })
app.mount('#app')
<!-- App.vue -->
<script setup lang="ts">
import { ThreadProvider, useThread } from '@standardagents/vue'
</script>

<template>
  <ThreadProvider threadId="thread-123">
    <ChatInterface />
  </ThreadProvider>
</template>
<!-- ChatInterface.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { useThread } from '@standardagents/vue'

const { messages, sendMessage, status } = useThread()
const input = ref('')

const handleSend = async () => {
  await sendMessage({ role: 'user', content: input.value })
  input.value = ''
}
</script>

<template>
  <div>
    <p>Status: {{ status }}</p>
    <div v-for="msg in messages" :key="msg.id">
      <strong>{{ msg.role }}:</strong> {{ msg.content }}
    </div>
    <input v-model="input" @keyup.enter="handleSend" />
    <button @click="handleSend">Send</button>
  </div>
</template>

Authentication

The package reads the authentication token from localStorage using the key agentbuilder_auth_token:

// Set the token before using the composables
localStorage.setItem('agentbuilder_auth_token', 'your-token-here')

All API requests and WebSocket connections will automatically include this token.

API Reference

StandardAgentsPlugin

Vue plugin that configures the Standard Agents client for all components.

Options:

  • endpoint: string - The API endpoint URL (required)
import { createApp } from 'vue'
import { StandardAgentsPlugin } from '@standardagents/vue'

const app = createApp(App)
app.use(StandardAgentsPlugin, { endpoint: 'https://api.example.com' })

ThreadProvider

Component that establishes a WebSocket connection to a specific thread and provides context to child components.

Props:

  • threadId: string - The thread ID to connect to
  • preload?: boolean - Fetch existing messages on mount (default: true)
  • live?: boolean - Enable WebSocket for real-time updates (default: true)
  • useWorkblocks?: boolean - Group tool calls into workblocks (default: false)
  • useSubagentBlocks?: boolean - Group referenced child traffic into subagent blocks (default: false). Unresolved runtime lifecycle calls remain ordinary tool work rather than synthetic child cards.
  • depth?: number - Message depth level (default: 0)
  • includeSilent?: boolean - Include silent messages (default: false). With subagent grouping enabled, explicitly included silent messages remain visible in chronological order.
  • endpoint?: string - Override the endpoint from plugin config
<template>
  <ThreadProvider threadId="thread-123" :live="true">
    <YourComponents />
  </ThreadProvider>
</template>

<script setup lang="ts">
import { ThreadProvider } from '@standardagents/vue'
</script>

useThread()

Composable to access the full thread context. Must be used within a ThreadProvider.

Returns:

  • threadId: string - The thread ID
  • messages: Ref<Message[]> - Reactive array of messages
  • workblocks: ComputedRef<ThreadMessage[]> - Messages transformed to workblocks (if useWorkblocks is true)
  • status: Ref<ConnectionStatus> - Connection status ("connecting" | "connected" | "disconnected" | "reconnecting")
  • loading: Ref<boolean> - Loading state (alias: isLoading)
  • error: Ref<Error | null> - Error state
  • options: ThreadProviderOptions - Options passed to the provider
  • sendMessage: (payload: SendMessagePayload) => Promise<Message> - Send a message
  • stopExecution: () => Promise<void> - Stop current execution
  • onEvent: <T>(eventType, callback) => () => void - Subscribe to custom events (alias: subscribeToEvent)
  • files: ComputedRef<ThreadFile[]> - All files (pending + committed)
  • addFiles: (files: File[] | FileList) => void - Upload files
  • removeFile: (id: string) => void - Remove a pending file
  • getFileUrl: (file: ThreadFile) => string - Get file URL
  • getThumbnailUrl: (file: ThreadFile) => string - Get thumbnail URL
  • getPreviewUrl: (file: ThreadFile) => string | null - Get preview URL

Example:

<script setup lang="ts">
import { useThread } from '@standardagents/vue'

const {
  messages,
  sendMessage,
  stopExecution,
  status,
  isLoading,
  files,
  addFiles,
  onEvent,
} = useThread()

// Subscribe to custom events
onEvent<{ todos: string[] }>('todo-updated', (data) => {
  console.log('Todos:', data.todos)
})
</script>

<template>
  <div>
    <p v-if="isLoading">Loading...</p>
    <p>Status: {{ status }}</p>

    <div v-for="msg in messages" :key="msg.id">
      <strong>{{ msg.role }}:</strong> {{ msg.content }}
    </div>

    <input type="file" multiple @change="(e) => addFiles(e.target.files)" />

    <div v-for="file in files" :key="file.id">
      {{ file.name }} ({{ file.status }})
    </div>

    <button @click="sendMessage({ role: 'user', content: 'Hello!' })">Send</button>
    <button @click="stopExecution">Stop</button>
  </div>
</template>

File Management

The useThread() composable provides file management capabilities:

<script setup lang="ts">
import { useThread } from '@standardagents/vue'

const { files, addFiles, removeFile, getPreviewUrl } = useThread()

const handleFileChange = (event: Event) => {
  const input = event.target as HTMLInputElement
  if (input.files) {
    addFiles(input.files)
  }
}
</script>

<template>
  <div>
    <input type="file" multiple accept="image/*,.pdf,.txt" @change="handleFileChange" />

    <div v-for="file in files" :key="file.id">
      <img
        v-if="file.isImage && file.status !== 'uploading'"
        :src="getPreviewUrl(file) || ''"
        :alt="file.name"
        width="50"
      />
      <span>{{ file.name }}</span>
      <span>{{ file.status }}</span>
      <span v-if="file.status === 'uploading'">Uploading...</span>
      <span v-if="file.status === 'error'">Error: {{ file.error }}</span>
      <button v-if="file.status !== 'committed'" @click="removeFile(file.id)">
        Remove
      </button>
    </div>
  </div>
</template>

File States

  • uploading - File is being uploaded
  • ready - Upload complete, file ready to attach to message
  • committed - File is attached to a sent message
  • error - Upload failed

Types

interface Message {
  id: string
  role: 'user' | 'assistant' | 'system' | 'tool'
  content: string | null
  created_at: number
  attachments?: string // JSON array of AttachmentRef
}

interface SendMessagePayload {
  role: 'user' | 'assistant' | 'system'
  content: string
  silent?: boolean
  attachments?: string[]  // Paths of files to attach
}

interface ThreadFile {
  id: string
  name: string
  mimeType: string
  size: number
  isImage: boolean
  status: 'uploading' | 'ready' | 'committed' | 'error'
  error?: string
  path?: string
  localPreviewUrl: string | null
}

type ConnectionStatus = 'connecting' | 'connected' | 'disconnected' | 'reconnecting'

Complete Example

<script setup lang="ts">
import { onMounted } from 'vue'
import { ThreadProvider } from '@standardagents/vue'

onMounted(() => {
  localStorage.setItem('agentbuilder_auth_token', 'your-token')
})
</script>

<template>
  <ThreadProvider threadId="thread-123">
    <AgentChat />
  </ThreadProvider>
</template>
<!-- AgentChat.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { useThread } from '@standardagents/vue'

const input = ref('')

const {
  messages,
  sendMessage,
  stopExecution,
  status,
  isLoading,
  files,
  addFiles,
  removeFile,
  getPreviewUrl,
} = useThread()

const handleSend = async () => {
  if (!input.value.trim()) return
  await sendMessage({ role: 'user', content: input.value })
  input.value = ''
}

const handleFileChange = (event: Event) => {
  const target = event.target as HTMLInputElement
  if (target.files) addFiles(target.files)
}
</script>

<template>
  <div>
    <p v-if="isLoading">Loading messages...</p>

    <div v-for="msg in messages" :key="msg.id">
      <strong>{{ msg.role }}:</strong> {{ msg.content }}
    </div>

    <input type="file" multiple @change="handleFileChange" />

    <div v-for="file in files.filter(f => f.status !== 'committed')" :key="file.id">
      <img
        v-if="file.isImage && getPreviewUrl(file)"
        :src="getPreviewUrl(file)!"
        :alt="file.name"
        width="50"
      />
      <span>{{ file.name }} ({{ file.status }})</span>
      <button @click="removeFile(file.id)">x</button>
    </div>

    <div>
      <input v-model="input" @keyup.enter="handleSend" />
      <button @click="handleSend">Send</button>
      <button @click="stopExecution">Stop</button>
      <span>Status: {{ status }}</span>
    </div>
  </div>
</template>

TypeScript Support

The package includes full TypeScript definitions:

import type {
  Message,
  SendMessagePayload,
  ThreadFile,
  ConnectionStatus,
  ThreadContext,
} from '@standardagents/vue'

Related Packages

@syzlm/fe-ai

面向前端项目的 AI 编码规范初始化工具

3,061
create-coaiforge

Create an independent Vue, NestJS or fullstack project with human-AI collaborati...

811 0
nuxt-agent-md

Generate AGENTS.md with Nuxt documentation for AI coding agents

2,145
@ai-sdk/vue
25,274,128 27,537
balsa-ui

Agent-native, open-code Vue 3 components with independent palettes, themes, and...

2,094 63

Version History

Version Released License
0.43.1 Proprietary
0.43.0 Proprietary
0.42.3 Proprietary
0.42.2 Proprietary
0.42.1 Proprietary
Pre-releases (34)
Version Released License
0.40.5-next.3b25e2a Proprietary
0.27.8-dev.b0d0355 Proprietary
0.17.0-next.1e58032 Proprietary
0.17.0-next.a4b7340 Proprietary
0.16.4-next.a699552 Proprietary