Skip to content
On this page

Agent 接入案例:Vue 3

Vue 3 使用 useAgent 接入多轮 Agent 对话、工具调用和状态管理。

vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { useAgent } from '@tencent/ssv-ai-sdk-vue';
import { AGUIPlugin } from '@tencent/ssv-ai-sdk-plugin-agui';

const UI_ONLY_TOOLS = ['launchRocket'];
const input = ref('');
const themeColor = ref('#1890ff');

const {
  messages,
  status,
  assistantStatus,
  agentState,
  send,
  stop,
  setMessages,
  setTools,
  on,
  off,
} = useAgent({
  api: {
    chatEndpoint: {
      url: 'https://your-api.com/agent',
    },
  },
  mode: 'stream',
  plugins: [new AGUIPlugin()],
});

onMounted(() => {
  setTools([
    {
      name: 'setThemeColor',
      description: 'Set the page theme color. Use hex format like #1890ff.',
      type: 'frontend',
      parameters: {
        type: 'object',
        properties: {
          color: { type: 'string', description: 'Hex color' },
        },
        required: ['color'],
      },
      handler: async ({ color }) => {
        themeColor.value = color;
        return { success: true, color };
      },
    },
  ]);

  on('toolExecuted', handleToolExecuted);
});

onUnmounted(() => {
  off('toolExecuted', handleToolExecuted);
});

function handleToolExecuted({ toolCallId, toolCallName, result }) {
  if (UI_ONLY_TOOLS.includes(toolCallName)) return;

  const toolMessage = {
    id: `tool-${Date.now()}`,
    role: 'tool',
    content: typeof result === 'string' ? result : JSON.stringify(result),
    toolCallId,
    extraInfo: {},
  };

  setMessages([...messages.value, toolMessage]);
  send({}, { type: 'tools' });
}

async function handleSend() {
  if (!input.value.trim() || status.value === 'loading') return;
  await send({ input: input.value });
  input.value = '';
}
</script>

<template>
  <div :style="{ '--theme-color': themeColor }">
    <div class="messages">
      <div
        v-for="message in messages"
        :key="message.id"
        :class="['message', message.role]"
      >
        <div v-if="message.role === 'user'">{{ message.content }}</div>

        <template v-else-if="message.role === 'assistant'">
          <template v-for="(part, index) in message.parts" :key="part.id || index">
            <div v-if="part.type === 'reasoning'" class="reasoning">
              {{ part.reason }}
            </div>
            <div v-else-if="part.type === 'text'">
              {{ part.text }}
            </div>
            <div v-else-if="part.type === 'tool_call'" class="tool-call">
              工具:{{ part.name }},状态:{{ part.status }}
              <pre v-if="part.result">{{ JSON.stringify(part.result, null, 2) }}</pre>
              <div v-if="part.error" class="error">{{ part.error }}</div>
            </div>
          </template>
        </template>
      </div>
    </div>

    <div>助手状态:{{ assistantStatus }}</div>
    <pre>Agent 状态:{{ JSON.stringify(agentState, null, 2) }}</pre>

    <input v-model="input" placeholder="输入消息..." @keydown.enter="handleSend" />
    <button v-if="status === 'loading'" @click="stop">停止</button>
    <button v-else @click="handleSend">发送</button>
  </div>
</template>

Released under the MIT License.