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

# Vue

> Vue 3 composables and provider for AI SDK 5 chat UIs

The `@openharness/vue` package provides the same functionality as the React package, using Vue 3 composables and Nuxt-compatible components.

## Setup

```bash theme={"dark"}
npm install @openharness/vue
```

Wrap your app with the `OpenHarnessProvider` component:

```vue theme={"dark"}
<script setup lang="ts">
import { OpenHarnessProvider } from "@openharness/vue";
</script>

<template>
  <OpenHarnessProvider>
    <Chat />
  </OpenHarnessProvider>
</template>
```

## `useOpenHarness`

Creates a chat session connected to your API endpoint. Returns an AI SDK 5 `Chat` instance with reactive properties (`messages`, `status`, `sendMessage`, `stop`, etc.), typed with `OHUIMessage`:

```vue theme={"dark"}
<script setup lang="ts">
import { ref } from "vue";
import { useOpenHarness } from "@openharness/vue";

const chat = useOpenHarness({ endpoint: "/api/chat" });
const input = ref("");

function send() {
  const text = input.value.trim();
  if (!text) return;
  input.value = "";
  chat.sendMessage({ text });
}
</script>

<template>
  <div>
    <div v-for="msg in chat.messages" :key="msg.id">
      <template v-for="(part, i) in msg.parts" :key="i">
        <span v-if="part.type === 'text'">{{ part.text }}</span>
      </template>
    </div>
    <form @submit.prevent="send">
      <input v-model="input" placeholder="Type a message..." />
      <button type="submit">Send</button>
    </form>
  </div>
</template>
```

### Resuming Streams

Pass a stable `id` and `resume: true` to reconnect to an active server-side stream when the component mounts:

```vue theme={"dark"}
<script setup lang="ts">
import { useOpenHarness } from "@openharness/vue";

const chat = useOpenHarness({
  endpoint: "/api/tasks/task-1/chat",
  id: "task-1",
  resume: true,
  prepareReconnectToStreamRequest: ({ id }) => ({
    api: `/api/tasks/${id}/chat/stream`,
    credentials: "include",
  }),
});
</script>
```

By default, reconnect attempts use `GET ${endpoint}/${id}/stream`. The server must own the active run and return the active stream or `204` when no stream is running.

<Note>
  AI SDK stream resumption is not compatible with treating browser request abort as cancellation. If a user needs to stop a background run, expose a separate server-side cancel action.
</Note>

## `useSubagentStatus`

Returns a computed ref deriving reactive state from `data-oh:subagent.*` events:

```vue theme={"dark"}
<script setup lang="ts">
import { useSubagentStatus } from "@openharness/vue";

const subagent = useSubagentStatus();
</script>

<template>
  <div v-if="subagent.hasActiveSubagents">
    <div v-for="agent in subagent.activeSubagents" :key="agent.path.join('/')">
      {{ agent.name }}: {{ agent.task }}
    </div>
  </div>
</template>
```

## `useSessionStatus`

Returns a computed ref tracking turn index, compaction state, and retry info:

```vue theme={"dark"}
<script setup lang="ts">
import { useSessionStatus } from "@openharness/vue";

const session = useSessionStatus();
</script>

<template>
  <div>Turn: {{ session.turnIndex }}</div>
</template>
```

## Full Example

```vue theme={"dark"}
<script setup lang="ts">
import { ref } from "vue";
import {
  useOpenHarness,
  useSubagentStatus,
  useSessionStatus,
} from "@openharness/vue";

const chat = useOpenHarness({ endpoint: "/api/chat" });
const subagent = useSubagentStatus();
const session = useSessionStatus();
const input = ref("");

function send() {
  const text = input.value.trim();
  if (!text) return;
  input.value = "";
  chat.sendMessage({ text });
}
</script>

<template>
  <OpenHarnessProvider>
    <div>
      <div v-for="msg in chat.messages" :key="msg.id">
        <template v-for="(part, i) in msg.parts" :key="i">
          <span v-if="part.type === 'text'">{{ part.text }}</span>
        </template>
      </div>
      <form @submit.prevent="send">
        <input v-model="input" placeholder="Type a message..." />
        <button type="submit">Send</button>
      </form>
    </div>
  </OpenHarnessProvider>
</template>
```

<Note>
  The `OpenHarnessProvider` is a renderless wrapper component that provides shared subagent, session, and sandbox state via Vue's `provide`/`inject`.
</Note>
