@d4y/agent-runtime-nuxt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +314 -0
- package/dist/module.d.mts +69 -0
- package/dist/module.json +12 -0
- package/dist/module.mjs +60 -0
- package/dist/runtime/components/AgentRuntimeArtifactPreview.d.vue.ts +14 -0
- package/dist/runtime/components/AgentRuntimeArtifactPreview.vue +112 -0
- package/dist/runtime/components/AgentRuntimeArtifactPreview.vue.d.ts +14 -0
- package/dist/runtime/composables/useAgentRuntime.d.ts +130 -0
- package/dist/runtime/composables/useAgentRuntime.js +306 -0
- package/dist/runtime/composables/useAgentRuntimeMarkdown.d.ts +15 -0
- package/dist/runtime/composables/useAgentRuntimeMarkdown.js +109 -0
- package/dist/runtime/server/api/app.get.d.ts +6 -0
- package/dist/runtime/server/api/app.get.js +26 -0
- package/dist/runtime/server/api/conversations/[id]/abort.post.d.ts +6 -0
- package/dist/runtime/server/api/conversations/[id]/abort.post.js +18 -0
- package/dist/runtime/server/api/conversations/[id]/env.post.d.ts +10 -0
- package/dist/runtime/server/api/conversations/[id]/env.post.js +22 -0
- package/dist/runtime/server/api/conversations/[id]/files/raw/[...path].get.d.ts +11 -0
- package/dist/runtime/server/api/conversations/[id]/files/raw/[...path].get.js +31 -0
- package/dist/runtime/server/api/conversations/[id]/files.get.d.ts +14 -0
- package/dist/runtime/server/api/conversations/[id]/files.get.js +16 -0
- package/dist/runtime/server/api/conversations/[id]/history.get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/history.get.js +16 -0
- package/dist/runtime/server/api/conversations/[id]/messages.post.d.ts +7 -0
- package/dist/runtime/server/api/conversations/[id]/messages.post.js +20 -0
- package/dist/runtime/server/api/conversations/[id]/stream.get.d.ts +9 -0
- package/dist/runtime/server/api/conversations/[id]/stream.get.js +28 -0
- package/dist/runtime/server/api/conversations/[id].delete.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id].delete.js +18 -0
- package/dist/runtime/server/api/conversations.post.d.ts +7 -0
- package/dist/runtime/server/api/conversations.post.js +17 -0
- package/dist/runtime/server/utils/agent-runtime.d.ts +12 -0
- package/dist/runtime/server/utils/agent-runtime.js +12 -0
- package/dist/runtime/utils/files.d.ts +16 -0
- package/dist/runtime/utils/files.js +42 -0
- package/dist/types.d.mts +9 -0
- package/package.json +67 -0
- package/src/frontend.ts +16 -0
- package/src/module.ts +155 -0
- package/src/nitro-globals.d.ts +8 -0
- package/src/runtime/components/AgentRuntimeArtifactPreview.vue +192 -0
- package/src/runtime/composables/useAgentRuntime.ts +527 -0
- package/src/runtime/composables/useAgentRuntimeMarkdown.ts +145 -0
- package/src/runtime/server/api/app.get.ts +50 -0
- package/src/runtime/server/api/conversations/[id]/abort.post.ts +26 -0
- package/src/runtime/server/api/conversations/[id]/env.post.ts +34 -0
- package/src/runtime/server/api/conversations/[id]/files/raw/[...path].get.ts +48 -0
- package/src/runtime/server/api/conversations/[id]/files.get.ts +33 -0
- package/src/runtime/server/api/conversations/[id]/history.get.ts +20 -0
- package/src/runtime/server/api/conversations/[id]/messages.post.ts +29 -0
- package/src/runtime/server/api/conversations/[id]/stream.get.ts +41 -0
- package/src/runtime/server/api/conversations/[id].delete.ts +22 -0
- package/src/runtime/server/api/conversations.post.ts +26 -0
- package/src/runtime/server/utils/agent-runtime.ts +33 -0
- package/src/runtime/utils/files.ts +78 -0
- package/src/shared.ts +46 -0
- package/src/vue-shim.d.ts +6 -0
package/README.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# `@d4y/agent-runtime-nuxt`
|
|
2
|
+
|
|
3
|
+
Headless Nuxt module that connects a Nuxt app to an [agent-runtime](../README.md) server.
|
|
4
|
+
|
|
5
|
+
It ships:
|
|
6
|
+
|
|
7
|
+
- **Server-side proxy routes** (auto-mounted under a configurable prefix) that
|
|
8
|
+
inject the `X-Agent-Runtime-App-Key` header so your secret never reaches the browser.
|
|
9
|
+
- **A single composable, `useAgentRuntime()`**, that exposes a typed reactive
|
|
10
|
+
chat client — conversation lifecycle, SSE stream consumption, generic
|
|
11
|
+
auth/env state, workspace file listing, and a download URL builder.
|
|
12
|
+
- **Optional frontend helpers** for common host-app concerns such as rewriting
|
|
13
|
+
workspace paths to download URLs inside markdown, classifying files for
|
|
14
|
+
inline preview vs. download, and rendering a minimal artifact preview panel.
|
|
15
|
+
|
|
16
|
+
It is **headless on purpose**: the core integration does not require any UI,
|
|
17
|
+
and the optional frontend exports stay small and app-agnostic. Render
|
|
18
|
+
whatever you want on top of the reactive state.
|
|
19
|
+
|
|
20
|
+
The package also exports a small shared helper surface from
|
|
21
|
+
`@d4y/agent-runtime-nuxt/shared` for host apps that need generic agent-runtime config /
|
|
22
|
+
header utilities without pulling in app-specific policy.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pnpm add @d4y/agent-runtime-nuxt
|
|
30
|
+
# or
|
|
31
|
+
bun add @d4y/agent-runtime-nuxt
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
// nuxt.config.ts
|
|
36
|
+
export default defineNuxtConfig({
|
|
37
|
+
modules: ['@d4y/agent-runtime-nuxt'],
|
|
38
|
+
|
|
39
|
+
agentRuntime: {
|
|
40
|
+
// All four keys are optional. When omitted they fall back to the
|
|
41
|
+
// matching AGENT_RUNTIME_* environment variable, so the same build works
|
|
42
|
+
// across dev / staging / prod without rebuilding.
|
|
43
|
+
baseUrl: 'http://127.0.0.1:18791', // AGENT_RUNTIME_URL
|
|
44
|
+
appKey: process.env.AGENT_RUNTIME_APP_KEY, // **secret** — server-only
|
|
45
|
+
appId: 'omnisearch', // AGENT_RUNTIME_APP_ID
|
|
46
|
+
apiPrefix: '/api/agent-runtime' // Where the proxy routes mount
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
> **`AGENT_RUNTIME_APP_KEY` is mandatory at runtime.** The proxy routes will
|
|
52
|
+
> return `500` until it is set.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<script setup lang="ts">
|
|
60
|
+
const chat = useAgentRuntime()
|
|
61
|
+
|
|
62
|
+
const input = ref('')
|
|
63
|
+
async function onSubmit() {
|
|
64
|
+
const text = input.value.trim()
|
|
65
|
+
input.value = ''
|
|
66
|
+
await chat.send(text)
|
|
67
|
+
}
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div v-if="!chat.authReady.value">
|
|
72
|
+
Fill in <code>{{ Object.keys(chat.app.value?.envSchema ?? {}).join(', ') }}</code>
|
|
73
|
+
then call <code>chat.saveAuth({ values: { … } })</code>.
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<UChatMessages
|
|
77
|
+
v-else
|
|
78
|
+
:messages="chat.messages.value"
|
|
79
|
+
:status="chat.status.value"
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
<UChatPrompt v-model="input" @submit="onSubmit" />
|
|
83
|
+
</template>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The composable returns AI-SDK / Nuxt UI compatible `UIMessage` shapes, so
|
|
87
|
+
`@nuxt/ui`'s chat components work out of the box.
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## API
|
|
92
|
+
|
|
93
|
+
### Module options
|
|
94
|
+
|
|
95
|
+
| Option | Type | Default | Env fallback | Notes |
|
|
96
|
+
|-------------|-----------|--------------------------|------------------------|---------------------------------------|
|
|
97
|
+
| `baseUrl` | `string` | `http://127.0.0.1:18791` | `AGENT_RUNTIME_URL` | Trailing slashes are stripped. |
|
|
98
|
+
| `appKey` | `string` | _(none)_ | `AGENT_RUNTIME_APP_KEY` | **Server-only secret.** Required. |
|
|
99
|
+
| `appId` | `string` | `omnisearch` | `AGENT_RUNTIME_APP_ID` | Must match a registered agent-runtime app. |
|
|
100
|
+
| `apiPrefix` | `string` | `/api/agent-runtime` | — | Where proxy routes mount. |
|
|
101
|
+
|
|
102
|
+
### Server routes (auto-mounted at `apiPrefix`)
|
|
103
|
+
|
|
104
|
+
| Route | Method | Purpose |
|
|
105
|
+
|------------------------------------------------------|--------|----------------------------------------------------------|
|
|
106
|
+
| `/app` | GET | Returns the active app's manifest summary. |
|
|
107
|
+
| `/conversations` | POST | Open a new conversation. Body: `{ env?, model? }`. |
|
|
108
|
+
| `/conversations/:id` | DELETE | Delete a persisted conversation. |
|
|
109
|
+
| `/conversations/:id/history` | GET | Return the persisted conversation history. |
|
|
110
|
+
| `/conversations/:id/stream` | GET | Pipes the upstream SSE stream verbatim. |
|
|
111
|
+
| `/conversations/:id/messages` | POST | Append a user turn. Body: `{ content, context? }`. |
|
|
112
|
+
| `/conversations/:id/abort` | POST | Cancel the in-flight agent run. |
|
|
113
|
+
| `/conversations/:id/env` | POST | Patch workspace env. Body: `{ env, merge? }`. |
|
|
114
|
+
| `/conversations/:id/files` | GET | List workspace files. |
|
|
115
|
+
| `/conversations/:id/files/raw/<path>` | GET | Stream a single workspace file. |
|
|
116
|
+
|
|
117
|
+
### `useAgentRuntime()`
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const {
|
|
121
|
+
conversationId, // Ref<string | null>
|
|
122
|
+
messages, // Ref<UIMessage[]>
|
|
123
|
+
status, // Ref<'idle' | 'submitted' | 'streaming' | 'ready' | 'error'>
|
|
124
|
+
error, // Ref<Error | null>
|
|
125
|
+
uiActions, // Ref<UiAction[]> — newest first, capped at 50
|
|
126
|
+
app, // Ref<AppInfo | null>
|
|
127
|
+
auth, // Ref<AppAuth>
|
|
128
|
+
authReady, // ComputedRef<boolean>
|
|
129
|
+
files, // Ref<FileEntry[]>
|
|
130
|
+
fileUrl, // (relPath: string) => string
|
|
131
|
+
refreshFiles, // () => Promise<void>
|
|
132
|
+
saveAuth, // (next: AppAuth) => Promise<void>
|
|
133
|
+
start, // () => Promise<string>
|
|
134
|
+
send, // (text: string, options?: SendOptions) => Promise<void>
|
|
135
|
+
abort, // () => Promise<void>
|
|
136
|
+
reset // () => Promise<void>
|
|
137
|
+
} = useAgentRuntime()
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
#### `auth` and `authReady`
|
|
141
|
+
|
|
142
|
+
The active app's manifest declares which env vars are required. The composable
|
|
143
|
+
fetches the manifest on mount, then loads any previously-saved values from
|
|
144
|
+
`localStorage` (scoped per `appId`). `authReady` is `true` iff every required
|
|
145
|
+
key has a non-empty value.
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
await chat.saveAuth({
|
|
149
|
+
values: {
|
|
150
|
+
OMNISEARCH_SESSION_TOKEN: 'abc…',
|
|
151
|
+
OMNISEARCH_ORGANIZATION_ID: 'e3db13ed-…'
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
If a conversation is already open, `saveAuth` also pushes the new map to its
|
|
157
|
+
workspace via `POST /conversations/:id/env`, which retriggers any matching
|
|
158
|
+
`bootstrap[]` step on the harness side.
|
|
159
|
+
|
|
160
|
+
#### `send(text, options?)`
|
|
161
|
+
|
|
162
|
+
Lazily calls `start()` if no conversation exists. The displayed user bubble
|
|
163
|
+
always shows `text`; pass `options.rewriteContent` to mutate the *forwarded*
|
|
164
|
+
prompt without changing what the user sees. Useful for model-specific soft
|
|
165
|
+
switches:
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
await chat.send(input.value, {
|
|
169
|
+
rewriteContent: t => `${t}\n\n/no_think` // Qwen3 soft-switch
|
|
170
|
+
})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### `fileUrl(relPath)`
|
|
174
|
+
|
|
175
|
+
Returns the fully-qualified URL of a workspace file behind the proxy.
|
|
176
|
+
Empty string when no conversation is open.
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
<a :href="chat.fileUrl(file.relPath)" download>{{ file.name }}</a>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Optional frontend helpers
|
|
183
|
+
|
|
184
|
+
The module stays headless, but it exposes a small optional helper surface for
|
|
185
|
+
host apps that want the same workspace-file ergonomics as the playground.
|
|
186
|
+
|
|
187
|
+
#### `useAgentRuntimeMarkdown(options)`
|
|
188
|
+
|
|
189
|
+
Auto-imported as a composable. It returns `render()` / `renderInline()` helpers
|
|
190
|
+
built on `markdown-it` and rewrites workspace references such as
|
|
191
|
+
`sandbox:outputs/foo.png` or `/workspace/outputs/foo.pdf` through your
|
|
192
|
+
`resolveWorkspacePath()` callback.
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
const chat = useAgentRuntime()
|
|
196
|
+
const { render } = useAgentRuntimeMarkdown({
|
|
197
|
+
resolveWorkspacePath: relPath => chat.fileUrl(relPath)
|
|
198
|
+
})
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Markdown image links that point at workspace files render as clickable images.
|
|
202
|
+
Non-image workspace links render as download links instead of broken `<img>` tags.
|
|
203
|
+
Bare `/workspace/...` paths in plain text are auto-linked as well.
|
|
204
|
+
|
|
205
|
+
#### File preview utilities
|
|
206
|
+
|
|
207
|
+
Available from `@d4y/agent-runtime-nuxt/frontend`:
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import {
|
|
211
|
+
AgentRuntimeArtifactPreview,
|
|
212
|
+
getAgentRuntimeFilePreviewKind,
|
|
213
|
+
canPreviewAgentRuntimeFileInline,
|
|
214
|
+
resolveAgentRuntimeWorkspaceUri,
|
|
215
|
+
toAgentRuntimeWorkspaceRelativePath
|
|
216
|
+
} from '@d4y/agent-runtime-nuxt/frontend'
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Example:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const kind = getAgentRuntimeFilePreviewKind(file)
|
|
223
|
+
// => 'image' | 'pdf' | 'text' | 'download'
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Use these helpers to decide whether to render an inline image/PDF/text preview
|
|
227
|
+
or fall back to a plain download affordance.
|
|
228
|
+
|
|
229
|
+
#### Minimal artifact preview component
|
|
230
|
+
|
|
231
|
+
`@d4y/agent-runtime-nuxt/frontend` also exports `AgentRuntimeArtifactPreview`, a tiny
|
|
232
|
+
optional Vue component for inline image / PDF / text previews:
|
|
233
|
+
|
|
234
|
+
```vue
|
|
235
|
+
<script setup lang="ts">
|
|
236
|
+
import { AgentRuntimeArtifactPreview } from '@d4y/agent-runtime-nuxt/frontend'
|
|
237
|
+
|
|
238
|
+
const chat = useAgentRuntime()
|
|
239
|
+
</script>
|
|
240
|
+
|
|
241
|
+
<template>
|
|
242
|
+
<AgentRuntimeArtifactPreview
|
|
243
|
+
:file="file"
|
|
244
|
+
:src="chat.fileUrl(file.relPath)" />
|
|
245
|
+
</template>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## Local development against a workspace copy
|
|
251
|
+
|
|
252
|
+
To consume the module from a sibling project (for example,
|
|
253
|
+
`~/projects/d4y/omnisearch-app`) before publishing to npm, link it via
|
|
254
|
+
your package manager's `file:` / `link:` protocol:
|
|
255
|
+
|
|
256
|
+
```jsonc
|
|
257
|
+
// omnisearch-app/package.json
|
|
258
|
+
{
|
|
259
|
+
"dependencies": {
|
|
260
|
+
"@d4y/agent-runtime-nuxt": "file:../../agent-runtime/packages/nuxt-module"
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
then `pnpm install` (or `bun install`).
|
|
266
|
+
|
|
267
|
+
## Shared helpers
|
|
268
|
+
|
|
269
|
+
For server-side host integrations, the module exposes a small app-agnostic
|
|
270
|
+
utility surface:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
import {
|
|
274
|
+
normalizeAgentRuntimeBaseUrl,
|
|
275
|
+
createScopeFingerprint,
|
|
276
|
+
resolveAgentRuntimeConfig,
|
|
277
|
+
createAgentRuntimeRequestHeaders
|
|
278
|
+
} from '@d4y/agent-runtime-nuxt/shared'
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
These helpers are intentionally limited to generic concerns such as config
|
|
282
|
+
normalization, request-header construction, and stable scope hashing. App-level
|
|
283
|
+
auth, tenancy, and manifest-specific context/env shaping should stay in the
|
|
284
|
+
host application.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Release
|
|
289
|
+
|
|
290
|
+
The npm package name is `@d4y/agent-runtime-nuxt`.
|
|
291
|
+
|
|
292
|
+
Publishing is handled by `.github/workflows/release-nuxt-module.yml` using npm
|
|
293
|
+
trusted publishing from GitHub Actions. Releases are triggered by pushing a tag
|
|
294
|
+
in this format:
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
git tag nuxt-module-v0.1.0
|
|
298
|
+
git push origin nuxt-module-v0.1.0
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
The workflow verifies that the tag version matches
|
|
302
|
+
`packages/nuxt-module/package.json` before running `npm publish --provenance`.
|
|
303
|
+
|
|
304
|
+
Before the first release, configure npm trusted publishing for:
|
|
305
|
+
|
|
306
|
+
- npm package: `@d4y/agent-runtime-nuxt`
|
|
307
|
+
- GitHub repository: `digital4you/agent-runtime`
|
|
308
|
+
- workflow file: `.github/workflows/release-nuxt-module.yml`
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## License
|
|
313
|
+
|
|
314
|
+
MIT
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
export { AppAuth, AppEnvField, AppInfo, ChatStatus, FileEntry, SendOptions, UIMessage, UiAction, UseAgentRuntime } from '../dist/runtime/composables/useAgentRuntime.js';
|
|
3
|
+
export { AgentRuntimeMarkdownRenderOptions } from '../dist/runtime/composables/useAgentRuntimeMarkdown.js';
|
|
4
|
+
export { AgentRuntimeFileLike, AgentRuntimeFilePreviewKind } from '../dist/runtime/utils/files.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Module options for `@d4y/agent-runtime-nuxt`.
|
|
8
|
+
*
|
|
9
|
+
* Every field is optional at config time — unset values fall back to the
|
|
10
|
+
* matching `AGENT_RUNTIME_*` environment variable at runtime, so the same build
|
|
11
|
+
* artifact works across environments without rebuilding.
|
|
12
|
+
*/
|
|
13
|
+
interface ModuleOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Base URL of the agent-runtime HTTP server (no trailing slash required).
|
|
16
|
+
*
|
|
17
|
+
* Falls back to `process.env.AGENT_RUNTIME_URL` then `http://127.0.0.1:18791`.
|
|
18
|
+
*/
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
/**
|
|
21
|
+
* App key used to authenticate against agent-runtime (`X-Agent-Runtime-App-Key` header).
|
|
22
|
+
*
|
|
23
|
+
* **Server-only secret.** Never exposed to the browser; the module only
|
|
24
|
+
* forwards it from the proxy routes it registers.
|
|
25
|
+
*
|
|
26
|
+
* Falls back to `process.env.AGENT_RUNTIME_APP_KEY`. Required at runtime — the
|
|
27
|
+
* module will throw a 500 from any proxy route if missing.
|
|
28
|
+
*/
|
|
29
|
+
appKey?: string;
|
|
30
|
+
/**
|
|
31
|
+
* App ID to bind every conversation to (must match an app registered in
|
|
32
|
+
* the agent-runtime `apps/` directory).
|
|
33
|
+
*
|
|
34
|
+
* Falls back to `process.env.AGENT_RUNTIME_APP_ID` then `omnisearch`.
|
|
35
|
+
*/
|
|
36
|
+
appId?: string;
|
|
37
|
+
/**
|
|
38
|
+
* URL prefix for the auto-registered Nitro proxy routes. Change it if you
|
|
39
|
+
* need to disambiguate from another module on the same `/api/...` namespace.
|
|
40
|
+
*
|
|
41
|
+
* Default: `/api/agent-runtime`.
|
|
42
|
+
*/
|
|
43
|
+
apiPrefix?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Public runtime-config shape exposed to the browser (path data only). */
|
|
46
|
+
interface PublicAgentRuntimeConfig {
|
|
47
|
+
/** Same value as `apiPrefix` from module options; needed by `useAgentRuntime` to build URLs. */
|
|
48
|
+
apiPrefix: string;
|
|
49
|
+
/** App ID, used by the composable to scope `localStorage` keys. */
|
|
50
|
+
appId: string;
|
|
51
|
+
}
|
|
52
|
+
/** Private runtime-config shape (server-only). */
|
|
53
|
+
interface PrivateAgentRuntimeConfig {
|
|
54
|
+
baseUrl: string;
|
|
55
|
+
appKey: string;
|
|
56
|
+
appId: string;
|
|
57
|
+
}
|
|
58
|
+
declare module '@nuxt/schema' {
|
|
59
|
+
interface RuntimeConfig {
|
|
60
|
+
agentRuntime: PrivateAgentRuntimeConfig;
|
|
61
|
+
}
|
|
62
|
+
interface PublicRuntimeConfig {
|
|
63
|
+
agentRuntime: PublicAgentRuntimeConfig;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
67
|
+
|
|
68
|
+
export { _default as default };
|
|
69
|
+
export type { ModuleOptions, PrivateAgentRuntimeConfig, PublicAgentRuntimeConfig };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addImportsDir, addTypeTemplate, addServerHandler } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
3
|
+
|
|
4
|
+
const DEFAULTS = {
|
|
5
|
+
baseUrl: "http://127.0.0.1:18791",
|
|
6
|
+
appId: "omnisearch",
|
|
7
|
+
apiPrefix: "/api/agent-runtime"
|
|
8
|
+
};
|
|
9
|
+
const module$1 = defineNuxtModule({
|
|
10
|
+
meta: {
|
|
11
|
+
name: "@d4y/agent-runtime-nuxt",
|
|
12
|
+
configKey: "agentRuntime",
|
|
13
|
+
compatibility: { nuxt: ">=3.13.0" }
|
|
14
|
+
},
|
|
15
|
+
defaults: {},
|
|
16
|
+
setup(userOptions, nuxt) {
|
|
17
|
+
const resolver = createResolver(import.meta.url);
|
|
18
|
+
const baseUrl = (userOptions.baseUrl ?? process.env.AGENT_RUNTIME_URL ?? DEFAULTS.baseUrl).replace(/\/+$/, "");
|
|
19
|
+
const appKey = userOptions.appKey ?? process.env.AGENT_RUNTIME_APP_KEY ?? "";
|
|
20
|
+
const appId = userOptions.appId ?? process.env.AGENT_RUNTIME_APP_ID ?? DEFAULTS.appId;
|
|
21
|
+
const apiPrefix = (userOptions.apiPrefix ?? DEFAULTS.apiPrefix).replace(/\/+$/, "");
|
|
22
|
+
nuxt.options.runtimeConfig.agentRuntime = defu(nuxt.options.runtimeConfig.agentRuntime, {
|
|
23
|
+
baseUrl,
|
|
24
|
+
appKey,
|
|
25
|
+
appId
|
|
26
|
+
});
|
|
27
|
+
nuxt.options.runtimeConfig.public.agentRuntime = defu(nuxt.options.runtimeConfig.public.agentRuntime, {
|
|
28
|
+
apiPrefix,
|
|
29
|
+
appId
|
|
30
|
+
});
|
|
31
|
+
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
32
|
+
addTypeTemplate({
|
|
33
|
+
filename: "types/agent-runtime.d.ts",
|
|
34
|
+
getContents: () => [
|
|
35
|
+
`// Auto-generated by @d4y/agent-runtime-nuxt`,
|
|
36
|
+
`export type { UseAgentRuntime, AppInfo, AppAuth, AppEnvField, FileEntry, UiAction, SendOptions, ChatStatus } from '${resolver.resolve("./runtime/composables/useAgentRuntime")}'`,
|
|
37
|
+
`export type { AgentRuntimeMarkdownRenderOptions } from '${resolver.resolve("./runtime/composables/useAgentRuntimeMarkdown")}'`,
|
|
38
|
+
`export type { AgentRuntimeFileLike, AgentRuntimeFilePreviewKind } from '${resolver.resolve("./runtime/utils/files")}'`,
|
|
39
|
+
""
|
|
40
|
+
].join("\n")
|
|
41
|
+
});
|
|
42
|
+
const route = (suffix, handler, method) => addServerHandler({
|
|
43
|
+
route: `${apiPrefix}${suffix}`,
|
|
44
|
+
method,
|
|
45
|
+
handler: resolver.resolve(`./runtime/server/api/${handler}`)
|
|
46
|
+
});
|
|
47
|
+
route("/app", "app.get", "get");
|
|
48
|
+
route("/conversations", "conversations.post", "post");
|
|
49
|
+
route("/conversations/:id", "conversations/[id].delete", "delete");
|
|
50
|
+
route("/conversations/:id/history", "conversations/[id]/history.get", "get");
|
|
51
|
+
route("/conversations/:id/stream", "conversations/[id]/stream.get", "get");
|
|
52
|
+
route("/conversations/:id/messages", "conversations/[id]/messages.post", "post");
|
|
53
|
+
route("/conversations/:id/abort", "conversations/[id]/abort.post", "post");
|
|
54
|
+
route("/conversations/:id/env", "conversations/[id]/env.post", "post");
|
|
55
|
+
route("/conversations/:id/files", "conversations/[id]/files.get", "get");
|
|
56
|
+
route("/conversations/:id/files/raw/**", "conversations/[id]/files/raw/[...path].get", "get");
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
export { module$1 as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AgentRuntimeFileLike } from '../utils/files.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
file: AgentRuntimeFileLike;
|
|
4
|
+
src?: string | null;
|
|
5
|
+
resolveSrc?: ((relPath: string) => string | null | undefined) | null;
|
|
6
|
+
textMaxChars?: number;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
9
|
+
src: string | null;
|
|
10
|
+
resolveSrc: ((relPath: string) => string | null | undefined) | null;
|
|
11
|
+
textMaxChars: number;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, onBeforeUnmount, ref, watch } from "vue";
|
|
3
|
+
import { getAgentRuntimeFilePreviewKind } from "../utils/files";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
file: { type: Object, required: true },
|
|
6
|
+
src: { type: [String, null], required: false, default: null },
|
|
7
|
+
resolveSrc: { type: [Function, null], required: false, default: null },
|
|
8
|
+
textMaxChars: { type: Number, required: false, default: 12e4 }
|
|
9
|
+
});
|
|
10
|
+
const kind = computed(() => getAgentRuntimeFilePreviewKind(props.file));
|
|
11
|
+
const resolvedSrc = computed(() => {
|
|
12
|
+
if (props.src) {
|
|
13
|
+
return props.src;
|
|
14
|
+
}
|
|
15
|
+
if (!props.file.relPath || !props.resolveSrc) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
return props.resolveSrc(props.file.relPath) ?? null;
|
|
19
|
+
});
|
|
20
|
+
const textContent = ref("");
|
|
21
|
+
const textError = ref(null);
|
|
22
|
+
const textLoading = ref(false);
|
|
23
|
+
let textAbortController = null;
|
|
24
|
+
const abortTextLoad = () => {
|
|
25
|
+
textAbortController?.abort();
|
|
26
|
+
textAbortController = null;
|
|
27
|
+
};
|
|
28
|
+
const loadTextPreview = async () => {
|
|
29
|
+
abortTextLoad();
|
|
30
|
+
textContent.value = "";
|
|
31
|
+
textError.value = null;
|
|
32
|
+
if (kind.value !== "text" || !resolvedSrc.value) {
|
|
33
|
+
textLoading.value = false;
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
textAbortController = controller;
|
|
38
|
+
textLoading.value = true;
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(resolvedSrc.value, {
|
|
41
|
+
signal: controller.signal
|
|
42
|
+
});
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
throw new Error(`Failed to load preview (${response.status})`);
|
|
45
|
+
}
|
|
46
|
+
const body = await response.text();
|
|
47
|
+
textContent.value = body.length > props.textMaxChars ? `${body.slice(0, props.textMaxChars).trimEnd()}
|
|
48
|
+
|
|
49
|
+
\u2026` : body;
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (controller.signal.aborted) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
textError.value = error instanceof Error ? error.message : "Failed to load preview";
|
|
55
|
+
} finally {
|
|
56
|
+
if (textAbortController === controller) {
|
|
57
|
+
textAbortController = null;
|
|
58
|
+
}
|
|
59
|
+
textLoading.value = false;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
watch([kind, resolvedSrc], () => {
|
|
63
|
+
void loadTextPreview();
|
|
64
|
+
}, { immediate: true });
|
|
65
|
+
onBeforeUnmount(() => {
|
|
66
|
+
abortTextLoad();
|
|
67
|
+
});
|
|
68
|
+
</script>
|
|
69
|
+
|
|
70
|
+
<template>
|
|
71
|
+
<div class="agent-runtime-artifact-preview">
|
|
72
|
+
<img
|
|
73
|
+
v-if="kind === 'image' && resolvedSrc"
|
|
74
|
+
:src="resolvedSrc"
|
|
75
|
+
:alt="file.name ?? file.relPath ?? 'Preview image'"
|
|
76
|
+
class="agent-runtime-artifact-preview__image">
|
|
77
|
+
|
|
78
|
+
<iframe
|
|
79
|
+
v-else-if="kind === 'pdf' && resolvedSrc"
|
|
80
|
+
:src="resolvedSrc"
|
|
81
|
+
:title="file.name ?? file.relPath ?? 'PDF preview'"
|
|
82
|
+
class="agent-runtime-artifact-preview__frame" />
|
|
83
|
+
|
|
84
|
+
<div v-else-if="kind === 'text'" class="agent-runtime-artifact-preview__text-shell">
|
|
85
|
+
<div v-if="textLoading" class="agent-runtime-artifact-preview__note">
|
|
86
|
+
Loading preview…
|
|
87
|
+
</div>
|
|
88
|
+
<div v-else-if="textError" class="agent-runtime-artifact-preview__note agent-runtime-artifact-preview__note--error">
|
|
89
|
+
{{ textError }}
|
|
90
|
+
</div>
|
|
91
|
+
<pre v-else class="agent-runtime-artifact-preview__text">{{ textContent }}</pre>
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
<div v-else class="agent-runtime-artifact-preview__fallback">
|
|
95
|
+
<p class="agent-runtime-artifact-preview__note">
|
|
96
|
+
Preview unavailable for this file type.
|
|
97
|
+
</p>
|
|
98
|
+
<a
|
|
99
|
+
v-if="resolvedSrc"
|
|
100
|
+
:href="resolvedSrc"
|
|
101
|
+
target="_blank"
|
|
102
|
+
rel="noopener noreferrer"
|
|
103
|
+
class="agent-runtime-artifact-preview__link">
|
|
104
|
+
Open file
|
|
105
|
+
</a>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
<style scoped>
|
|
111
|
+
.agent-runtime-artifact-preview{display:block;min-height:12rem;width:100%}.agent-runtime-artifact-preview__frame,.agent-runtime-artifact-preview__image{background:rgba(15,23,42,.04);border:0;border-radius:.875rem;display:block;width:100%}.agent-runtime-artifact-preview__image{max-height:min(70vh,48rem);-o-object-fit:contain;object-fit:contain}.agent-runtime-artifact-preview__frame{min-height:min(78vh,52rem)}.agent-runtime-artifact-preview__fallback,.agent-runtime-artifact-preview__text-shell{background:rgba(15,23,42,.03);border:1px solid rgba(15,23,42,.1);border-radius:.875rem;min-height:18rem}.agent-runtime-artifact-preview__text{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:.8rem;line-height:1.55;margin:0;max-height:min(72vh,52rem);overflow:auto;padding:1rem;white-space:pre-wrap;word-break:break-word}.agent-runtime-artifact-preview__note{color:rgba(15,23,42,.72);font-size:.875rem;padding:1rem}.agent-runtime-artifact-preview__note--error{color:#b91c1c}.agent-runtime-artifact-preview__link{color:inherit;display:inline-flex;margin:0 1rem 1rem;text-decoration:underline;text-underline-offset:.18em}
|
|
112
|
+
</style>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type AgentRuntimeFileLike } from '../utils/files.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
file: AgentRuntimeFileLike;
|
|
4
|
+
src?: string | null;
|
|
5
|
+
resolveSrc?: ((relPath: string) => string | null | undefined) | null;
|
|
6
|
+
textMaxChars?: number;
|
|
7
|
+
};
|
|
8
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
9
|
+
src: string | null;
|
|
10
|
+
resolveSrc: ((relPath: string) => string | null | undefined) | null;
|
|
11
|
+
textMaxChars: number;
|
|
12
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
|
+
declare const _default: typeof __VLS_export;
|
|
14
|
+
export default _default;
|