Skip to content

Vue 3 app example

A minimal but realistic Vite + Vue 3 + Pinia setup with the bar dropped in.

src/main.ts

ts
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import { AutopilotClient, setAutopilotClient } from '@llmor/autopilot-core';
import { enableAutopilotBar } from '@llmor/autopilot-bar';
import App from './App.vue';

const client = new AutopilotClient();
setAutopilotClient(client);

const app = createApp(App);
app.use(createPinia());
app.mount('#app');

client
  .connect({ conversationUrl: import.meta.env.VITE_CONVERSATION_URL })
  .then(() => enableAutopilotBar(client))
  .catch((err) => console.error('autopilot connect failed', err));

src/App.vue

vue
<script setup lang="ts">
import { ref, watch } from 'vue';
import { useAutopilotClient } from '@llmor/autopilot-core';
import { useAutopilotStore } from '@llmor/autopilot-vue';

const store = useAutopilotStore();
const client = useAutopilotClient();

const city = ref('Berlin');

// Mirror user's selection into context so the autopilot sees it.
watch(city, (v) => client.updateContext({ city: v }), { immediate: true });

// Register a function the autopilot can call.
client.registerFunction({
  name: 'get_weather',
  description: 'Returns weather for a city.',
  parameters: {
    type: 'object',
    properties: { city: { type: 'string' } },
    required: ['city'],
  },
  handler: async ({ city }: { city: string }) => {
    const res = await fetch(`https://wttr.in/${encodeURIComponent(city)}?format=j1`);
    const data = await res.json();
    return {
      city,
      temp_c: data.current_condition[0].temp_C,
      description: data.current_condition[0].weatherDesc[0].value,
    };
  },
});
</script>

<template>
  <main class="container">
    <h1>Weather assistant</h1>
    <p>Status: <strong>{{ store.connectionStatus }}</strong></p>

    <label>
      City:
      <input v-model="city" />
    </label>

    <p>
      Click the floating button (bottom right) and ask
      <em>"What's the weather like?"</em>
    </p>

    <hr />

    <h2>Recent activity</h2>
    <ul>
      <li v-for="entry in store.recentActivity" :key="entry.id">
        [{{ entry.type }}] {{ entry.message }}
      </li>
    </ul>
  </main>
</template>

<style>
.container { max-width: 720px; margin: 40px auto; padding: 0 20px; font-family: system-ui; }
</style>

vite.config.ts

Nothing special is needed — the default @vitejs/plugin-vue config from create vite works.

Custom UI instead of the bar

Drop the enableAutopilotBar call and build your own chat surface from the Vue components or the useAutopilotConversation composable.