Skip to content

浏览器环境

导入

typescript
// 浏览器环境
import { createAgentClient } from '@multi-agent/a2a/browser'

// Node.js 环境
import { createAgentClient } from '@multi-agent/a2a'

基本用法

typescript
import { createAgentClient } from '@multi-agent/a2a/browser'

const client = createAgentClient({
  agentId: 'chat-agent',
  address: 'a2a://localhost:50054',
})

const stream = await client.call('chat', { message: '你好' })

for await (const msg of stream) {
  if (msg.type === 'progress') console.log(msg.text)
  if (msg.type === 'done') console.log('完成:', msg.data)
}

React 示例

tsx
import { useState, useRef } from 'react'
import { createAgentClient } from '@multi-agent/a2a/browser'

const client = createAgentClient({
  agentId: 'chat-agent',
  address: 'a2a://localhost:50054',
})

const Chat = () => {
  const [messages, setMessages] = useState<string[]>([])
  const [loading, setLoading] = useState(false)
  const abortRef = useRef<AbortController | null>(null)

  const send = async (text: string) => {
    setLoading(true)
    setMessages(prev => [...prev, `You: ${text}`])

    abortRef.current = new AbortController()
    const stream = await client.call('chat', { message: text }, {
      signal: abortRef.current.signal,
    })

    let response = ''
    setMessages(prev => [...prev, 'AI: '])

    for await (const msg of stream) {
      if (msg.type === 'progress') {
        response += msg.text
        setMessages(prev => [...prev.slice(0, -1), `AI: ${response}`])
      }
    }

    setLoading(false)
  }

  const cancel = () => {
    abortRef.current?.abort()
    setLoading(false)
  }

  return (
    <div>
      {messages.map((msg, i) => <div key={i}>{msg}</div>)}
      <input
        onKeyPress={e => {
          if (e.key === 'Enter') {
            send(e.currentTarget.value)
            e.currentTarget.value = ''
          }
        }}
        disabled={loading}
      />
      <button onClick={cancel} disabled={!loading}>取消</button>
    </div>
  )
}

Vue 示例

vue
<script setup lang="ts">
import { ref } from 'vue'
import { createAgentClient } from '@multi-agent/a2a/browser'

const client = createAgentClient({
  agentId: 'chat-agent',
  address: 'a2a://localhost:50054',
})

const messages = ref<string[]>([])
const loading = ref(false)
const input = ref('')
let abortController: AbortController | null = null

const send = async () => {
  if (!input.value.trim()) return
  loading.value = true
  messages.value.push(`You: ${input.value}`)

  abortController = new AbortController()
  const stream = await client.call('chat', { message: input.value }, {
    signal: abortController.signal,
  })
  input.value = ''

  let response = ''
  messages.value.push('AI: ')

  for await (const msg of stream) {
    if (msg.type === 'progress') {
      response += msg.text
      messages.value[messages.value.length - 1] = `AI: ${response}`
    }
  }

  loading.value = false
}

const cancel = () => {
  abortController?.abort()
  loading.value = false
}
</script>

<template>
  <div>
    <div v-for="(msg, i) in messages" :key="i">{{ msg }}</div>
    <input v-model="input" @keypress.enter="send" :disabled="loading" />
    <button @click="cancel" :disabled="!loading">取消</button>
  </div>
</template>

取消请求

typescript
const controller = new AbortController()

const stream = await client.call('chat', { message: 'Hi' }, {
  signal: controller.signal,
})

// 取消按钮
cancelBtn.onclick = () => controller.abort()

for await (const msg of stream) {
  if (msg.type === 'progress') console.log(msg.text)
  if (msg.type === 'done') console.log(msg.data)
}
// 取消后循环正常退出

传递 Metadata

typescript
const stream = await client.call('chat', { message: 'Hi' }, {
  metadata: {
    'x-user-id': 'user-123',
    'x-session-id': 'session-abc',
  },
})

HTTPS 页面连接

HTTPS 页面必须使用 a2as:// 连接启用了 TLS 的 Agent。详见 TLS 配置

与 Node.js 的区别

特性Node.js浏览器
协议gRPCWebSocket
导入@multi-agent/a2a@multi-agent/a2a/browser
Server支持不支持
TLSa2as:// → gRPC + TLSa2as:// → wss://

MIT Licensed