@d4y/agent-runtime-nuxt 0.1.7 → 0.1.8
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/dist/module.d.mts +15 -1
- package/dist/module.json +1 -1
- package/dist/module.mjs +9 -2
- package/dist/runtime/composables/useAgentRuntime.d.ts +118 -1
- package/dist/runtime/composables/useAgentRuntime.js +220 -44
- package/dist/runtime/server/api/app.get.d.ts +3 -0
- package/dist/runtime/server/api/app.get.js +5 -3
- package/dist/runtime/server/api/conversations/[id]/abort.post.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/env.post.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/files/preview/[...path].get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/files/raw/[...path].get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/files.get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/files.post.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/files.post.js +34 -0
- package/dist/runtime/server/api/conversations/[id]/history.get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/messages.post.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/runs/[runId].get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/runs/[runId].get.js +19 -0
- package/dist/runtime/server/api/conversations/[id]/runs.get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/runs.get.js +17 -0
- package/dist/runtime/server/api/conversations/[id]/stream.get.js +1 -1
- package/dist/runtime/server/api/conversations/[id]/workflow.get.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/workflow.get.js +17 -0
- package/dist/runtime/server/api/conversations/[id]/workflows.post.d.ts +2 -0
- package/dist/runtime/server/api/conversations/[id]/workflows.post.js +27 -0
- package/dist/runtime/server/api/conversations/[id].delete.js +1 -1
- package/dist/runtime/server/api/conversations.post.js +9 -2
- package/dist/runtime/server/utils/agent-runtime.d.ts +2 -7
- package/dist/runtime/server/utils/agent-runtime.js +11 -3
- package/dist/runtime/shared.d.ts +6 -0
- package/dist/runtime/shared.js +8 -4
- package/dist/types.d.mts +1 -1
- package/package.json +13 -13
package/dist/module.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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';
|
|
2
|
+
export { AppAuth, AppEnvField, AppInfo, AppStartField, AppStartSpec, ChatStatus, FileEntry, RunKind, RunRecord, RunStatus, SendOptions, UIMessage, UiAction, UploadFilesOptions, UseAgentRuntime, UseAgentRuntimeOptions, WorkflowStartOptions } from '../dist/runtime/composables/useAgentRuntime.js';
|
|
3
3
|
export { AgentRuntimeMarkdownRenderOptions } from '../dist/runtime/composables/useAgentRuntimeMarkdown.js';
|
|
4
4
|
export { AgentRuntimeFileLike, AgentRuntimeFilePreviewKind, AgentRuntimeResolvedAsset } from '../dist/runtime/utils/files.js';
|
|
5
5
|
export { createAgentRuntimeRequestHeaders, createScopeFingerprint, normalizeAgentRuntimeBaseUrl, resolveAgentRuntimeConfig } from '../dist/runtime/shared.js';
|
|
@@ -35,6 +35,15 @@ interface ModuleOptions {
|
|
|
35
35
|
* Falls back to `process.env.AGENT_RUNTIME_APP_ID` then `omnisearch`.
|
|
36
36
|
*/
|
|
37
37
|
appId?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Additional server-side app bindings. This lets one Nuxt app render chats
|
|
40
|
+
* for multiple agent-runtime apps without exposing app keys to the browser.
|
|
41
|
+
*/
|
|
42
|
+
apps?: Record<string, {
|
|
43
|
+
baseUrl?: string;
|
|
44
|
+
appKey?: string;
|
|
45
|
+
appId?: string;
|
|
46
|
+
}>;
|
|
38
47
|
/**
|
|
39
48
|
* URL prefix for the auto-registered Nitro proxy routes. Change it if you
|
|
40
49
|
* need to disambiguate from another module on the same `/api/...` namespace.
|
|
@@ -55,6 +64,11 @@ interface PrivateAgentRuntimeConfig {
|
|
|
55
64
|
baseUrl: string;
|
|
56
65
|
appKey: string;
|
|
57
66
|
appId: string;
|
|
67
|
+
apps?: Record<string, {
|
|
68
|
+
baseUrl?: string;
|
|
69
|
+
appKey?: string;
|
|
70
|
+
appId?: string;
|
|
71
|
+
}>;
|
|
58
72
|
}
|
|
59
73
|
declare module '@nuxt/schema' {
|
|
60
74
|
interface RuntimeConfig {
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -20,10 +20,12 @@ const module$1 = defineNuxtModule({
|
|
|
20
20
|
const appKey = userOptions.appKey ?? process.env.AGENT_RUNTIME_APP_KEY ?? "";
|
|
21
21
|
const appId = userOptions.appId ?? process.env.AGENT_RUNTIME_APP_ID ?? DEFAULTS.appId;
|
|
22
22
|
const apiPrefix = (userOptions.apiPrefix ?? DEFAULTS.apiPrefix).replace(/\/+$/, "");
|
|
23
|
+
const apps = userOptions.apps ?? {};
|
|
23
24
|
nuxt.options.runtimeConfig.agentRuntime = defu(nuxt.options.runtimeConfig.agentRuntime, {
|
|
24
25
|
baseUrl,
|
|
25
26
|
appKey,
|
|
26
|
-
appId
|
|
27
|
+
appId,
|
|
28
|
+
apps
|
|
27
29
|
});
|
|
28
30
|
nuxt.options.runtimeConfig.public.agentRuntime = defu(nuxt.options.runtimeConfig.public.agentRuntime, {
|
|
29
31
|
apiPrefix,
|
|
@@ -34,7 +36,7 @@ const module$1 = defineNuxtModule({
|
|
|
34
36
|
filename: "types/agent-runtime.d.ts",
|
|
35
37
|
getContents: () => [
|
|
36
38
|
`// Auto-generated by @d4y/agent-runtime-nuxt`,
|
|
37
|
-
`export type { UseAgentRuntime, AppInfo, AppAuth, AppEnvField, FileEntry, UiAction, SendOptions, ChatStatus } from '${resolver.resolve("./runtime/composables/useAgentRuntime")}'`,
|
|
39
|
+
`export type { UseAgentRuntime, UseAgentRuntimeOptions, AppInfo, AppStartSpec, AppStartField, AppAuth, AppEnvField, FileEntry, UiAction, RunKind, RunStatus, RunRecord, SendOptions, WorkflowStartOptions, UploadFilesOptions, ChatStatus } from '${resolver.resolve("./runtime/composables/useAgentRuntime")}'`,
|
|
38
40
|
`export type { AgentRuntimeMarkdownRenderOptions } from '${resolver.resolve("./runtime/composables/useAgentRuntimeMarkdown")}'`,
|
|
39
41
|
`export type { AgentRuntimeFileLike, AgentRuntimeFilePreviewKind, AgentRuntimeResolvedAsset } from '${resolver.resolve("./runtime/utils/files")}'`,
|
|
40
42
|
""
|
|
@@ -51,9 +53,14 @@ const module$1 = defineNuxtModule({
|
|
|
51
53
|
route("/conversations/:id/history", "conversations/[id]/history.get", "get");
|
|
52
54
|
route("/conversations/:id/stream", "conversations/[id]/stream.get", "get");
|
|
53
55
|
route("/conversations/:id/messages", "conversations/[id]/messages.post", "post");
|
|
56
|
+
route("/conversations/:id/workflows", "conversations/[id]/workflows.post", "post");
|
|
54
57
|
route("/conversations/:id/abort", "conversations/[id]/abort.post", "post");
|
|
55
58
|
route("/conversations/:id/env", "conversations/[id]/env.post", "post");
|
|
59
|
+
route("/conversations/:id/workflow", "conversations/[id]/workflow.get", "get");
|
|
60
|
+
route("/conversations/:id/runs", "conversations/[id]/runs.get", "get");
|
|
61
|
+
route("/conversations/:id/runs/:runId", "conversations/[id]/runs/[runId].get", "get");
|
|
56
62
|
route("/conversations/:id/files", "conversations/[id]/files.get", "get");
|
|
63
|
+
route("/conversations/:id/files", "conversations/[id]/files.post", "post");
|
|
57
64
|
route("/conversations/:id/files/preview/**", "conversations/[id]/files/preview/[...path].get", "get");
|
|
58
65
|
route("/conversations/:id/files/raw/**", "conversations/[id]/files/raw/[...path].get", "get");
|
|
59
66
|
}
|
|
@@ -16,12 +16,47 @@ export interface AppEnvField {
|
|
|
16
16
|
required: boolean;
|
|
17
17
|
secret: boolean;
|
|
18
18
|
description?: string;
|
|
19
|
+
default?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface AppStartField {
|
|
22
|
+
type?: 'string' | 'number' | 'boolean' | 'array';
|
|
23
|
+
items?: 'string' | 'number' | 'boolean';
|
|
24
|
+
title?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
placeholder?: string;
|
|
27
|
+
enum?: string[];
|
|
28
|
+
options?: Array<{
|
|
29
|
+
label: string;
|
|
30
|
+
value: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
disabledReason?: string;
|
|
34
|
+
}>;
|
|
35
|
+
default?: string | number | boolean | Array<string | number | boolean>;
|
|
36
|
+
}
|
|
37
|
+
export interface AppStartSpec {
|
|
38
|
+
mode: 'interactive' | 'workflow';
|
|
39
|
+
label?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
inputSchema?: {
|
|
42
|
+
type?: 'object';
|
|
43
|
+
required?: string[];
|
|
44
|
+
properties?: Record<string, AppStartField>;
|
|
45
|
+
};
|
|
46
|
+
workflow?: {
|
|
47
|
+
name?: string;
|
|
48
|
+
initialPrompt?: string;
|
|
49
|
+
runner?: 'autonomous' | 'supervisor';
|
|
50
|
+
maxIterations?: number;
|
|
51
|
+
};
|
|
19
52
|
}
|
|
20
53
|
/** Manifest summary for the active app, as returned by `${apiPrefix}/app`. */
|
|
21
54
|
export interface AppInfo {
|
|
22
55
|
appId: string;
|
|
23
56
|
name: string;
|
|
24
57
|
envSchema: Record<string, AppEnvField>;
|
|
58
|
+
start?: AppStartSpec;
|
|
59
|
+
workflows?: Record<string, unknown>;
|
|
25
60
|
}
|
|
26
61
|
/**
|
|
27
62
|
* Generic auth state. Keys are app-defined (whatever the active app declares
|
|
@@ -43,6 +78,38 @@ export interface ContextUsage {
|
|
|
43
78
|
contextWindow: number;
|
|
44
79
|
percent: number | null;
|
|
45
80
|
}
|
|
81
|
+
export type RunKind = 'workflow' | 'subagent';
|
|
82
|
+
export type RunStatus = 'queued' | 'running' | 'completed' | 'failed' | 'aborted';
|
|
83
|
+
export interface RunRecord {
|
|
84
|
+
schemaVersion: 1;
|
|
85
|
+
runId: string;
|
|
86
|
+
conversationId: string;
|
|
87
|
+
appId: string;
|
|
88
|
+
kind: RunKind;
|
|
89
|
+
status: RunStatus;
|
|
90
|
+
createdAt: string;
|
|
91
|
+
updatedAt: string;
|
|
92
|
+
startedAt?: string;
|
|
93
|
+
finishedAt?: string;
|
|
94
|
+
workflow?: string;
|
|
95
|
+
runner?: string;
|
|
96
|
+
iteration?: number;
|
|
97
|
+
maxIterations?: number;
|
|
98
|
+
agent?: string;
|
|
99
|
+
step?: string;
|
|
100
|
+
task?: string;
|
|
101
|
+
mode?: string;
|
|
102
|
+
parentRunId?: string;
|
|
103
|
+
parentToolCallId?: string;
|
|
104
|
+
parentToolName?: string;
|
|
105
|
+
edgeKind?: string;
|
|
106
|
+
edgeLabel?: string;
|
|
107
|
+
graphOrder?: number;
|
|
108
|
+
result?: unknown;
|
|
109
|
+
reason?: string;
|
|
110
|
+
error?: string;
|
|
111
|
+
sessionFile?: string;
|
|
112
|
+
}
|
|
46
113
|
export interface CompactionLogEntry {
|
|
47
114
|
phase: 'start' | 'end';
|
|
48
115
|
at: number;
|
|
@@ -96,11 +163,50 @@ export interface SendOptions {
|
|
|
96
163
|
}
|
|
97
164
|
/** Options for `start`. */
|
|
98
165
|
export interface StartOptions {
|
|
166
|
+
/** Conversation mode. `workflow` starts an autonomous run from `initialPrompt` or `workflow` input. */
|
|
167
|
+
chatType?: 'interactive' | 'workflow';
|
|
168
|
+
/** Initial autonomous workflow prompt. Used when `chatType` is `workflow`. */
|
|
169
|
+
initialPrompt?: string;
|
|
170
|
+
/** Optional named workflow input for autonomous conversations. */
|
|
171
|
+
workflow?: {
|
|
172
|
+
name?: string;
|
|
173
|
+
input?: unknown;
|
|
174
|
+
runner?: 'autonomous' | 'supervisor';
|
|
175
|
+
maxIterations?: number;
|
|
176
|
+
};
|
|
177
|
+
/** Optional previous conversation to use as context for a follow-up chat. */
|
|
178
|
+
parentConversationId?: string;
|
|
179
|
+
/** How much previous-conversation context to inject. */
|
|
180
|
+
parentContextMode?: 'summary+artifacts' | 'full-history' | 'artifacts-only';
|
|
99
181
|
/** Optional language override for the newly created conversation. */
|
|
100
182
|
language?: string;
|
|
101
183
|
/** Optional default provider request options for the conversation. */
|
|
102
184
|
requestOptions?: RequestOptions;
|
|
103
185
|
}
|
|
186
|
+
export interface WorkflowStartOptions {
|
|
187
|
+
workflow: {
|
|
188
|
+
name?: string;
|
|
189
|
+
input?: unknown;
|
|
190
|
+
runner?: 'autonomous' | 'supervisor';
|
|
191
|
+
maxIterations?: number;
|
|
192
|
+
};
|
|
193
|
+
initialPrompt?: string;
|
|
194
|
+
/** Optional language override for the workflow turn. */
|
|
195
|
+
language?: string;
|
|
196
|
+
/** Optional provider request overrides for the workflow turn. */
|
|
197
|
+
requestOptions?: RequestOptions;
|
|
198
|
+
model?: unknown;
|
|
199
|
+
}
|
|
200
|
+
export interface UploadFilesOptions {
|
|
201
|
+
targetDir?: string;
|
|
202
|
+
}
|
|
203
|
+
type MaybeRef<T> = T | Ref<T> | ComputedRef<T>;
|
|
204
|
+
export interface UseAgentRuntimeOptions {
|
|
205
|
+
/** Override the proxy prefix. Admin pages can point this at an admin-backed proxy. */
|
|
206
|
+
apiPrefix?: MaybeRef<string | null | undefined>;
|
|
207
|
+
/** Optional active app id. When it changes, the composable loads that app and starts fresh chat state. */
|
|
208
|
+
appId?: MaybeRef<string | null | undefined>;
|
|
209
|
+
}
|
|
104
210
|
/** Return shape of {@link useAgentRuntime}. All members are reactive. */
|
|
105
211
|
export interface UseAgentRuntime {
|
|
106
212
|
/** Active conversation id, or `null` until `start()` (or the first `send()`) succeeds. */
|
|
@@ -127,12 +233,22 @@ export interface UseAgentRuntime {
|
|
|
127
233
|
authReady: ComputedRef<boolean>;
|
|
128
234
|
/** Workspace files for the current conversation. Refreshed on every stream `end` event. */
|
|
129
235
|
files: Ref<FileEntry[]>;
|
|
236
|
+
/** Persisted workflow/subagent runs for the current conversation. */
|
|
237
|
+
runs: Ref<RunRecord[]>;
|
|
130
238
|
/** Build the proxied download URL for a workspace-relative path. */
|
|
131
239
|
fileUrl: (relPath: string) => string;
|
|
132
240
|
/** Build the proxied preview URL for a workspace-relative path. */
|
|
133
241
|
filePreviewUrl: (relPath: string) => string;
|
|
134
242
|
/** Manually re-fetch the workspace file listing. */
|
|
135
243
|
refreshFiles: () => Promise<void>;
|
|
244
|
+
/** Manually re-fetch persisted run records. */
|
|
245
|
+
refreshRuns: () => Promise<void>;
|
|
246
|
+
/** Open an existing conversation, load its history, and attach to the live event stream. */
|
|
247
|
+
open: (conversationId: string) => Promise<void>;
|
|
248
|
+
/** Upload user files into this conversation workspace. */
|
|
249
|
+
uploadFiles: (files: File | File[] | FileList, options?: UploadFilesOptions) => Promise<FileEntry[]>;
|
|
250
|
+
/** Start a named workflow inside the active conversation. */
|
|
251
|
+
startWorkflow: (options: WorkflowStartOptions) => Promise<void>;
|
|
136
252
|
/** Persist a new auth map; if a conversation is open, push the change to its env. */
|
|
137
253
|
saveAuth: (next: AppAuth) => Promise<void>;
|
|
138
254
|
/** Open a fresh conversation with the current auth. Returns the new id. */
|
|
@@ -169,4 +285,5 @@ export interface UseAgentRuntime {
|
|
|
169
285
|
* </template>
|
|
170
286
|
* ```
|
|
171
287
|
*/
|
|
172
|
-
export declare const useAgentRuntime: () => UseAgentRuntime;
|
|
288
|
+
export declare const useAgentRuntime: (options?: UseAgentRuntimeOptions) => UseAgentRuntime;
|
|
289
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computed, onMounted, ref, shallowRef } from "vue";
|
|
1
|
+
import { computed, onMounted, ref, shallowRef, unref, watch } from "vue";
|
|
2
2
|
import { useRuntimeConfig } from "nuxt/app";
|
|
3
3
|
const newId = () => typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `id-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
4
4
|
const authStorageKey = (appId) => `agent-runtime.app-auth.${appId}`;
|
|
@@ -35,9 +35,21 @@ const computeAuthReady = (auth, app) => {
|
|
|
35
35
|
return required.every((k) => (auth.values[k] ?? "").trim().length > 0);
|
|
36
36
|
};
|
|
37
37
|
const encodeRelPath = (relPath) => relPath.split("/").map(encodeURIComponent).join("/");
|
|
38
|
-
export const useAgentRuntime = () => {
|
|
38
|
+
export const useAgentRuntime = (options = {}) => {
|
|
39
39
|
const cfg = useRuntimeConfig().public.agentRuntime;
|
|
40
|
-
const apiPrefix = (
|
|
40
|
+
const apiPrefix = computed(() => {
|
|
41
|
+
const raw = options.apiPrefix === void 0 ? cfg?.apiPrefix : unref(options.apiPrefix);
|
|
42
|
+
return `${raw || "/api/agent-runtime"}`.replace(/\/+$/, "");
|
|
43
|
+
});
|
|
44
|
+
const selectedAppId = computed(() => {
|
|
45
|
+
const raw = options.appId === void 0 ? cfg?.appId : unref(options.appId);
|
|
46
|
+
return `${raw ?? ""}`.trim();
|
|
47
|
+
});
|
|
48
|
+
const withAppQuery = (url) => {
|
|
49
|
+
const appId = selectedAppId.value;
|
|
50
|
+
if (!appId) return url;
|
|
51
|
+
return `${url}${url.includes("?") ? "&" : "?"}appId=${encodeURIComponent(appId)}`;
|
|
52
|
+
};
|
|
41
53
|
const conversationId = ref(null);
|
|
42
54
|
const messages = shallowRef([]);
|
|
43
55
|
const status = ref("idle");
|
|
@@ -49,25 +61,69 @@ export const useAgentRuntime = () => {
|
|
|
49
61
|
const app = ref(null);
|
|
50
62
|
const auth = ref(emptyAuth());
|
|
51
63
|
const authReady = computed(() => computeAuthReady(auth.value, app.value));
|
|
52
|
-
|
|
64
|
+
let abortController = null;
|
|
65
|
+
let messageAbortController = null;
|
|
66
|
+
let currentAssistantId = null;
|
|
67
|
+
const clearLocalConversation = () => {
|
|
68
|
+
abortController?.abort();
|
|
69
|
+
abortController = null;
|
|
70
|
+
messageAbortController?.abort();
|
|
71
|
+
messageAbortController = null;
|
|
72
|
+
conversationId.value = null;
|
|
73
|
+
currentAssistantId = null;
|
|
74
|
+
replaceMessages([]);
|
|
75
|
+
uiActions.value = [];
|
|
76
|
+
contextUsage.value = null;
|
|
77
|
+
compactionInProgress.value = false;
|
|
78
|
+
compactionLog.value = [];
|
|
79
|
+
files.value = [];
|
|
80
|
+
runs.value = [];
|
|
81
|
+
status.value = "idle";
|
|
82
|
+
error.value = null;
|
|
83
|
+
};
|
|
84
|
+
const appUrl = () => {
|
|
85
|
+
const appId = selectedAppId.value;
|
|
86
|
+
const suffix = appId ? `?appId=${encodeURIComponent(appId)}` : "";
|
|
87
|
+
return `${apiPrefix.value}/app${suffix}`;
|
|
88
|
+
};
|
|
89
|
+
let appLoadSeq = 0;
|
|
90
|
+
const loadApp = async () => {
|
|
91
|
+
const seq = ++appLoadSeq;
|
|
92
|
+
if (options.appId !== void 0 && !selectedAppId.value) {
|
|
93
|
+
app.value = null;
|
|
94
|
+
auth.value = emptyAuth();
|
|
95
|
+
clearLocalConversation();
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
53
98
|
try {
|
|
54
|
-
const info = await $fetch(
|
|
99
|
+
const info = await $fetch(appUrl());
|
|
100
|
+
if (seq !== appLoadSeq) return;
|
|
55
101
|
app.value = info;
|
|
56
102
|
auth.value = loadAuth(info.appId);
|
|
57
103
|
} catch (err) {
|
|
104
|
+
if (seq !== appLoadSeq) return;
|
|
58
105
|
console.warn("[agent-runtime] failed to load app manifest", err);
|
|
106
|
+
app.value = null;
|
|
107
|
+
auth.value = emptyAuth();
|
|
59
108
|
}
|
|
109
|
+
};
|
|
110
|
+
onMounted(loadApp);
|
|
111
|
+
watch(selectedAppId, async (next, previous) => {
|
|
112
|
+
if (next === previous) return;
|
|
113
|
+
clearLocalConversation();
|
|
114
|
+
await loadApp();
|
|
60
115
|
});
|
|
61
116
|
const files = ref([]);
|
|
117
|
+
const runs = ref([]);
|
|
62
118
|
const fileUrl = (relPath) => {
|
|
63
119
|
const cid = conversationId.value;
|
|
64
120
|
if (!cid) return "";
|
|
65
|
-
return `${apiPrefix}/conversations/${cid}/files/raw/${encodeRelPath(relPath)}
|
|
121
|
+
return withAppQuery(`${apiPrefix.value}/conversations/${cid}/files/raw/${encodeRelPath(relPath)}`);
|
|
66
122
|
};
|
|
67
123
|
const filePreviewUrl = (relPath) => {
|
|
68
124
|
const cid = conversationId.value;
|
|
69
125
|
if (!cid) return "";
|
|
70
|
-
return `${apiPrefix}/conversations/${cid}/files/preview/${encodeRelPath(relPath)}
|
|
126
|
+
return withAppQuery(`${apiPrefix.value}/conversations/${cid}/files/preview/${encodeRelPath(relPath)}`);
|
|
71
127
|
};
|
|
72
128
|
const refreshFiles = async () => {
|
|
73
129
|
const cid = conversationId.value;
|
|
@@ -76,14 +132,29 @@ export const useAgentRuntime = () => {
|
|
|
76
132
|
return;
|
|
77
133
|
}
|
|
78
134
|
try {
|
|
79
|
-
const res = await $fetch(`${apiPrefix}/conversations/${cid}/files`);
|
|
135
|
+
const res = await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${cid}/files`));
|
|
80
136
|
files.value = res.items;
|
|
81
137
|
} catch (err) {
|
|
82
138
|
console.warn("[agent-runtime] file list failed", err);
|
|
83
139
|
}
|
|
84
140
|
};
|
|
85
|
-
|
|
86
|
-
|
|
141
|
+
const refreshRuns = async () => {
|
|
142
|
+
const cid = conversationId.value;
|
|
143
|
+
if (!cid) {
|
|
144
|
+
runs.value = [];
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
const res = await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${cid}/runs`));
|
|
149
|
+
runs.value = res.runs;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
console.warn("[agent-runtime] run list failed", err);
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
const upsertRun = (run) => {
|
|
155
|
+
const next = [run, ...runs.value.filter((item) => item.runId !== run.runId)];
|
|
156
|
+
runs.value = next.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
157
|
+
};
|
|
87
158
|
const replaceMessages = (next) => {
|
|
88
159
|
messages.value = next;
|
|
89
160
|
};
|
|
@@ -114,13 +185,24 @@ export const useAgentRuntime = () => {
|
|
|
114
185
|
});
|
|
115
186
|
};
|
|
116
187
|
const upsertToolPart = (toolName, toolCallId, mut) => {
|
|
188
|
+
let found = false;
|
|
189
|
+
const nextMessages = messages.value.map((message) => {
|
|
190
|
+
if (message.role !== "assistant") return message;
|
|
191
|
+
const parts = message.parts.slice();
|
|
192
|
+
const idx = parts.findIndex((p) => p.type === `tool-${toolName}` && p.toolCallId === toolCallId);
|
|
193
|
+
if (idx < 0) return message;
|
|
194
|
+
found = true;
|
|
195
|
+
parts[idx] = mut(parts[idx]);
|
|
196
|
+
return { ...message, parts };
|
|
197
|
+
});
|
|
198
|
+
if (found) {
|
|
199
|
+
replaceMessages(nextMessages);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
117
202
|
ensureAssistant();
|
|
118
203
|
updateAssistant((msg) => {
|
|
119
204
|
const parts = msg.parts.slice();
|
|
120
|
-
|
|
121
|
-
const next = mut(idx >= 0 ? parts[idx] : void 0);
|
|
122
|
-
if (idx >= 0) parts[idx] = next;
|
|
123
|
-
else parts.push(next);
|
|
205
|
+
parts.push(mut(void 0));
|
|
124
206
|
return { ...msg, parts };
|
|
125
207
|
});
|
|
126
208
|
};
|
|
@@ -208,11 +290,21 @@ export const useAgentRuntime = () => {
|
|
|
208
290
|
uiActions.value = [{ toolCallId: d.toolCallId, type: d.type, payload: d.payload, at: Date.now() }, ...uiActions.value].slice(0, 50);
|
|
209
291
|
break;
|
|
210
292
|
}
|
|
293
|
+
case "run_started":
|
|
294
|
+
case "run_updated":
|
|
295
|
+
case "run_completed":
|
|
296
|
+
case "run_failed":
|
|
297
|
+
case "run_aborted": {
|
|
298
|
+
const d = data;
|
|
299
|
+
if (d.run?.runId) upsertRun(d.run);
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
211
302
|
case "end":
|
|
212
303
|
compactionInProgress.value = false;
|
|
213
304
|
status.value = "ready";
|
|
214
305
|
currentAssistantId = null;
|
|
215
306
|
void refreshFiles();
|
|
307
|
+
void refreshRuns();
|
|
216
308
|
break;
|
|
217
309
|
case "error": {
|
|
218
310
|
const d = data;
|
|
@@ -227,7 +319,7 @@ export const useAgentRuntime = () => {
|
|
|
227
319
|
}
|
|
228
320
|
};
|
|
229
321
|
const consume = async (signal) => {
|
|
230
|
-
const res = await fetch(`${apiPrefix}/conversations/${conversationId.value}/stream
|
|
322
|
+
const res = await fetch(withAppQuery(`${apiPrefix.value}/conversations/${conversationId.value}/stream`), { signal });
|
|
231
323
|
if (!res.ok || !res.body) throw new Error(`stream failed: ${res.status}`);
|
|
232
324
|
const reader = res.body.getReader();
|
|
233
325
|
const decoder = new TextDecoder();
|
|
@@ -259,7 +351,17 @@ export const useAgentRuntime = () => {
|
|
|
259
351
|
}
|
|
260
352
|
}
|
|
261
353
|
};
|
|
262
|
-
const
|
|
354
|
+
const openStream = () => {
|
|
355
|
+
abortController?.abort();
|
|
356
|
+
abortController = new AbortController();
|
|
357
|
+
const signal = abortController.signal;
|
|
358
|
+
consume(signal).catch((err) => {
|
|
359
|
+
if (signal.aborted) return;
|
|
360
|
+
error.value = err instanceof Error ? err : new Error(String(err));
|
|
361
|
+
status.value = "error";
|
|
362
|
+
});
|
|
363
|
+
};
|
|
364
|
+
const start = async (options2 = {}) => {
|
|
263
365
|
if (!authReady.value) {
|
|
264
366
|
const missing = app.value ? Object.entries(app.value.envSchema).filter(([k, f]) => f.required && !(auth.value.values[k] ?? "").trim()).map(([k]) => k) : [];
|
|
265
367
|
throw new Error(
|
|
@@ -267,31 +369,79 @@ export const useAgentRuntime = () => {
|
|
|
267
369
|
);
|
|
268
370
|
}
|
|
269
371
|
error.value = null;
|
|
270
|
-
const res = await $fetch(`${apiPrefix}/conversations`, {
|
|
372
|
+
const res = await $fetch(`${apiPrefix.value}/conversations`, {
|
|
271
373
|
method: "POST",
|
|
272
374
|
body: {
|
|
273
375
|
env: buildEnvFromAuth(auth.value),
|
|
274
|
-
|
|
275
|
-
|
|
376
|
+
appId: (app.value?.appId ?? selectedAppId.value) || void 0,
|
|
377
|
+
chatType: options2.chatType,
|
|
378
|
+
initialPrompt: options2.initialPrompt,
|
|
379
|
+
workflow: options2.workflow,
|
|
380
|
+
parentConversationId: options2.parentConversationId,
|
|
381
|
+
parentContextMode: options2.parentContextMode,
|
|
382
|
+
language: options2.language,
|
|
383
|
+
requestOptions: options2.requestOptions
|
|
276
384
|
}
|
|
277
385
|
});
|
|
278
386
|
conversationId.value = res.conversationId;
|
|
279
|
-
|
|
280
|
-
abortController = new AbortController();
|
|
281
|
-
const signal = abortController.signal;
|
|
282
|
-
consume(signal).catch((err) => {
|
|
283
|
-
if (signal.aborted) return;
|
|
284
|
-
error.value = err instanceof Error ? err : new Error(String(err));
|
|
285
|
-
status.value = "error";
|
|
286
|
-
});
|
|
387
|
+
openStream();
|
|
287
388
|
void refreshFiles();
|
|
389
|
+
void refreshRuns();
|
|
288
390
|
return res.conversationId;
|
|
289
391
|
};
|
|
392
|
+
const open = async (id) => {
|
|
393
|
+
const nextId = id.trim();
|
|
394
|
+
if (!nextId) return;
|
|
395
|
+
abortController?.abort();
|
|
396
|
+
abortController = null;
|
|
397
|
+
messageAbortController?.abort();
|
|
398
|
+
messageAbortController = null;
|
|
399
|
+
error.value = null;
|
|
400
|
+
status.value = "ready";
|
|
401
|
+
currentAssistantId = null;
|
|
402
|
+
conversationId.value = nextId;
|
|
403
|
+
uiActions.value = [];
|
|
404
|
+
contextUsage.value = null;
|
|
405
|
+
compactionInProgress.value = false;
|
|
406
|
+
compactionLog.value = [];
|
|
407
|
+
const history = await $fetch(
|
|
408
|
+
withAppQuery(`${apiPrefix.value}/conversations/${nextId}/history`)
|
|
409
|
+
);
|
|
410
|
+
replaceMessages(history.messages ?? []);
|
|
411
|
+
openStream();
|
|
412
|
+
await Promise.all([refreshFiles(), refreshRuns()]);
|
|
413
|
+
};
|
|
414
|
+
const uploadFiles = async (filesInput, options2 = {}) => {
|
|
415
|
+
const cid = conversationId.value;
|
|
416
|
+
if (!cid) throw new Error("Start or open a conversation before uploading files.");
|
|
417
|
+
const filesArray = typeof FileList !== "undefined" && filesInput instanceof FileList ? Array.from(filesInput) : Array.isArray(filesInput) ? filesInput : [filesInput];
|
|
418
|
+
const form = new FormData();
|
|
419
|
+
if (options2.targetDir) form.append("targetDir", options2.targetDir);
|
|
420
|
+
for (const file of filesArray) form.append("files", file, file.name);
|
|
421
|
+
const res = await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${cid}/files`), {
|
|
422
|
+
method: "POST",
|
|
423
|
+
body: form
|
|
424
|
+
});
|
|
425
|
+
await refreshFiles();
|
|
426
|
+
return res.items;
|
|
427
|
+
};
|
|
428
|
+
const startWorkflow = async (options2) => {
|
|
429
|
+
const cid = conversationId.value;
|
|
430
|
+
if (!cid) throw new Error("Start or open a conversation before running a workflow.");
|
|
431
|
+
error.value = null;
|
|
432
|
+
status.value = "submitted";
|
|
433
|
+
if (!abortController) openStream();
|
|
434
|
+
await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${cid}/workflows`), {
|
|
435
|
+
method: "POST",
|
|
436
|
+
body: options2
|
|
437
|
+
});
|
|
438
|
+
await refreshRuns();
|
|
439
|
+
};
|
|
290
440
|
const saveAuth = async (next) => {
|
|
291
441
|
auth.value = { values: { ...next.values } };
|
|
292
442
|
if (app.value) persistAuth(app.value.appId, auth.value);
|
|
293
443
|
if (conversationId.value) {
|
|
294
|
-
await $fetch(`${apiPrefix}/conversations/${conversationId.value}/env
|
|
444
|
+
await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${conversationId.value}/env`), {
|
|
295
445
|
method: "POST",
|
|
296
446
|
body: { env: buildEnvFromAuth(auth.value), merge: true }
|
|
297
447
|
}).catch((err) => {
|
|
@@ -299,43 +449,63 @@ export const useAgentRuntime = () => {
|
|
|
299
449
|
});
|
|
300
450
|
}
|
|
301
451
|
};
|
|
302
|
-
const send = async (text,
|
|
452
|
+
const send = async (text, options2 = {}) => {
|
|
303
453
|
if (!text.trim()) return;
|
|
304
454
|
if (!conversationId.value) {
|
|
305
455
|
try {
|
|
306
|
-
await start({ language:
|
|
456
|
+
await start({ language: options2.language });
|
|
307
457
|
} catch (err) {
|
|
308
458
|
error.value = err instanceof Error ? err : new Error(String(err));
|
|
309
459
|
status.value = "error";
|
|
310
460
|
return;
|
|
311
461
|
}
|
|
462
|
+
} else if (!abortController) {
|
|
463
|
+
openStream();
|
|
312
464
|
}
|
|
313
465
|
error.value = null;
|
|
314
466
|
status.value = "submitted";
|
|
315
467
|
currentAssistantId = null;
|
|
468
|
+
messageAbortController?.abort();
|
|
469
|
+
const messageController = new AbortController();
|
|
470
|
+
messageAbortController = messageController;
|
|
316
471
|
replaceMessages([
|
|
317
472
|
...messages.value,
|
|
318
473
|
{ id: newId(), role: "user", parts: [{ type: "text", text }] }
|
|
319
474
|
]);
|
|
320
|
-
const wireContent =
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
475
|
+
const wireContent = options2.rewriteContent ? options2.rewriteContent(text) : text;
|
|
476
|
+
try {
|
|
477
|
+
await $fetch(withAppQuery(`${apiPrefix.value}/conversations/${conversationId.value}/messages`), {
|
|
478
|
+
method: "POST",
|
|
479
|
+
signal: messageController.signal,
|
|
480
|
+
body: {
|
|
481
|
+
content: wireContent,
|
|
482
|
+
context: options2.context,
|
|
483
|
+
language: options2.language,
|
|
484
|
+
requestOptions: options2.requestOptions
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
} catch (err) {
|
|
488
|
+
if (messageController.signal.aborted) return;
|
|
330
489
|
error.value = err instanceof Error ? err : new Error(String(err));
|
|
331
490
|
status.value = "error";
|
|
332
|
-
}
|
|
491
|
+
} finally {
|
|
492
|
+
if (messageAbortController === messageController) {
|
|
493
|
+
messageAbortController = null;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
333
496
|
};
|
|
334
497
|
const abort = async () => {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
498
|
+
const cid = conversationId.value;
|
|
499
|
+
if (!cid) return;
|
|
500
|
+
abortController?.abort();
|
|
501
|
+
abortController = null;
|
|
502
|
+
messageAbortController?.abort();
|
|
503
|
+
messageAbortController = null;
|
|
504
|
+
compactionInProgress.value = false;
|
|
338
505
|
status.value = "ready";
|
|
506
|
+
currentAssistantId = null;
|
|
507
|
+
void $fetch(withAppQuery(`${apiPrefix.value}/conversations/${cid}/abort`), { method: "POST" }).catch(() => {
|
|
508
|
+
});
|
|
339
509
|
};
|
|
340
510
|
const reset = async () => {
|
|
341
511
|
abortController?.abort();
|
|
@@ -348,6 +518,7 @@ export const useAgentRuntime = () => {
|
|
|
348
518
|
compactionInProgress.value = false;
|
|
349
519
|
compactionLog.value = [];
|
|
350
520
|
files.value = [];
|
|
521
|
+
runs.value = [];
|
|
351
522
|
status.value = "idle";
|
|
352
523
|
error.value = null;
|
|
353
524
|
};
|
|
@@ -367,9 +538,14 @@ export const useAgentRuntime = () => {
|
|
|
367
538
|
auth,
|
|
368
539
|
authReady,
|
|
369
540
|
files,
|
|
541
|
+
runs,
|
|
370
542
|
fileUrl,
|
|
371
543
|
filePreviewUrl,
|
|
372
544
|
refreshFiles,
|
|
545
|
+
refreshRuns,
|
|
546
|
+
open,
|
|
547
|
+
uploadFiles,
|
|
548
|
+
startWorkflow,
|
|
373
549
|
saveAuth,
|
|
374
550
|
start,
|
|
375
551
|
send,
|
|
@@ -2,6 +2,7 @@ interface AppEnvField {
|
|
|
2
2
|
required?: boolean;
|
|
3
3
|
secret?: boolean;
|
|
4
4
|
description?: string;
|
|
5
|
+
default?: string;
|
|
5
6
|
}
|
|
6
7
|
/**
|
|
7
8
|
* GET `${apiPrefix}/app` — returns the manifest of the configured app
|
|
@@ -11,5 +12,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
11
12
|
appId: string;
|
|
12
13
|
name: string;
|
|
13
14
|
envSchema: Record<string, AppEnvField>;
|
|
15
|
+
start: unknown;
|
|
16
|
+
workflows: Record<string, unknown>;
|
|
14
17
|
}>>;
|
|
15
18
|
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler } from "h3";
|
|
2
2
|
import { agentRuntime, agentRuntimeHeaders } from "../utils/agent-runtime.js";
|
|
3
|
-
export default defineEventHandler(async () => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const response = await fetch(`${cfg.baseUrl}/v1/apps`, {
|
|
6
6
|
headers: agentRuntimeHeaders(cfg)
|
|
7
7
|
});
|
|
@@ -22,6 +22,8 @@ export default defineEventHandler(async () => {
|
|
|
22
22
|
return {
|
|
23
23
|
appId: app.appId,
|
|
24
24
|
name: app.name,
|
|
25
|
-
envSchema: app.envSchema ?? {}
|
|
25
|
+
envSchema: app.envSchema ?? {},
|
|
26
|
+
start: app.start,
|
|
27
|
+
workflows: app.workflows ?? {}
|
|
26
28
|
};
|
|
27
29
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam, setResponseStatus } from "h3";
|
|
2
2
|
import { agentRuntime, agentRuntimeHeaders } from "../../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/abort`, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam, readBody } from "h3";
|
|
2
2
|
import { agentRuntime, agentRuntimeHeaders } from "../../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const body = await readBody(event).catch(() => ({}));
|
|
@@ -11,7 +11,7 @@ const PASS_THROUGH_HEADERS = [
|
|
|
11
11
|
"x-content-type-options"
|
|
12
12
|
];
|
|
13
13
|
export default defineEventHandler(async (event) => {
|
|
14
|
-
const cfg = agentRuntime();
|
|
14
|
+
const cfg = agentRuntime(event);
|
|
15
15
|
const id = getRouterParam(event, "id");
|
|
16
16
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
17
17
|
const apiPrefix = (useRuntimeConfig().public.agentRuntime?.apiPrefix ?? "/api/agent-runtime").replace(/\/+$/, "");
|
|
@@ -4,7 +4,7 @@ import { createError, defineEventHandler, getRouterParam, sendStream, setHeader
|
|
|
4
4
|
import { agentRuntime } from "../../../../../utils/agent-runtime.js";
|
|
5
5
|
const PASS_THROUGH_HEADERS = ["content-type", "content-length", "content-disposition", "cache-control"];
|
|
6
6
|
export default defineEventHandler(async (event) => {
|
|
7
|
-
const cfg = agentRuntime();
|
|
7
|
+
const cfg = agentRuntime(event);
|
|
8
8
|
const id = getRouterParam(event, "id");
|
|
9
9
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
10
10
|
const apiPrefix = (useRuntimeConfig().public.agentRuntime?.apiPrefix ?? "/api/agent-runtime").replace(/\/+$/, "");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
2
|
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/files`, {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam, readMultipartFormData } from "h3";
|
|
2
|
+
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
|
+
const id = getRouterParam(event, "id");
|
|
6
|
+
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
|
+
const parts = await readMultipartFormData(event);
|
|
8
|
+
if (!parts?.length) throw createError({ statusCode: 400, statusMessage: "expected multipart/form-data" });
|
|
9
|
+
const form = new FormData();
|
|
10
|
+
for (const part of parts) {
|
|
11
|
+
if (!part.name) continue;
|
|
12
|
+
if (part.filename) {
|
|
13
|
+
const bytes = new Uint8Array(part.data.length);
|
|
14
|
+
bytes.set(part.data);
|
|
15
|
+
form.append(part.name, new Blob([bytes], { type: part.type || "application/octet-stream" }), part.filename);
|
|
16
|
+
} else {
|
|
17
|
+
form.append(part.name, part.data.toString("utf8"));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/files`, {
|
|
21
|
+
method: "POST",
|
|
22
|
+
headers: {
|
|
23
|
+
"X-Agent-Runtime-App-Key": cfg.appKey
|
|
24
|
+
},
|
|
25
|
+
body: form
|
|
26
|
+
});
|
|
27
|
+
if (!response.ok) {
|
|
28
|
+
throw createError({
|
|
29
|
+
statusCode: response.status,
|
|
30
|
+
statusMessage: await response.text()
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return await response.json();
|
|
34
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
2
|
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/history`, {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam, readBody } from "h3";
|
|
2
2
|
import { agentRuntime, agentRuntimeHeaders } from "../../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const body = await readBody(event);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { agentRuntime } from "../../../../utils/agent-runtime.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
|
+
const id = getRouterParam(event, "id");
|
|
6
|
+
const runId = getRouterParam(event, "runId");
|
|
7
|
+
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
8
|
+
if (!runId) throw createError({ statusCode: 400, statusMessage: "missing run id" });
|
|
9
|
+
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/runs/${runId}`, {
|
|
10
|
+
headers: { "X-Agent-Runtime-App-Key": cfg.appKey }
|
|
11
|
+
});
|
|
12
|
+
if (!response.ok) {
|
|
13
|
+
throw createError({
|
|
14
|
+
statusCode: response.status,
|
|
15
|
+
statusMessage: await response.text()
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return await response.json();
|
|
19
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
|
+
const id = getRouterParam(event, "id");
|
|
6
|
+
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
|
+
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/runs`, {
|
|
8
|
+
headers: { "X-Agent-Runtime-App-Key": cfg.appKey }
|
|
9
|
+
});
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw createError({
|
|
12
|
+
statusCode: response.status,
|
|
13
|
+
statusMessage: await response.text()
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return await response.json();
|
|
17
|
+
});
|
|
@@ -2,7 +2,7 @@ import { Readable } from "node:stream";
|
|
|
2
2
|
import { createError, defineEventHandler, getRouterParam, sendStream, setHeader } from "h3";
|
|
3
3
|
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
4
4
|
export default defineEventHandler(async (event) => {
|
|
5
|
-
const cfg = agentRuntime();
|
|
5
|
+
const cfg = agentRuntime(event);
|
|
6
6
|
const id = getRouterParam(event, "id");
|
|
7
7
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
8
8
|
const controller = new AbortController();
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam } from "h3";
|
|
2
|
+
import { agentRuntime } from "../../../utils/agent-runtime.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
|
+
const id = getRouterParam(event, "id");
|
|
6
|
+
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
|
+
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/workflow`, {
|
|
8
|
+
headers: { "X-Agent-Runtime-App-Key": cfg.appKey }
|
|
9
|
+
});
|
|
10
|
+
if (!response.ok) {
|
|
11
|
+
throw createError({
|
|
12
|
+
statusCode: response.status,
|
|
13
|
+
statusMessage: await response.text()
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return await response.json();
|
|
17
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createError, defineEventHandler, getRouterParam, readBody } from "h3";
|
|
2
|
+
import { agentRuntime, agentRuntimeHeaders } from "../../../utils/agent-runtime.js";
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
|
+
const id = getRouterParam(event, "id");
|
|
6
|
+
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
|
+
const body = await readBody(event);
|
|
8
|
+
if (!body?.workflow) throw createError({ statusCode: 400, statusMessage: "missing workflow" });
|
|
9
|
+
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}/workflows`, {
|
|
10
|
+
method: "POST",
|
|
11
|
+
headers: agentRuntimeHeaders(cfg),
|
|
12
|
+
body: JSON.stringify({
|
|
13
|
+
workflow: body.workflow,
|
|
14
|
+
initialPrompt: body.initialPrompt,
|
|
15
|
+
requestOptions: body.requestOptions,
|
|
16
|
+
language: body.language,
|
|
17
|
+
model: body.model
|
|
18
|
+
})
|
|
19
|
+
});
|
|
20
|
+
if (!response.ok) {
|
|
21
|
+
throw createError({
|
|
22
|
+
statusCode: response.status,
|
|
23
|
+
statusMessage: await response.text()
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return await response.json();
|
|
27
|
+
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getRouterParam, setResponseStatus } from "h3";
|
|
2
2
|
import { agentRuntime } from "../../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
4
|
+
const cfg = agentRuntime(event);
|
|
5
5
|
const id = getRouterParam(event, "id");
|
|
6
6
|
if (!id) throw createError({ statusCode: 400, statusMessage: "missing conversation id" });
|
|
7
7
|
const response = await fetch(`${cfg.baseUrl}/v1/conversations/${id}`, {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createError, defineEventHandler, readBody } from "h3";
|
|
2
2
|
import { agentRuntime, agentRuntimeHeaders } from "../utils/agent-runtime.js";
|
|
3
3
|
export default defineEventHandler(async (event) => {
|
|
4
|
-
const cfg = agentRuntime();
|
|
5
4
|
const body = await readBody(event).catch(() => ({}));
|
|
5
|
+
const cfg = agentRuntime(event, body.appId);
|
|
6
6
|
const response = await fetch(`${cfg.baseUrl}/v1/conversations`, {
|
|
7
7
|
method: "POST",
|
|
8
8
|
headers: agentRuntimeHeaders(cfg),
|
|
@@ -10,8 +10,15 @@ export default defineEventHandler(async (event) => {
|
|
|
10
10
|
appId: cfg.appId,
|
|
11
11
|
env: body.env ?? {},
|
|
12
12
|
model: body.model,
|
|
13
|
+
chatType: body.chatType,
|
|
14
|
+
initialPrompt: body.initialPrompt,
|
|
15
|
+
workflow: body.workflow,
|
|
16
|
+
parentConversationId: body.parentConversationId,
|
|
17
|
+
parentContextMode: body.parentContextMode,
|
|
13
18
|
requestOptions: body.requestOptions,
|
|
14
|
-
language: body.language
|
|
19
|
+
language: body.language,
|
|
20
|
+
systemPromptAppend: body.systemPromptAppend,
|
|
21
|
+
metadata: body.metadata
|
|
15
22
|
})
|
|
16
23
|
});
|
|
17
24
|
if (!response.ok) {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
+
import { type H3Event } from 'h3';
|
|
1
2
|
import { type AgentRuntimeResolvedConfig } from '../../shared.js';
|
|
2
3
|
/** Resolved server-side configuration for talking to agent-runtime. */
|
|
3
4
|
export type AgentRuntimeRuntime = AgentRuntimeResolvedConfig;
|
|
4
|
-
|
|
5
|
-
* Read the agent-runtime section of `runtimeConfig`, validating that the app key
|
|
6
|
-
* has been provided. Throws a typed Nitro 500 otherwise so the proxy routes
|
|
7
|
-
* surface a clear error instead of silently forwarding an unauthenticated
|
|
8
|
-
* request.
|
|
9
|
-
*/
|
|
10
|
-
export declare const agentRuntime: () => AgentRuntimeRuntime;
|
|
5
|
+
export declare const agentRuntime: (event?: H3Event, appId?: string | null) => AgentRuntimeRuntime;
|
|
11
6
|
/** Build the standard JSON request headers, including the app key. */
|
|
12
7
|
export declare const agentRuntimeHeaders: (cfg: AgentRuntimeRuntime, extra?: Record<string, string>) => Record<string, string>;
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { useRuntimeConfig } from "#imports";
|
|
2
|
-
import { createError } from "h3";
|
|
2
|
+
import { createError, getQuery } from "h3";
|
|
3
3
|
import { createAgentRuntimeRequestHeaders, resolveAgentRuntimeConfig } from "../../shared.js";
|
|
4
|
-
|
|
4
|
+
const queryAppId = (event) => {
|
|
5
|
+
if (!event) return void 0;
|
|
6
|
+
const raw = getQuery(event).appId;
|
|
7
|
+
if (Array.isArray(raw)) return raw[0] ? String(raw[0]) : void 0;
|
|
8
|
+
return raw ? String(raw) : void 0;
|
|
9
|
+
};
|
|
10
|
+
export const agentRuntime = (event, appId) => {
|
|
5
11
|
try {
|
|
6
|
-
return resolveAgentRuntimeConfig(useRuntimeConfig().agentRuntime
|
|
12
|
+
return resolveAgentRuntimeConfig(useRuntimeConfig().agentRuntime, {
|
|
13
|
+
appId: appId || queryAppId(event)
|
|
14
|
+
});
|
|
7
15
|
} catch (error) {
|
|
8
16
|
throw createError({
|
|
9
17
|
statusCode: 500,
|
package/dist/runtime/shared.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ export interface AgentRuntimeConfigInput {
|
|
|
2
2
|
baseUrl?: string | null;
|
|
3
3
|
appKey?: string | null;
|
|
4
4
|
appId?: string | null;
|
|
5
|
+
apps?: Record<string, {
|
|
6
|
+
baseUrl?: string | null;
|
|
7
|
+
appKey?: string | null;
|
|
8
|
+
appId?: string | null;
|
|
9
|
+
}> | null;
|
|
5
10
|
}
|
|
6
11
|
export interface AgentRuntimeResolvedConfig {
|
|
7
12
|
baseUrl: string;
|
|
@@ -11,6 +16,7 @@ export interface AgentRuntimeResolvedConfig {
|
|
|
11
16
|
export declare const normalizeAgentRuntimeBaseUrl: (value: string | null | undefined) => string;
|
|
12
17
|
export declare const createScopeFingerprint: (parts: Array<string | null | undefined>) => string;
|
|
13
18
|
export declare const resolveAgentRuntimeConfig: (config: AgentRuntimeConfigInput | null | undefined, options?: {
|
|
19
|
+
appId?: string | null;
|
|
14
20
|
defaultAppId?: string;
|
|
15
21
|
}) => AgentRuntimeResolvedConfig;
|
|
16
22
|
export declare const createAgentRuntimeRequestHeaders: (config: Pick<AgentRuntimeResolvedConfig, "appKey">, extra?: Record<string, string>) => Record<string, string>;
|
package/dist/runtime/shared.js
CHANGED
|
@@ -5,14 +5,18 @@ export const createScopeFingerprint = (parts) => {
|
|
|
5
5
|
return createHash("sha256").update(normalized).digest("hex").slice(0, 12);
|
|
6
6
|
};
|
|
7
7
|
export const resolveAgentRuntimeConfig = (config, options) => {
|
|
8
|
-
const
|
|
8
|
+
const requestedAppId = String(options?.appId || "").trim();
|
|
9
|
+
const defaultAppId = String(config?.appId || options?.defaultAppId || "omnisearch").trim();
|
|
10
|
+
const selectedAppId = requestedAppId || defaultAppId;
|
|
11
|
+
const appConfig = selectedAppId ? config?.apps?.[selectedAppId] : void 0;
|
|
12
|
+
const appKey = String(appConfig?.appKey || (!requestedAppId || selectedAppId === config?.appId ? config?.appKey : "") || "").trim();
|
|
9
13
|
if (!appKey) {
|
|
10
|
-
throw new Error(
|
|
14
|
+
throw new Error(`[agent-runtime] AGENT_RUNTIME_APP_KEY is not configured for app "${selectedAppId}"`);
|
|
11
15
|
}
|
|
12
16
|
return {
|
|
13
|
-
baseUrl: normalizeAgentRuntimeBaseUrl(config?.baseUrl),
|
|
17
|
+
baseUrl: normalizeAgentRuntimeBaseUrl(appConfig?.baseUrl || config?.baseUrl),
|
|
14
18
|
appKey,
|
|
15
|
-
appId: String(
|
|
19
|
+
appId: String(appConfig?.appId || selectedAppId)
|
|
16
20
|
};
|
|
17
21
|
};
|
|
18
22
|
export const createAgentRuntimeRequestHeaders = (config, extra = {}) => ({
|
package/dist/types.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type AppAuth, type AppEnvField, type AppInfo, type ChatStatus, type FileEntry, type SendOptions, type UIMessage, type UiAction, type UseAgentRuntime } from '../dist/runtime/composables/useAgentRuntime.js'
|
|
1
|
+
export { type AppAuth, type AppEnvField, type AppInfo, type AppStartField, type AppStartSpec, type ChatStatus, type FileEntry, type RunKind, type RunRecord, type RunStatus, type SendOptions, type UIMessage, type UiAction, type UploadFilesOptions, type UseAgentRuntime, type UseAgentRuntimeOptions, type WorkflowStartOptions } from '../dist/runtime/composables/useAgentRuntime.js'
|
|
2
2
|
|
|
3
3
|
export { type AgentRuntimeMarkdownRenderOptions } from '../dist/runtime/composables/useAgentRuntimeMarkdown.js'
|
|
4
4
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d4y/agent-runtime-nuxt",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "Headless Nuxt module that connects a Nuxt app to an agent-runtime server. Ships server-side proxy routes (so your X-Agent-Runtime-App-Key never leaves the server) and a single composable, useAgentRuntime(), that exposes a typed chat client.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -57,20 +57,20 @@
|
|
|
57
57
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@nuxt/kit": "
|
|
61
|
-
"ai": "
|
|
62
|
-
"defu": "
|
|
63
|
-
"h3": "
|
|
64
|
-
"markdown-it": "
|
|
60
|
+
"@nuxt/kit": "4.4.4",
|
|
61
|
+
"ai": "6.0.175",
|
|
62
|
+
"defu": "6.1.7",
|
|
63
|
+
"h3": "1.15.11",
|
|
64
|
+
"markdown-it": "14.1.1"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@nuxt/module-builder": "
|
|
68
|
-
"@nuxt/schema": "
|
|
69
|
-
"@types/markdown-it": "
|
|
70
|
-
"nuxt": "
|
|
71
|
-
"typescript": "
|
|
72
|
-
"vue": "
|
|
73
|
-
"vue-tsc": "
|
|
67
|
+
"@nuxt/module-builder": "1.0.2",
|
|
68
|
+
"@nuxt/schema": "4.4.4",
|
|
69
|
+
"@types/markdown-it": "14.1.2",
|
|
70
|
+
"nuxt": "4.4.4",
|
|
71
|
+
"typescript": "6.0.3",
|
|
72
|
+
"vue": "3.5.34",
|
|
73
|
+
"vue-tsc": "3.2.8"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"nuxt": "^3.13.0 || ^4.0.0"
|