Voice

Add runtime-backed speech-to-text to a Vue chat composer.

Open your coding agent in your project's folder, or in an empty folder for a new app.This runs in a coding agent on your computer.

You can add voice input to CopilotChat without wiring a separate microphone button. The component renders its transcription controls only when the runtime advertises audioFileTranscriptionEnabled and the browser supports MediaRecorder.

When to use this#

  • Use voice input for hands-free, accessibility, mobile, kiosk, and long-form prompts.
  • Use multimodal attachments when the user is sending an audio file rather than speaking live.

Frontend setup#

App.vue
<script setup lang="ts">
import { CopilotChat, CopilotKitProvider } from "@copilotkit/vue/v2";
import "@copilotkit/vue/styles.css";
</script>

<template>
  <CopilotKitProvider runtime-url="/api/copilotkit">
    <CopilotChat />
  </CopilotKitProvider>
</template>

When the user starts recording, the browser requests microphone permission. After recording finishes, the Vue component sends the audio to the runtime, places the returned transcript into the composer, and leaves it editable. The user submits it like any other message; Vue does not auto-send the transcript. Serve production pages over HTTPS so browsers can grant microphone access.

The default REST transport posts multipart form data to {runtimeUrl}/transcribe with an audio field. With use-single-endpoint, the Vue client sends a JSON envelope to runtimeUrl containing base64 audio, mimeType, and filename.

Set the provider prop when your runtime exposes one single endpoint:

<CopilotKitProvider
  runtime-url="/api/copilotkit"
  :use-single-endpoint="true"
>
  <CopilotChat />
</CopilotKitProvider>

Custom audio handling#

Pass on-finish-transcribe-with-audio when your application wants to receive the recorded Blob and handle transcription itself. This callback replaces the default runtime request, so it must put any resulting text into your own UI:

<script setup lang="ts">
async function handleAudio(audio: Blob) {
  const transcript = await myTranscriptionService(audio);
  console.log(transcript);
}
</script>

<template>
  <CopilotChat :on-finish-transcribe-with-audio="handleAudio" />
</template>

The Vue package does not expose the React demo's onTranscribed canned-audio callback or a runnable voice Showcase route. For deterministic demos and tests, call your own handler with a recorded Blob instead of documenting a non-existent Vue prop.

Configure the runtime#

The mic appears only when the runtime has a TranscriptionService. Configure that service in your V2 runtime and mount the normal runtime handler. The service implements:

import {
  CopilotRuntime,
  TranscriptionService,
} from "@copilotkit/runtime/v2";

class MyTranscriptionService extends TranscriptionService {
  async transcribeFile({ audioFile }: { audioFile: File }): Promise<string> {
    return transcribeWithYourProvider(audioFile);
  }
}

const runtime = new CopilotRuntime({
  agents,
  transcriptionService: new MyTranscriptionService(),
});

With the service configured, GET /info reports audioFileTranscriptionEnabled: true and POST /transcribe dispatches to transcribeFile. Without it, the runtime cannot produce a transcript even if the browser has a microphone.

See Runtime HTTP endpoints for route mounting, request shapes, and server-side error handling. The V2 runtime maps service errors to transcription error codes such as rate_limited, auth_failed, audio_too_long, and provider_error; the Vue composer presents a retryable or actionable message and clears it after a short delay.