> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gatelit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# useGatelit

> Vue 3 composable for streaming AI responses from the Gatelit gateway.

## Import

```ts theme={null}
import { useGatelit } from "@gatelit/sdk-vue"
```

## Signature

```ts theme={null}
function useGatelit(config: GatelitClientConfig): {
  messages:    Readonly<Ref<ChatMessageWithId[]>>
  isStreaming:  Readonly<Ref<boolean>>
  error:        Readonly<Ref<GatelitError | null>>
  send(userMessage: string, model: string, options?: Partial<ChatOptions>): Promise<void>
  stop(): void
  clear(): void
}
```

***

## Configuration

`useGatelit` accepts a `GatelitClientConfig` object — the same configuration used by the core JS SDK.

<ParamField body="gatewayUrl" type="string" required>
  Base URL of your deployed Gatelit gateway, e.g. `"https://gateway.yourapp.com"`.
</ParamField>

<ParamField body="getToken" type="() => Promise<{ token: string; scheme: TokenScheme }>" required>
  Called before each request to obtain a fresh auth token. Return the token string and the authentication scheme:

  | Scheme            | When to use                                                    |
  | ----------------- | -------------------------------------------------------------- |
  | `"GatelitSigned"` | Backend-issued HMAC signed token (recommended for client apps) |
  | `"Bearer"`        | OIDC token from Clerk, Supabase, Auth0, etc.                   |
  | `"GatelitKey"`    | Long-lived service key (backend-to-backend only)               |

  Implement token caching inside this function to avoid a fetch on every message.
</ParamField>

***

## Returned values

### Reactive state

All state properties are `readonly` refs — mutate them only through the provided functions.

<ResponseField name="messages" type="Readonly<Ref<ChatMessageWithId[]>>">
  The full conversation history in chronological order. Each entry is a `ChatMessageWithId`:

  <Expandable title="ChatMessageWithId">
    <ResponseField name="id" type="string">
      Unique identifier generated client-side (`msg_<random>`). Stable across re-renders — use as the `:key` in `v-for`.
    </ResponseField>

    <ResponseField name="role" type="&#x22;user&#x22; | &#x22;assistant&#x22; | &#x22;system&#x22;">
      The author of the message.
    </ResponseField>

    <ResponseField name="content" type="string">
      The message text. For assistant messages, this grows incrementally while `isStreaming` is `true`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="isStreaming" type="Readonly<Ref<boolean>>">
  `true` while an assistant response is being streamed. `send()` is a no-op when this is `true`.
</ResponseField>

<ResponseField name="error" type="Readonly<Ref<GatelitError | null>>">
  The last error, or `null` if no error has occurred (or after `clear()` is called). A `GatelitError` has three properties:

  <Expandable title="GatelitError">
    <ResponseField name="code" type="string">
      Machine-readable error code, e.g. `"unauthorized"`, `"provider_error"`, `"gateway_error"`.
    </ResponseField>

    <ResponseField name="message" type="string">
      Human-readable description of the error.
    </ResponseField>

    <ResponseField name="status" type="number">
      HTTP status code returned by the gateway.
    </ResponseField>
  </Expandable>
</ResponseField>

### Functions

<ResponseField name="send" type="(userMessage: string, model: string, options?: Partial<ChatOptions>) => Promise<void>">
  Appends the user message to `messages`, opens a streaming request, and appends a live-updating assistant message.

  * Does nothing if `isStreaming` is already `true`.
  * Clears `error` before each new request.
  * If the stream is aborted via `stop()`, no error is set — the partial assistant message is kept if it contains any content; an empty assistant placeholder is removed.
  * If the stream fails with a `GatelitError`, `error` is populated.

  **Parameters:**

  | Name          | Type                   | Description                                                                                                                                                  |
  | ------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
  | `userMessage` | `string`               | The user's message text.                                                                                                                                     |
  | `model`       | `string`               | Model in `"provider/model-name"` format, e.g. `"openai/gpt-4o"`.                                                                                             |
  | `options`     | `Partial<ChatOptions>` | Optional overrides: `maxTokens`, `temperature`, `outputSchema`, `promptId`. Cannot override `messages`, `model`, or `signal` (those are managed internally). |
</ResponseField>

<ResponseField name="stop" type="() => void">
  Aborts the current stream by calling `AbortController.abort()`. `isStreaming` returns to `false`. Any content streamed so far is kept in `messages`.
</ResponseField>

<ResponseField name="clear" type="() => void">
  Clears all messages and resets `error` to `null`. If a stream is in progress, it is aborted first.
</ResponseField>

***

## Examples

### Full chat interface

A complete Vue SFC with message history, a streaming indicator, error display, and stop button.

```vue theme={null}
<script setup lang="ts">
import { ref } from "vue"
import { useGatelit } from "@gatelit/sdk-vue"

const input = ref("")

const { messages, isStreaming, error, send, stop, clear } = useGatelit({
  gatewayUrl: "https://gateway.yourapp.com",
  getToken: async () => {
    const res = await fetch("/api/ai-token").then((r) => r.json())
    return { token: res.token, scheme: "GatelitSigned" }
  },
})

async function handleSend() {
  const text = input.value.trim()
  if (!text) return
  input.value = ""
  await send(text, "openai/gpt-4o")
}
</script>

<template>
  <div class="messages">
    <div
      v-for="msg in messages"
      :key="msg.id"
      :class="['message', msg.role]"
    >
      <strong>{{ msg.role }}</strong>
      <p>{{ msg.content }}</p>
    </div>
  </div>

  <div v-if="error" class="error">
    {{ error.message }} ({{ error.code }})
  </div>

  <div class="controls">
    <input v-model="input" @keydown.enter="handleSend" :disabled="isStreaming" />
    <button @click="handleSend" :disabled="isStreaming">Send</button>
    <button v-if="isStreaming" @click="stop">Stop</button>
    <button @click="clear">Clear</button>
  </div>
</template>
```

<Note>
  The assistant message object is replaced in the array on every chunk (to
  trigger Vue's reactivity system), so `:key="msg.id"` ensures the DOM node is
  reused rather than recreated. Always bind `id` as the key.
</Note>

### Usage with Nuxt

In a Nuxt application, use `$fetch` (provided by Nuxt's runtime) inside `getToken` to call your server route:

```vue theme={null}
<script setup lang="ts">
import { useGatelit } from "@gatelit/sdk-vue"

const { messages, isStreaming, error, send, stop } = useGatelit({
  gatewayUrl: useRuntimeConfig().public.gatewayUrl,
  getToken: async () => {
    const res = await $fetch<{ token: string }>("/api/ai-token")
    return { token: res.token, scheme: "GatelitSigned" }
  },
})
</script>
```

Your `server/api/ai-token.ts` route signs and returns a short-lived token using `signToken` from `@gatelit/sdk`.
