Skip to content

3. Registering functions

Functions are how you let the autopilot read or do things on the client. The autopilot decides when to call them; your code defines what they do.

Define a get_weather function

ts
// src/autopilot.ts (extending the previous step)
import { AutopilotClient, setAutopilotClient } from '@llmor/autopilot-core';

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

client.registerFunction({
  name: 'get_weather',
  description: 'Returns the current weather for a city.',
  parameters: {
    type: 'object',
    properties: {
      city: {
        type: 'string',
        description: 'The city to look up.',
      },
    },
    required: ['city'],
  },
  handler: async ({ city }: { city: string }) => {
    const res = await fetch(
      `https://wttr.in/${encodeURIComponent(city)}?format=j1`,
    );
    if (!res.ok) throw new Error(`weather lookup failed: ${res.status}`);
    const data = await res.json();
    const current = data.current_condition?.[0];
    return {
      city,
      temperature_c: current?.temp_C,
      description: current?.weatherDesc?.[0]?.value,
    };
  },
});

export async function bootAutopilot() {
  await client.connect({
    conversationUrl: import.meta.env.VITE_CONVERSATION_URL,
  });
}

A few things to notice:

  • parameters is JSON Schema, the same format the autopilot uses on the server side. Keep it strict — required is honored.
  • The handler can be sync or async; the return value is JSON-stringified and sent back to the autopilot.
  • Thrown errors do not crash the connection. They are surfaced as a functionError event and reported to the autopilot as a failed call.

Call it

In the conversation, ask the autopilot something like "What's the weather in Berlin?" — it will invoke get_weather and stream a reply.

You can watch it happen by listening to events:

ts
client.on('functionCall', ({ request }) => {
  console.log('autopilot is calling', request.name, request.arguments);
});

client.on('functionSuccess', ({ request, result }) => {
  console.log('returned', request.name, result);
});

client.on('functionError', ({ request, error }) => {
  console.error('failed', request.name, error);
});

Unregister at teardown (optional)

If your function is only relevant on a specific route:

ts
import { onScopeDispose } from 'vue';
import { client } from '@/autopilot';

client.registerFunction({ name: 'get_weather', /* … */ });
onScopeDispose(() => client.unregisterFunction('get_weather'));

Registration changes are debounced and synced as JSON Patches at /autopilot/functions.

Next: sync the selected city into context.