@d4y/agent-runtime-nuxt 0.1.4 → 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/components/AgentRuntimeMarkdown.d.vue.ts +10 -0
- package/dist/runtime/components/AgentRuntimeMarkdown.vue +17 -7
- package/dist/runtime/components/AgentRuntimeMarkdown.vue.d.ts +10 -0
- package/dist/runtime/composables/useAgentRuntime.d.ts +118 -1
- package/dist/runtime/composables/useAgentRuntime.js +220 -44
- package/dist/runtime/composables/useAgentRuntimeMarkdown.d.ts +5 -0
- package/dist/runtime/composables/useAgentRuntimeMarkdown.js +11 -8
- 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 +15 -15
|
@@ -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,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import MarkdownIt from 'markdown-it';
|
|
2
2
|
import { type AgentRuntimeAssetResolverOptions } from '../utils/files.js';
|
|
3
3
|
export interface AgentRuntimeMarkdownRenderOptions extends AgentRuntimeAssetResolverOptions {
|
|
4
|
+
previewLinkLabel?: string;
|
|
5
|
+
downloadLinkLabel?: string;
|
|
6
|
+
pdfPreviewTitleLabel?: string;
|
|
7
|
+
htmlPreviewTitleLabel?: string;
|
|
8
|
+
showPdfEmbedToolbar?: boolean;
|
|
4
9
|
}
|
|
5
10
|
export declare const createAgentRuntimeMarkdownRenderer: (options?: AgentRuntimeMarkdownRenderOptions) => MarkdownIt;
|
|
6
11
|
export declare const useAgentRuntimeMarkdown: (options?: AgentRuntimeMarkdownRenderOptions) => {
|
|
@@ -33,7 +33,7 @@ const buildImageMarkup = (md, asset, alt, title) => {
|
|
|
33
33
|
const attrs = previewAttrs(md, asset);
|
|
34
34
|
return `<a href="${safePreviewUrl}" target="_blank" rel="noopener noreferrer" class="agent-runtime-md-image-link" ${attrs}><img src="${safePreviewUrl}" alt="${safeAlt}" loading="lazy" class="agent-runtime-md-image"${titleAttr} /></a>`;
|
|
35
35
|
};
|
|
36
|
-
const buildPreviewShellMarkup = (md, asset, label) => {
|
|
36
|
+
const buildPreviewShellMarkup = (md, asset, label, options) => {
|
|
37
37
|
const previewUrl = asset.previewUrl;
|
|
38
38
|
if (!previewUrl) {
|
|
39
39
|
return buildDownloadLinkMarkup(md, asset, label);
|
|
@@ -44,16 +44,19 @@ const buildPreviewShellMarkup = (md, asset, label) => {
|
|
|
44
44
|
const shellClass = asset.kind === "pdf" ? "agent-runtime-md-pdf-shell" : "agent-runtime-md-html-shell";
|
|
45
45
|
const frameClass = asset.kind === "pdf" ? "agent-runtime-md-pdf-frame" : "agent-runtime-md-html-frame";
|
|
46
46
|
const frameAttrs = asset.kind === "pdf" ? "" : ' sandbox="" referrerpolicy="no-referrer"';
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
47
|
+
const titleLabel = asset.kind === "pdf" ? options.pdfPreviewTitleLabel ?? "PDF preview" : options.htmlPreviewTitleLabel ?? "HTML preview";
|
|
48
|
+
const title = `${titleLabel}: ${label}`;
|
|
49
|
+
const showToolbar = asset.kind !== "pdf" || options.showPdfEmbedToolbar === true;
|
|
50
|
+
const downloadButton = asset.canDownload && asset.rawUrl ? `<a href="${escapeAttr(md, asset.rawUrl)}" target="_blank" rel="noopener noreferrer" class="agent-runtime-md-download-link">${escapeAttr(md, options.downloadLinkLabel ?? "Download")}</a>` : "";
|
|
51
|
+
const toolbar = showToolbar ? `<span class="agent-runtime-md-embed-toolbar"><span class="agent-runtime-md-embed-label">${safeLabel}</span><span class="agent-runtime-md-embed-actions"><a href="${safePreviewUrl}" target="_blank" rel="noopener noreferrer" class="agent-runtime-md-preview-link" ${attrs}>${escapeAttr(md, options.previewLinkLabel ?? "Preview")}</a>${downloadButton}</span></span>` : "";
|
|
52
|
+
return `<span class="${shellClass}">${toolbar}<iframe src="${safePreviewUrl}" title="${escapeAttr(md, title)}" loading="lazy"${frameAttrs} class="${frameClass}"></iframe></span>`;
|
|
50
53
|
};
|
|
51
54
|
const toHtmlToken = (state, markup) => {
|
|
52
55
|
const token = new state.Token("html_inline", "", 0);
|
|
53
56
|
token.content = markup;
|
|
54
57
|
return token;
|
|
55
58
|
};
|
|
56
|
-
const renderWorkspaceLink = (md, asset, label) => {
|
|
59
|
+
const renderWorkspaceLink = (md, asset, label, options) => {
|
|
57
60
|
if (asset.kind === "blocked") {
|
|
58
61
|
return escapeAttr(md, label);
|
|
59
62
|
}
|
|
@@ -61,7 +64,7 @@ const renderWorkspaceLink = (md, asset, label) => {
|
|
|
61
64
|
return buildImageMarkup(md, asset, label);
|
|
62
65
|
}
|
|
63
66
|
if (asset.kind === "html" || asset.kind === "pdf") {
|
|
64
|
-
return buildPreviewShellMarkup(md, asset, label);
|
|
67
|
+
return buildPreviewShellMarkup(md, asset, label, options);
|
|
65
68
|
}
|
|
66
69
|
return buildDownloadLinkMarkup(md, asset, label);
|
|
67
70
|
};
|
|
@@ -107,7 +110,7 @@ export const createAgentRuntimeMarkdownRenderer = (options = {}) => {
|
|
|
107
110
|
if (asset.kind === "image") {
|
|
108
111
|
return buildImageMarkup(md, asset, alt, title);
|
|
109
112
|
}
|
|
110
|
-
return renderWorkspaceLink(md, asset, alt || asset.label);
|
|
113
|
+
return renderWorkspaceLink(md, asset, alt || asset.label, options);
|
|
111
114
|
};
|
|
112
115
|
md.core.ruler.after("inline", "agent_runtime_workspace_links", (state) => {
|
|
113
116
|
for (const blockToken of state.tokens) {
|
|
@@ -128,7 +131,7 @@ export const createAgentRuntimeMarkdownRenderer = (options = {}) => {
|
|
|
128
131
|
out.push(child);
|
|
129
132
|
continue;
|
|
130
133
|
}
|
|
131
|
-
out.push(toHtmlToken(state, renderWorkspaceLink(md, asset, next.content || asset.label)));
|
|
134
|
+
out.push(toHtmlToken(state, renderWorkspaceLink(md, asset, next.content || asset.label, options)));
|
|
132
135
|
idx += 2;
|
|
133
136
|
}
|
|
134
137
|
blockToken.children = out;
|
|
@@ -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
|
+
});
|