memeloop 0.0.1 → 0.1.1
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 +63 -0
- package/dist/browser.cjs +1413 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +3066 -0
- package/dist/browser.d.ts +3066 -0
- package/dist/browser.js +43 -0
- package/dist/chunk-2C6BJZI3.js +382 -0
- package/dist/chunk-2C6BJZI3.js.map +1 -0
- package/dist/chunk-426CJUZP.js +630 -0
- package/dist/chunk-426CJUZP.js.map +1 -0
- package/dist/chunk-7ZDTB4VZ.js +63 -0
- package/dist/chunk-7ZDTB4VZ.js.map +1 -0
- package/dist/chunk-AZFYDWIN.js +98 -0
- package/dist/chunk-AZFYDWIN.js.map +1 -0
- package/dist/chunk-BGPU4RR7.js +367 -0
- package/dist/chunk-BGPU4RR7.js.map +1 -0
- package/dist/chunk-CCEFAOSH.js +496 -0
- package/dist/chunk-CCEFAOSH.js.map +1 -0
- package/dist/chunk-FWSY5HOA.js +63 -0
- package/dist/chunk-FWSY5HOA.js.map +1 -0
- package/dist/chunk-GYIOMQMY.js +8726 -0
- package/dist/chunk-GYIOMQMY.js.map +1 -0
- package/dist/chunk-K6P63KD4.js +68 -0
- package/dist/chunk-K6P63KD4.js.map +1 -0
- package/dist/chunk-KFS2EJT6.js +42 -0
- package/dist/chunk-KFS2EJT6.js.map +1 -0
- package/dist/chunk-MAJWHAKR.js +3637 -0
- package/dist/chunk-MAJWHAKR.js.map +1 -0
- package/dist/chunk-MRKY4HGF.js +205 -0
- package/dist/chunk-MRKY4HGF.js.map +1 -0
- package/dist/chunk-T7FSXWFR.js +2744 -0
- package/dist/chunk-T7FSXWFR.js.map +1 -0
- package/dist/chunk-VZKQX5PP.js +1 -0
- package/dist/chunk-VZKQX5PP.js.map +1 -0
- package/dist/chunk-WAI6BODI.js +175 -0
- package/dist/chunk-WAI6BODI.js.map +1 -0
- package/dist/chunk-YMNXDNDW.js +798 -0
- package/dist/chunk-YMNXDNDW.js.map +1 -0
- package/dist/conversation.cjs +208 -0
- package/dist/conversation.cjs.map +1 -0
- package/dist/conversation.d.cts +100 -0
- package/dist/conversation.d.ts +100 -0
- package/dist/conversation.js +21 -0
- package/dist/conversation.js.map +1 -0
- package/dist/device-network-portable.cjs +702 -0
- package/dist/device-network-portable.cjs.map +1 -0
- package/dist/device-network-portable.d.cts +110 -0
- package/dist/device-network-portable.d.ts +110 -0
- package/dist/device-network-portable.js +53 -0
- package/dist/device-network-portable.js.map +1 -0
- package/dist/device-network.cjs +906 -0
- package/dist/device-network.cjs.map +1 -0
- package/dist/device-network.d.cts +6 -0
- package/dist/device-network.d.ts +6 -0
- package/dist/device-network.js +59 -0
- package/dist/device-network.js.map +1 -0
- package/dist/fetchProvider-WWnWnQFP.d.ts +91 -0
- package/dist/fetchProvider-toTHy5Nu.d.cts +91 -0
- package/dist/index.cjs +28051 -5459
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +94 -1320
- package/dist/index.d.ts +94 -1320
- package/dist/index.js +10616 -2420
- package/dist/index.js.map +1 -1
- package/dist/interface-IrKBFtL1.d.cts +493 -0
- package/dist/interface-IrKBFtL1.d.ts +493 -0
- package/dist/llm-providers.cjs +43 -8
- package/dist/llm-providers.cjs.map +1 -1
- package/dist/llm-providers.d.cts +2 -1
- package/dist/llm-providers.d.ts +2 -1
- package/dist/llm-providers.js +4 -2
- package/dist/llm-providers.js.map +1 -1
- package/dist/loop-api.cjs +5227 -2010
- package/dist/loop-api.cjs.map +1 -1
- package/dist/loop-api.d.cts +11 -5
- package/dist/loop-api.d.ts +11 -5
- package/dist/loop-api.js +86 -49
- package/dist/mobile.cjs +2711 -0
- package/dist/mobile.cjs.map +1 -0
- package/dist/mobile.d.cts +6 -0
- package/dist/mobile.d.ts +6 -0
- package/dist/mobile.js +22 -0
- package/dist/mobile.js.map +1 -0
- package/dist/orchestration-portable-BHB_YrNN.d.ts +2192 -0
- package/dist/orchestration-portable-mvYBvGBb.d.cts +2192 -0
- package/dist/orchestration-portable.cjs +9553 -0
- package/dist/orchestration-portable.cjs.map +1 -0
- package/dist/orchestration-portable.d.cts +5 -0
- package/dist/orchestration-portable.d.ts +5 -0
- package/dist/orchestration-portable.js +290 -0
- package/dist/orchestration-portable.js.map +1 -0
- package/dist/pairingInvite-BXPWY3aM.d.cts +149 -0
- package/dist/pairingInvite-Cuz0wuq9.d.ts +149 -0
- package/dist/promptConcat-0WNFTg4l.d.ts +516 -0
- package/dist/promptConcat-D6wr5V-V.d.cts +516 -0
- package/dist/providerRegistry-Bi6pAvSj.d.ts +86 -0
- package/dist/providerRegistry-CPsktuiX.d.cts +86 -0
- package/dist/registry-D0kbxksn.d.cts +393 -0
- package/dist/registry-DDbvhlhs.d.ts +393 -0
- package/dist/remoteClient-B_spK019.d.ts +87 -0
- package/dist/remoteClient-CBggnRy3.d.cts +87 -0
- package/dist/runtime-PGWR6FIV.js +18 -0
- package/dist/runtime-PGWR6FIV.js.map +1 -0
- package/dist/scriptDeploymentPipeline-CXJcC82H.d.ts +2464 -0
- package/dist/scriptDeploymentPipeline-yG1ZhVVI.d.cts +2464 -0
- package/dist/syncCloudDevices-BEqwgrhD.d.ts +49 -0
- package/dist/syncCloudDevices-Ds_Kcgrv.d.cts +49 -0
- package/dist/types-7pYti-k9.d.cts +255 -0
- package/dist/types-CdFVSntj.d.ts +255 -0
- package/package.json +110 -35
- package/dist/anthropic.cjs +0 -72
- package/dist/anthropic.cjs.map +0 -1
- package/dist/anthropic.d.cts +0 -21
- package/dist/anthropic.d.ts +0 -21
- package/dist/anthropic.js +0 -21
- package/dist/anthropic.js.map +0 -1
- package/dist/azure.cjs +0 -72
- package/dist/azure.cjs.map +0 -1
- package/dist/azure.d.cts +0 -21
- package/dist/azure.d.ts +0 -21
- package/dist/azure.js +0 -21
- package/dist/azure.js.map +0 -1
- package/dist/chunk-3CN7DFBL.js +0 -4894
- package/dist/chunk-3CN7DFBL.js.map +0 -1
- package/dist/chunk-4AZ4D7U5.js +0 -32
- package/dist/chunk-4AZ4D7U5.js.map +0 -1
- package/dist/chunk-6ON4XSOV.js +0 -63
- package/dist/chunk-6ON4XSOV.js.map +0 -1
- package/dist/chunk-DJQNGIXX.js +0 -4793
- package/dist/chunk-DJQNGIXX.js.map +0 -1
- package/dist/chunk-FKQP6AOQ.js +0 -32
- package/dist/chunk-FKQP6AOQ.js.map +0 -1
- package/dist/chunk-OVJ7JJBA.js +0 -35
- package/dist/chunk-OVJ7JJBA.js.map +0 -1
- package/dist/chunk-P4UZ7IXC.js +0 -42
- package/dist/chunk-YHJ2AEFR.js +0 -4933
- package/dist/chunk-YHJ2AEFR.js.map +0 -1
- package/dist/chunk-YVK7RYRO.js +0 -4973
- package/dist/chunk-YVK7RYRO.js.map +0 -1
- package/dist/code-assistant.json +0 -114
- package/dist/cohere.cjs +0 -72
- package/dist/cohere.cjs.map +0 -1
- package/dist/cohere.d.cts +0 -21
- package/dist/cohere.d.ts +0 -21
- package/dist/cohere.js +0 -21
- package/dist/cohere.js.map +0 -1
- package/dist/deepseek.cjs +0 -72
- package/dist/deepseek.cjs.map +0 -1
- package/dist/deepseek.d.cts +0 -21
- package/dist/deepseek.d.ts +0 -21
- package/dist/deepseek.js +0 -21
- package/dist/deepseek.js.map +0 -1
- package/dist/dist-65U7OYRG.js +0 -1257
- package/dist/dist-65U7OYRG.js.map +0 -1
- package/dist/fetchProvider-Cu4WkU5O.d.cts +0 -819
- package/dist/fetchProvider-Cu4WkU5O.d.ts +0 -819
- package/dist/frontend-ui-ux.json +0 -105
- package/dist/general-assistant.json +0 -95
- package/dist/git-master.json +0 -51
- package/dist/google-vertex.cjs +0 -72
- package/dist/google-vertex.cjs.map +0 -1
- package/dist/google-vertex.d.cts +0 -21
- package/dist/google-vertex.d.ts +0 -21
- package/dist/google-vertex.js +0 -21
- package/dist/google-vertex.js.map +0 -1
- package/dist/google.cjs +0 -72
- package/dist/google.cjs.map +0 -1
- package/dist/google.d.cts +0 -21
- package/dist/google.d.ts +0 -21
- package/dist/google.js +0 -21
- package/dist/google.js.map +0 -1
- package/dist/groq.cjs +0 -72
- package/dist/groq.cjs.map +0 -1
- package/dist/groq.d.cts +0 -21
- package/dist/groq.d.ts +0 -21
- package/dist/groq.js +0 -21
- package/dist/groq.js.map +0 -1
- package/dist/index.d.mts +0 -3203
- package/dist/index.mjs +0 -7064
- package/dist/index.mjs.map +0 -1
- package/dist/mistral.cjs +0 -72
- package/dist/mistral.cjs.map +0 -1
- package/dist/mistral.d.cts +0 -21
- package/dist/mistral.d.ts +0 -21
- package/dist/mistral.js +0 -21
- package/dist/mistral.js.map +0 -1
- package/dist/multipart-parser-EJCXIUHC.js +0 -372
- package/dist/multipart-parser-EJCXIUHC.js.map +0 -1
- package/dist/openai.cjs +0 -72
- package/dist/openai.cjs.map +0 -1
- package/dist/openai.d.cts +0 -21
- package/dist/openai.d.ts +0 -21
- package/dist/openai.js +0 -21
- package/dist/openai.js.map +0 -1
- package/dist/perplexity.cjs +0 -72
- package/dist/perplexity.cjs.map +0 -1
- package/dist/perplexity.d.cts +0 -21
- package/dist/perplexity.d.ts +0 -21
- package/dist/perplexity.js +0 -21
- package/dist/perplexity.js.map +0 -1
- package/dist/playwright.json +0 -52
- package/dist/promptConcat-BJdazTg5.d.cts +0 -1832
- package/dist/promptConcat-BJdazTg5.d.ts +0 -1832
- package/dist/promptConcat-CAkpni_8.d.cts +0 -1834
- package/dist/promptConcat-CAkpni_8.d.ts +0 -1834
- package/dist/promptConcat-CfH5-GAE.d.cts +0 -1036
- package/dist/promptConcat-ChcAZOOL.d.ts +0 -1036
- package/dist/promptConcat-G5TnJVRy.d.cts +0 -1800
- package/dist/promptConcat-G5TnJVRy.d.ts +0 -1800
- package/dist/promptConcat-L72eowzp.d.ts +0 -1090
- package/dist/promptConcat-eLHdN7K8.d.cts +0 -1090
- package/dist/src-VTSXKG72.js +0 -1409
- package/dist/src-VTSXKG72.js.map +0 -1
- package/dist/togetherai.cjs +0 -72
- package/dist/togetherai.cjs.map +0 -1
- package/dist/togetherai.d.cts +0 -21
- package/dist/togetherai.d.ts +0 -21
- package/dist/togetherai.js +0 -21
- package/dist/togetherai.js.map +0 -1
- package/dist/types-B0Jm2l38.d.cts +0 -767
- package/dist/types-B0Jm2l38.d.ts +0 -767
- package/dist/xai.cjs +0 -72
- package/dist/xai.cjs.map +0 -1
- package/dist/xai.d.cts +0 -21
- package/dist/xai.d.ts +0 -21
- package/dist/xai.js +0 -21
- package/dist/xai.js.map +0 -1
- /package/dist/{chunk-P4UZ7IXC.js.map → browser.js.map} +0 -0
package/dist/browser.cjs
ADDED
|
@@ -0,0 +1,1413 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/browser.ts
|
|
21
|
+
var browser_exports = {};
|
|
22
|
+
__export(browser_exports, {
|
|
23
|
+
ALL_CATEGORIES: () => ALL_CATEGORIES,
|
|
24
|
+
AgentCreationController: () => AgentCreationController,
|
|
25
|
+
AgentDefinitionEditorController: () => AgentDefinitionEditorController,
|
|
26
|
+
AgentSessionController: () => AgentSessionController,
|
|
27
|
+
OrchestrationError: () => OrchestrationError,
|
|
28
|
+
PromptPreviewController: () => PromptPreviewController,
|
|
29
|
+
REMOTE_ORCHESTRATION_PROTOCOL: () => REMOTE_ORCHESTRATION_PROTOCOL,
|
|
30
|
+
TiddlyWikiHttpStorage: () => TiddlyWikiHttpStorage,
|
|
31
|
+
createFetchOrchestrationTransport: () => createFetchOrchestrationTransport,
|
|
32
|
+
createNamespacedOrchestrationClient: () => createNamespacedOrchestrationClient,
|
|
33
|
+
createReadOnlyOrchestrationClient: () => createReadOnlyOrchestrationClient,
|
|
34
|
+
createRemoteOrchestrationClient: () => createRemoteOrchestrationClient,
|
|
35
|
+
createRemoteOrchestrationHandler: () => createRemoteOrchestrationHandler,
|
|
36
|
+
getCategoryConfig: () => getCategoryConfig,
|
|
37
|
+
isTaskCategory: () => isTaskCategory,
|
|
38
|
+
resolveCategory: () => resolveCategory
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(browser_exports);
|
|
41
|
+
|
|
42
|
+
// src/orchestration/errors.ts
|
|
43
|
+
var OrchestrationError = class extends Error {
|
|
44
|
+
code;
|
|
45
|
+
retryable;
|
|
46
|
+
retryAfterMs;
|
|
47
|
+
reason;
|
|
48
|
+
details;
|
|
49
|
+
constructor(data) {
|
|
50
|
+
super(data.message);
|
|
51
|
+
this.name = "OrchestrationError";
|
|
52
|
+
this.code = data.code;
|
|
53
|
+
this.retryable = data.retryable;
|
|
54
|
+
this.retryAfterMs = data.retryAfterMs;
|
|
55
|
+
this.reason = data.reason;
|
|
56
|
+
this.details = data.details;
|
|
57
|
+
}
|
|
58
|
+
toJSON() {
|
|
59
|
+
return {
|
|
60
|
+
code: this.code,
|
|
61
|
+
message: this.message,
|
|
62
|
+
retryable: this.retryable,
|
|
63
|
+
retryAfterMs: this.retryAfterMs,
|
|
64
|
+
reason: this.reason,
|
|
65
|
+
details: this.details
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
// src/storage/tiddlyWikiHttpStorage.ts
|
|
71
|
+
var PREFIX = "$:/memeloop";
|
|
72
|
+
var DEFAULT_MAX_INLINE_BLOB = 256 * 1024;
|
|
73
|
+
var DEFAULT_CAS_ATTEMPTS = 3;
|
|
74
|
+
function bytesToBase64(bytes) {
|
|
75
|
+
let binary = "";
|
|
76
|
+
for (const byte of bytes) binary += String.fromCharCode(byte);
|
|
77
|
+
return btoa(binary);
|
|
78
|
+
}
|
|
79
|
+
function base64ToBytes(value) {
|
|
80
|
+
const binary = atob(value);
|
|
81
|
+
const bytes = new Uint8Array(binary.length);
|
|
82
|
+
for (let index = 0; index < binary.length; index += 1) bytes[index] = binary.charCodeAt(index);
|
|
83
|
+
return bytes;
|
|
84
|
+
}
|
|
85
|
+
function escapeFilterValue(value) {
|
|
86
|
+
return value.replace(/["\\[\]]/g, (character) => `\\${character}`);
|
|
87
|
+
}
|
|
88
|
+
var TiddlyWikiHttpStorage = class {
|
|
89
|
+
baseUrl;
|
|
90
|
+
recipe;
|
|
91
|
+
fetchImpl;
|
|
92
|
+
credentialHandle;
|
|
93
|
+
credentialResolver;
|
|
94
|
+
maxInlineBlobBytes;
|
|
95
|
+
maxCasAttempts;
|
|
96
|
+
constructor(options) {
|
|
97
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
98
|
+
this.recipe = options.recipe ?? "default";
|
|
99
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
100
|
+
this.maxInlineBlobBytes = options.maxInlineBlobBytes ?? DEFAULT_MAX_INLINE_BLOB;
|
|
101
|
+
this.maxCasAttempts = options.maxCasAttempts ?? DEFAULT_CAS_ATTEMPTS;
|
|
102
|
+
if (options.credentialHandle === void 0 !== (options.credentialResolver === void 0)) {
|
|
103
|
+
throw new OrchestrationError({
|
|
104
|
+
code: "INVALID",
|
|
105
|
+
message: "credentialHandle and credentialResolver must be provided together",
|
|
106
|
+
retryable: false
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
this.credentialHandle = options.credentialHandle;
|
|
110
|
+
this.credentialResolver = options.credentialResolver;
|
|
111
|
+
}
|
|
112
|
+
eventTitle(conversationId, messageId) {
|
|
113
|
+
return `${PREFIX}/e/${conversationId}/${messageId}`;
|
|
114
|
+
}
|
|
115
|
+
metaTitle(conversationId) {
|
|
116
|
+
return `${PREFIX}/meta/${conversationId}`;
|
|
117
|
+
}
|
|
118
|
+
blobTitle(contentHash) {
|
|
119
|
+
return `${PREFIX}/blob/${contentHash}`;
|
|
120
|
+
}
|
|
121
|
+
definitionTitle(id) {
|
|
122
|
+
return `${PREFIX}/def/${id}`;
|
|
123
|
+
}
|
|
124
|
+
instanceTitle(id) {
|
|
125
|
+
return `${PREFIX}/inst/${id}`;
|
|
126
|
+
}
|
|
127
|
+
imTitle(channelId, imUserId) {
|
|
128
|
+
return `${PREFIX}/im/${channelId}/${imUserId}`;
|
|
129
|
+
}
|
|
130
|
+
tiddlerUrl(title) {
|
|
131
|
+
return `${this.baseUrl}/recipes/${encodeURIComponent(this.recipe)}/tiddlers/${encodeURIComponent(title)}`;
|
|
132
|
+
}
|
|
133
|
+
filterUrl(filter) {
|
|
134
|
+
return `${this.baseUrl}/recipes/${encodeURIComponent(this.recipe)}/tiddlers.json?filter=${encodeURIComponent(filter)}`;
|
|
135
|
+
}
|
|
136
|
+
async headers(url, method, extra = {}) {
|
|
137
|
+
const credentialHeaders = this.credentialHandle && this.credentialResolver ? await this.credentialResolver.resolveHeaders(this.credentialHandle, { url, method }) : {};
|
|
138
|
+
return {
|
|
139
|
+
"content-type": "application/json",
|
|
140
|
+
"x-requested-with": "TiddlyWiki",
|
|
141
|
+
...credentialHeaders,
|
|
142
|
+
...extra
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/** GET a tiddler; returns null on 404. Includes the ETag when the server sends one. */
|
|
146
|
+
async readTiddler(title) {
|
|
147
|
+
const url = this.tiddlerUrl(title);
|
|
148
|
+
const response = await this.fetchImpl(url, { headers: await this.headers(url, "GET") });
|
|
149
|
+
if (response.status === 404) return null;
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
throw new OrchestrationError({ code: "UNAVAILABLE", message: `tiddler read failed: HTTP ${response.status}`, retryable: true });
|
|
152
|
+
}
|
|
153
|
+
const tiddler = await response.json();
|
|
154
|
+
const etag = response.headers.get("etag") ?? void 0;
|
|
155
|
+
return { tiddler, ...etag ? { etag } : {} };
|
|
156
|
+
}
|
|
157
|
+
/** CAS write: If-Match when an ETag is known; bounded retries on 412/409. */
|
|
158
|
+
async writeTiddler(title, build) {
|
|
159
|
+
for (let attempt = 1; attempt <= this.maxCasAttempts; attempt += 1) {
|
|
160
|
+
const current = await this.readTiddler(title);
|
|
161
|
+
if (current && !current.etag) {
|
|
162
|
+
throw new OrchestrationError({ code: "CONFLICT", message: `tiddler '${title}' has no ETag for a safe update`, retryable: false });
|
|
163
|
+
}
|
|
164
|
+
const next = build(current?.tiddler ?? null);
|
|
165
|
+
const url = this.tiddlerUrl(title);
|
|
166
|
+
const precondition = current ? { "if-match": current.etag } : { "if-none-match": "*" };
|
|
167
|
+
const response = await this.fetchImpl(url, {
|
|
168
|
+
method: "PUT",
|
|
169
|
+
headers: await this.headers(url, "PUT", precondition),
|
|
170
|
+
body: JSON.stringify(next)
|
|
171
|
+
});
|
|
172
|
+
if (response.ok) return;
|
|
173
|
+
if (response.status === 412 || response.status === 409) {
|
|
174
|
+
if (attempt === this.maxCasAttempts) {
|
|
175
|
+
throw new OrchestrationError({
|
|
176
|
+
code: "CONFLICT",
|
|
177
|
+
message: `tiddler '${title}' was modified concurrently after ${attempt} CAS attempts`,
|
|
178
|
+
retryable: true
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
throw new OrchestrationError({ code: "UNAVAILABLE", message: `tiddler write failed: HTTP ${response.status}`, retryable: true });
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
async listByPrefix(prefix) {
|
|
187
|
+
const filter = `[prefix["${escapeFilterValue(prefix)}"]]`;
|
|
188
|
+
const url = this.filterUrl(filter);
|
|
189
|
+
const response = await this.fetchImpl(url, { headers: await this.headers(url, "GET") });
|
|
190
|
+
if (!response.ok) {
|
|
191
|
+
throw new OrchestrationError({ code: "UNAVAILABLE", message: `tiddler list failed: HTTP ${response.status}`, retryable: true });
|
|
192
|
+
}
|
|
193
|
+
return await response.json();
|
|
194
|
+
}
|
|
195
|
+
parsePayload(tiddler) {
|
|
196
|
+
return JSON.parse(tiddler.text ?? "{}");
|
|
197
|
+
}
|
|
198
|
+
async listConversations(options = {}) {
|
|
199
|
+
const tiddlers = await this.listByPrefix(`${PREFIX}/meta/`);
|
|
200
|
+
const metas = tiddlers.map((tiddler) => this.parsePayload(tiddler));
|
|
201
|
+
metas.sort((a, b) => (b.lastMessageTimestamp ?? 0) - (a.lastMessageTimestamp ?? 0));
|
|
202
|
+
const offset = options.offset ?? 0;
|
|
203
|
+
const limit = options.limit ?? metas.length;
|
|
204
|
+
return metas.slice(offset, offset + limit);
|
|
205
|
+
}
|
|
206
|
+
async getMessages(conversationId, _options = {}) {
|
|
207
|
+
const tiddlers = await this.listByPrefix(`${PREFIX}/e/${conversationId}/`);
|
|
208
|
+
const messages = tiddlers.map((tiddler) => this.parsePayload(tiddler));
|
|
209
|
+
messages.sort((a, b) => (a.lamportClock ?? 0) - (b.lamportClock ?? 0));
|
|
210
|
+
return messages;
|
|
211
|
+
}
|
|
212
|
+
async appendMessage(message) {
|
|
213
|
+
await this.writeTiddler(this.eventTitle(message.conversationId, message.messageId), () => ({
|
|
214
|
+
title: this.eventTitle(message.conversationId, message.messageId),
|
|
215
|
+
text: JSON.stringify(message)
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
async insertMessagesIfAbsent(messages) {
|
|
219
|
+
for (const message of messages) {
|
|
220
|
+
const title = this.eventTitle(message.conversationId, message.messageId);
|
|
221
|
+
const existing = await this.readTiddler(title);
|
|
222
|
+
if (!existing) {
|
|
223
|
+
await this.writeTiddler(title, () => ({ title, text: JSON.stringify(message) }));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async getMaxLamportClockForConversation(conversationId) {
|
|
228
|
+
const messages = await this.getMessages(conversationId);
|
|
229
|
+
return messages.reduce((max, message) => Math.max(max, message.lamportClock ?? 0), 0);
|
|
230
|
+
}
|
|
231
|
+
async upsertConversationMetadata(meta) {
|
|
232
|
+
const title = this.metaTitle(meta.conversationId);
|
|
233
|
+
await this.writeTiddler(title, () => ({ title, text: JSON.stringify(meta) }));
|
|
234
|
+
}
|
|
235
|
+
async getConversationMeta(conversationId) {
|
|
236
|
+
const result = await this.readTiddler(this.metaTitle(conversationId));
|
|
237
|
+
return result ? this.parsePayload(result.tiddler) : null;
|
|
238
|
+
}
|
|
239
|
+
async saveAttachment(reference, data) {
|
|
240
|
+
if (data.byteLength > this.maxInlineBlobBytes) {
|
|
241
|
+
throw new OrchestrationError({
|
|
242
|
+
code: "INVALID",
|
|
243
|
+
message: `blob of ${data.byteLength} bytes exceeds the inline limit ${this.maxInlineBlobBytes}; store it in an external BlobStore and keep the reference`,
|
|
244
|
+
retryable: false,
|
|
245
|
+
details: { maxInlineBlobBytes: this.maxInlineBlobBytes }
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const title = this.blobTitle(reference.contentHash);
|
|
249
|
+
await this.writeTiddler(title, () => ({
|
|
250
|
+
title,
|
|
251
|
+
text: JSON.stringify({ reference, dataBase64: bytesToBase64(data) })
|
|
252
|
+
}));
|
|
253
|
+
}
|
|
254
|
+
async getAttachment(contentHash) {
|
|
255
|
+
const result = await this.readTiddler(this.blobTitle(contentHash));
|
|
256
|
+
if (!result) return null;
|
|
257
|
+
return this.parsePayload(result.tiddler).reference;
|
|
258
|
+
}
|
|
259
|
+
async readAttachmentData(contentHash) {
|
|
260
|
+
const result = await this.readTiddler(this.blobTitle(contentHash));
|
|
261
|
+
if (!result) return null;
|
|
262
|
+
return base64ToBytes(this.parsePayload(result.tiddler).dataBase64);
|
|
263
|
+
}
|
|
264
|
+
async getAgentDefinition(id) {
|
|
265
|
+
const result = await this.readTiddler(this.definitionTitle(id));
|
|
266
|
+
return result ? this.parsePayload(result.tiddler) : null;
|
|
267
|
+
}
|
|
268
|
+
async saveAgentDefinition(definition) {
|
|
269
|
+
const title = this.definitionTitle(definition.id);
|
|
270
|
+
await this.writeTiddler(title, () => ({ title, text: JSON.stringify(definition) }));
|
|
271
|
+
}
|
|
272
|
+
async saveAgentInstance(meta) {
|
|
273
|
+
const title = this.instanceTitle(meta.instanceId);
|
|
274
|
+
await this.writeTiddler(title, () => ({ title, text: JSON.stringify(meta) }));
|
|
275
|
+
}
|
|
276
|
+
async getImBinding(channelId, imUserId) {
|
|
277
|
+
const result = await this.readTiddler(this.imTitle(channelId, imUserId));
|
|
278
|
+
return result ? this.parsePayload(result.tiddler) : null;
|
|
279
|
+
}
|
|
280
|
+
async setImBinding(record) {
|
|
281
|
+
const title = this.imTitle(record.channelId, record.imUserId);
|
|
282
|
+
await this.writeTiddler(title, () => ({ title, text: JSON.stringify(record) }));
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
// src/agent/categories.ts
|
|
287
|
+
var CATEGORY_CONFIGS = {
|
|
288
|
+
"visual-engineering": {
|
|
289
|
+
model: "default",
|
|
290
|
+
temperature: 0.3,
|
|
291
|
+
description: "UI/UX visual engineering tasks requiring precise rendering and layout"
|
|
292
|
+
},
|
|
293
|
+
ultrabrain: {
|
|
294
|
+
model: "default",
|
|
295
|
+
temperature: 0.1,
|
|
296
|
+
description: "Deep logical reasoning, architecture decisions, and complex problem-solving"
|
|
297
|
+
},
|
|
298
|
+
artistry: {
|
|
299
|
+
model: "default",
|
|
300
|
+
temperature: 0.8,
|
|
301
|
+
description: "Creative writing, design, and artistic generation tasks"
|
|
302
|
+
},
|
|
303
|
+
quick: {
|
|
304
|
+
model: "default",
|
|
305
|
+
temperature: 0.2,
|
|
306
|
+
description: "Fast, straightforward tasks with minimal deliberation needed"
|
|
307
|
+
},
|
|
308
|
+
"unspecified-low": {
|
|
309
|
+
model: "default",
|
|
310
|
+
temperature: 0.5,
|
|
311
|
+
description: "Unclassified tasks of moderate complexity and effort"
|
|
312
|
+
},
|
|
313
|
+
"unspecified-high": {
|
|
314
|
+
model: "default",
|
|
315
|
+
temperature: 0.4,
|
|
316
|
+
description: "Unclassified tasks requiring substantial effort across multiple systems"
|
|
317
|
+
},
|
|
318
|
+
writing: {
|
|
319
|
+
model: "default",
|
|
320
|
+
temperature: 0.7,
|
|
321
|
+
description: "Documentation, prose, technical writing, and content generation"
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
function getCategoryConfig(category) {
|
|
325
|
+
const config = CATEGORY_CONFIGS[category];
|
|
326
|
+
if (!config) {
|
|
327
|
+
throw new Error(`Unknown task category: ${category}`);
|
|
328
|
+
}
|
|
329
|
+
return { ...config };
|
|
330
|
+
}
|
|
331
|
+
function isTaskCategory(value) {
|
|
332
|
+
return value in CATEGORY_CONFIGS;
|
|
333
|
+
}
|
|
334
|
+
var ALL_CATEGORIES = Object.keys(CATEGORY_CONFIGS);
|
|
335
|
+
function resolveCategory(category) {
|
|
336
|
+
if (isTaskCategory(category)) {
|
|
337
|
+
return getCategoryConfig(category);
|
|
338
|
+
}
|
|
339
|
+
return getCategoryConfig("unspecified-low");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// src/agent-management/AgentSessionController.ts
|
|
343
|
+
var AgentSessionController = class {
|
|
344
|
+
options;
|
|
345
|
+
listener = null;
|
|
346
|
+
snapshot = {
|
|
347
|
+
agent: null,
|
|
348
|
+
loading: false,
|
|
349
|
+
error: null,
|
|
350
|
+
messages: [],
|
|
351
|
+
orderedMessageIds: [],
|
|
352
|
+
streamingMessageIds: /* @__PURE__ */ new Set()
|
|
353
|
+
};
|
|
354
|
+
unsubAgentUpdates = null;
|
|
355
|
+
unsubMessages = null;
|
|
356
|
+
pollingTimer = null;
|
|
357
|
+
agentId = null;
|
|
358
|
+
constructor(options) {
|
|
359
|
+
this.options = {
|
|
360
|
+
pollInterval: 500,
|
|
361
|
+
...options
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
// ── Lifecycle ─────────────────────────────────────────────────
|
|
365
|
+
/**
|
|
366
|
+
* Start a session for the given agent ID.
|
|
367
|
+
* Fetches the agent, subscribes to live updates, and loads messages.
|
|
368
|
+
*/
|
|
369
|
+
async start(agentId) {
|
|
370
|
+
this.agentId = agentId;
|
|
371
|
+
this.emitPartial({ loading: true, error: null });
|
|
372
|
+
try {
|
|
373
|
+
const [agent, rawMessages] = await Promise.all([
|
|
374
|
+
this.options.agentInstanceClient.fetchAgent(agentId),
|
|
375
|
+
this.options.conversationClient.getMessages(agentId)
|
|
376
|
+
]);
|
|
377
|
+
const orderedMessageIds = rawMessages.map((m) => m.messageId);
|
|
378
|
+
const messagesMap = /* @__PURE__ */ new Map();
|
|
379
|
+
for (const m of rawMessages) messagesMap.set(m.messageId, m);
|
|
380
|
+
this.emitPartial({
|
|
381
|
+
agent,
|
|
382
|
+
loading: false,
|
|
383
|
+
messages: rawMessages,
|
|
384
|
+
orderedMessageIds,
|
|
385
|
+
streamingMessageIds: /* @__PURE__ */ new Set()
|
|
386
|
+
});
|
|
387
|
+
this.unsubAgentUpdates = this.options.agentInstanceClient.subscribeToUpdates(
|
|
388
|
+
agentId,
|
|
389
|
+
this.handleAgentUpdate
|
|
390
|
+
);
|
|
391
|
+
this.unsubMessages = this.options.conversationClient.subscribeToMessages(
|
|
392
|
+
agentId,
|
|
393
|
+
this.handleNewMessage
|
|
394
|
+
);
|
|
395
|
+
this.startPolling(agentId);
|
|
396
|
+
} catch (error_) {
|
|
397
|
+
this.emitPartial({
|
|
398
|
+
loading: false,
|
|
399
|
+
error: error_ instanceof Error ? error_ : new Error(String(error_))
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
/** Stop the session and clean up subscriptions. */
|
|
404
|
+
stop() {
|
|
405
|
+
this.stopPolling();
|
|
406
|
+
this.unsubAgentUpdates?.();
|
|
407
|
+
this.unsubAgentUpdates = null;
|
|
408
|
+
this.unsubMessages?.();
|
|
409
|
+
this.unsubMessages = null;
|
|
410
|
+
this.agentId = null;
|
|
411
|
+
}
|
|
412
|
+
// ── Actions ───────────────────────────────────────────────────
|
|
413
|
+
/** Send a user message. */
|
|
414
|
+
async sendMessage(content, file, wikiTiddlers) {
|
|
415
|
+
if (!this.agentId) return;
|
|
416
|
+
this.emitPartial({ error: null });
|
|
417
|
+
try {
|
|
418
|
+
await this.options.conversationClient.sendMessage(this.agentId, content, file, wikiTiddlers);
|
|
419
|
+
} catch (error_) {
|
|
420
|
+
this.emitPartial({
|
|
421
|
+
error: error_ instanceof Error ? error_ : new Error(String(error_))
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
/** Cancel the current agent operation. */
|
|
426
|
+
async cancel() {
|
|
427
|
+
if (!this.agentId) return;
|
|
428
|
+
try {
|
|
429
|
+
await this.options.agentInstanceClient.cancelAgent(this.agentId);
|
|
430
|
+
} catch (error_) {
|
|
431
|
+
this.emitPartial({
|
|
432
|
+
error: error_ instanceof Error ? error_ : new Error(String(error_))
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/** Delete a turn starting at the given user message ID. */
|
|
437
|
+
async deleteTurn(userMessageId) {
|
|
438
|
+
return this.options.conversationClient.deleteTurn(userMessageId);
|
|
439
|
+
}
|
|
440
|
+
/** Retry a turn starting at the given user message ID. */
|
|
441
|
+
async retryTurn(userMessageId) {
|
|
442
|
+
return this.options.conversationClient.retryTurn(userMessageId);
|
|
443
|
+
}
|
|
444
|
+
// ── Subscription ──────────────────────────────────────────────
|
|
445
|
+
/** Subscribe to snapshot changes. Returns unsubscribe function. */
|
|
446
|
+
subscribe(listener) {
|
|
447
|
+
this.listener = listener;
|
|
448
|
+
listener({ ...this.snapshot, streamingMessageIds: new Set(this.snapshot.streamingMessageIds) });
|
|
449
|
+
return () => {
|
|
450
|
+
if (this.listener === listener) this.listener = null;
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
/** Get current snapshot without subscribing. */
|
|
454
|
+
getSnapshot() {
|
|
455
|
+
return this.snapshot;
|
|
456
|
+
}
|
|
457
|
+
// ── Private helpers ───────────────────────────────────────────
|
|
458
|
+
emitPartial(partial) {
|
|
459
|
+
this.snapshot = { ...this.snapshot, ...partial };
|
|
460
|
+
if (this.listener) {
|
|
461
|
+
this.listener({
|
|
462
|
+
...this.snapshot,
|
|
463
|
+
streamingMessageIds: new Set(this.snapshot.streamingMessageIds)
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
handleAgentUpdate = (update) => {
|
|
468
|
+
if (this.snapshot.agent) {
|
|
469
|
+
this.emitPartial({ agent: { ...this.snapshot.agent, ...update } });
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
handleNewMessage = (message) => {
|
|
473
|
+
const messages = [...this.snapshot.messages.filter((m) => m.messageId !== message.messageId), message];
|
|
474
|
+
const orderedMessageIds = [.../* @__PURE__ */ new Set([...this.snapshot.orderedMessageIds, message.messageId])];
|
|
475
|
+
this.emitPartial({ messages, orderedMessageIds });
|
|
476
|
+
};
|
|
477
|
+
startPolling(agentId) {
|
|
478
|
+
this.stopPolling();
|
|
479
|
+
this.pollingTimer = setInterval(async () => {
|
|
480
|
+
try {
|
|
481
|
+
const agent = await this.options.agentInstanceClient.fetchAgent(agentId);
|
|
482
|
+
this.emitPartial({ agent });
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
}, this.options.pollInterval);
|
|
486
|
+
}
|
|
487
|
+
stopPolling() {
|
|
488
|
+
if (this.pollingTimer !== null) {
|
|
489
|
+
clearInterval(this.pollingTimer);
|
|
490
|
+
this.pollingTimer = null;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
// src/agent-management/AgentDefinitionEditorController.ts
|
|
496
|
+
var AgentDefinitionEditorController = class {
|
|
497
|
+
options;
|
|
498
|
+
listener = null;
|
|
499
|
+
state = {
|
|
500
|
+
agentDefinition: null,
|
|
501
|
+
agentName: "",
|
|
502
|
+
previewAgentId: null,
|
|
503
|
+
isLoading: false,
|
|
504
|
+
isSaving: false,
|
|
505
|
+
promptSchema: null
|
|
506
|
+
};
|
|
507
|
+
autosaveTimer = null;
|
|
508
|
+
constructor(options) {
|
|
509
|
+
this.options = {
|
|
510
|
+
autosaveDebounceMs: 1e3,
|
|
511
|
+
...options
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
// ── Lifecycle ─────────────────────────────────────────────────
|
|
515
|
+
/** Load an agent definition and its prompt schema. */
|
|
516
|
+
async loadDefinition(definitionId) {
|
|
517
|
+
this.emit({ isLoading: true });
|
|
518
|
+
try {
|
|
519
|
+
const [definition, previewAgentId] = await Promise.all([
|
|
520
|
+
this.options.definitionRepository.getAgentDef(definitionId),
|
|
521
|
+
this.findOrCreatePreviewAgent(definitionId)
|
|
522
|
+
]);
|
|
523
|
+
if (!definition) {
|
|
524
|
+
this.emit({ isLoading: false });
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
let promptSchema = null;
|
|
528
|
+
if (definition.agentFrameworkID) {
|
|
529
|
+
try {
|
|
530
|
+
promptSchema = await this.options.agentInstanceClient.getFrameworkConfigSchema(
|
|
531
|
+
definition.agentFrameworkID
|
|
532
|
+
);
|
|
533
|
+
} catch {
|
|
534
|
+
promptSchema = null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
this.state = {
|
|
538
|
+
agentDefinition: definition,
|
|
539
|
+
agentName: definition.name ?? "",
|
|
540
|
+
previewAgentId,
|
|
541
|
+
isLoading: false,
|
|
542
|
+
isSaving: false,
|
|
543
|
+
promptSchema
|
|
544
|
+
};
|
|
545
|
+
this.emit(this.state);
|
|
546
|
+
} catch {
|
|
547
|
+
this.emit({ isLoading: false });
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
/** Update the agent definition field. Triggers debounced autosave. */
|
|
551
|
+
updateDefinition(change) {
|
|
552
|
+
if (!this.state.agentDefinition) return;
|
|
553
|
+
const updated = { ...this.state.agentDefinition, ...change };
|
|
554
|
+
this.state = { ...this.state, agentDefinition: updated, agentName: updated.name ?? "" };
|
|
555
|
+
this.emit({ agentDefinition: updated, agentName: this.state.agentName });
|
|
556
|
+
this.scheduleAutosave(updated);
|
|
557
|
+
}
|
|
558
|
+
/** Force an immediate save to the repository. */
|
|
559
|
+
async saveNow() {
|
|
560
|
+
if (!this.state.agentDefinition) return;
|
|
561
|
+
this.emit({ isSaving: true });
|
|
562
|
+
try {
|
|
563
|
+
await this.options.definitionRepository.updateAgentDef({
|
|
564
|
+
id: this.state.agentDefinition.id,
|
|
565
|
+
name: this.state.agentName,
|
|
566
|
+
description: this.state.agentDefinition.description,
|
|
567
|
+
agentFrameworkConfig: this.state.agentDefinition.agentFrameworkConfig,
|
|
568
|
+
aiApiConfig: this.state.agentDefinition.aiApiConfig,
|
|
569
|
+
agentTools: this.state.agentDefinition.agentTools,
|
|
570
|
+
heartbeat: this.state.agentDefinition.heartbeat
|
|
571
|
+
});
|
|
572
|
+
} catch {
|
|
573
|
+
} finally {
|
|
574
|
+
this.emit({ isSaving: false });
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
/** Reload the prompt schema for a framework ID. */
|
|
578
|
+
async reloadSchema(frameworkId) {
|
|
579
|
+
try {
|
|
580
|
+
const schema = await this.options.agentInstanceClient.getFrameworkConfigSchema(frameworkId);
|
|
581
|
+
this.emit({ promptSchema: schema });
|
|
582
|
+
} catch {
|
|
583
|
+
this.emit({ promptSchema: null });
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
// ── Preview agent lifecycle ───────────────────────────────────
|
|
587
|
+
/** Get or create a preview agent instance tied to this definition. */
|
|
588
|
+
async findOrCreatePreviewAgent(definitionId) {
|
|
589
|
+
try {
|
|
590
|
+
const result = await this.options.agentInstanceClient.createAgent(definitionId, {
|
|
591
|
+
preview: true
|
|
592
|
+
});
|
|
593
|
+
return result.id;
|
|
594
|
+
} catch {
|
|
595
|
+
return null;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
// ── Scheduled tasks ───────────────────────────────────────────
|
|
599
|
+
async loadScheduledTasks() {
|
|
600
|
+
if (!this.state.previewAgentId) return [];
|
|
601
|
+
return this.options.scheduledTaskClient.listScheduledTasksForAgent(
|
|
602
|
+
this.state.previewAgentId
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
async saveScheduledTask(input) {
|
|
606
|
+
return this.options.scheduledTaskClient.createScheduledTask(input);
|
|
607
|
+
}
|
|
608
|
+
async deleteScheduledTask(taskId) {
|
|
609
|
+
return this.options.scheduledTaskClient.deleteScheduledTask(taskId);
|
|
610
|
+
}
|
|
611
|
+
// ── Subscription ──────────────────────────────────────────────
|
|
612
|
+
subscribe(listener) {
|
|
613
|
+
this.listener = listener;
|
|
614
|
+
listener(this.state);
|
|
615
|
+
return () => {
|
|
616
|
+
if (this.listener === listener) this.listener = null;
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
getState() {
|
|
620
|
+
return this.state;
|
|
621
|
+
}
|
|
622
|
+
// ── Private ───────────────────────────────────────────────────
|
|
623
|
+
emit(change) {
|
|
624
|
+
this.listener?.(change);
|
|
625
|
+
}
|
|
626
|
+
scheduleAutosave(definition) {
|
|
627
|
+
if (this.autosaveTimer !== null) clearTimeout(this.autosaveTimer);
|
|
628
|
+
this.autosaveTimer = setTimeout(() => {
|
|
629
|
+
this.options.definitionRepository.updateAgentDef({
|
|
630
|
+
id: definition.id,
|
|
631
|
+
name: definition.name,
|
|
632
|
+
description: definition.description,
|
|
633
|
+
agentFrameworkConfig: definition.agentFrameworkConfig,
|
|
634
|
+
aiApiConfig: definition.aiApiConfig,
|
|
635
|
+
agentTools: definition.agentTools,
|
|
636
|
+
heartbeat: definition.heartbeat
|
|
637
|
+
}).catch(() => {
|
|
638
|
+
});
|
|
639
|
+
}, this.options.autosaveDebounceMs);
|
|
640
|
+
}
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
// src/agent-management/AgentCreationController.ts
|
|
644
|
+
var AgentCreationController = class {
|
|
645
|
+
options;
|
|
646
|
+
listener = null;
|
|
647
|
+
state = {
|
|
648
|
+
currentStep: 0,
|
|
649
|
+
agentName: "",
|
|
650
|
+
selectedTemplate: null,
|
|
651
|
+
temporaryAgentDefinition: null,
|
|
652
|
+
previewAgentId: null,
|
|
653
|
+
isLoading: false,
|
|
654
|
+
promptSchema: null
|
|
655
|
+
};
|
|
656
|
+
constructor(options) {
|
|
657
|
+
this.options = {
|
|
658
|
+
defaultFrameworkId: "memeloopAgentToolLoop",
|
|
659
|
+
...options
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
/** Initialize the creation wizard, optionally from a saved tab state. */
|
|
663
|
+
async start(definitionId, templateDefinitionId) {
|
|
664
|
+
this.emit({ isLoading: true });
|
|
665
|
+
try {
|
|
666
|
+
if (definitionId) {
|
|
667
|
+
const temporaryDefinition = await this.options.definitionRepository.getAgentDef(definitionId);
|
|
668
|
+
if (temporaryDefinition) {
|
|
669
|
+
this.state = {
|
|
670
|
+
...this.state,
|
|
671
|
+
temporaryAgentDefinition: temporaryDefinition,
|
|
672
|
+
agentName: temporaryDefinition.name ?? "",
|
|
673
|
+
isLoading: false
|
|
674
|
+
};
|
|
675
|
+
this.emit(this.state);
|
|
676
|
+
if (templateDefinitionId) {
|
|
677
|
+
const template = await this.options.definitionRepository.getAgentDef(templateDefinitionId);
|
|
678
|
+
if (template) {
|
|
679
|
+
this.state = { ...this.state, selectedTemplate: template };
|
|
680
|
+
this.emit(this.state);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
this.emit({ isLoading: false });
|
|
687
|
+
} catch {
|
|
688
|
+
this.emit({ isLoading: false });
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
/** Select a template for the new agent. */
|
|
692
|
+
selectTemplate(template) {
|
|
693
|
+
this.state = { ...this.state, selectedTemplate: template };
|
|
694
|
+
this.emit(this.state);
|
|
695
|
+
}
|
|
696
|
+
/** Update the agent name. */
|
|
697
|
+
setAgentName(name) {
|
|
698
|
+
this.state = { ...this.state, agentName: name };
|
|
699
|
+
this.emit(this.state);
|
|
700
|
+
}
|
|
701
|
+
/** Advance to the next wizard step. */
|
|
702
|
+
nextStep() {
|
|
703
|
+
this.state = { ...this.state, currentStep: Math.min(this.state.currentStep + 1, 2) };
|
|
704
|
+
this.emit(this.state);
|
|
705
|
+
}
|
|
706
|
+
/** Go back to the previous wizard step. */
|
|
707
|
+
previousStep() {
|
|
708
|
+
this.state = { ...this.state, currentStep: Math.max(this.state.currentStep - 1, 0) };
|
|
709
|
+
this.emit(this.state);
|
|
710
|
+
}
|
|
711
|
+
/** Set the current wizard step directly. */
|
|
712
|
+
setStep(step) {
|
|
713
|
+
this.state = { ...this.state, currentStep: Math.max(0, Math.min(step, 2)) };
|
|
714
|
+
this.emit(this.state);
|
|
715
|
+
}
|
|
716
|
+
/** Update the temporary agent definition. */
|
|
717
|
+
updateTemporaryDefinition(change) {
|
|
718
|
+
const updated = this.state.temporaryAgentDefinition ? { ...this.state.temporaryAgentDefinition, ...change } : null;
|
|
719
|
+
this.state = { ...this.state, temporaryAgentDefinition: updated };
|
|
720
|
+
this.emit(this.state);
|
|
721
|
+
}
|
|
722
|
+
/** Set the prompt schema for the selected framework. */
|
|
723
|
+
setPromptSchema(schema) {
|
|
724
|
+
this.state = { ...this.state, promptSchema: schema };
|
|
725
|
+
this.emit(this.state);
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Create a preview agent instance for the chat-preview step.
|
|
729
|
+
* Should be called when entering step 2 (or the chat preview step).
|
|
730
|
+
*/
|
|
731
|
+
async createPreviewAgent(definitionId) {
|
|
732
|
+
this.emit({ isLoading: true });
|
|
733
|
+
try {
|
|
734
|
+
const result = await this.options.agentInstanceClient.createAgent(definitionId, {
|
|
735
|
+
preview: true
|
|
736
|
+
});
|
|
737
|
+
this.state = { ...this.state, previewAgentId: result.id, isLoading: false };
|
|
738
|
+
this.emit(this.state);
|
|
739
|
+
} catch {
|
|
740
|
+
this.emit({ isLoading: false });
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* Finalize creation: persist the temporary definition and create the actual
|
|
745
|
+
* agent instance. Returns the final agent instance ID, or null on failure.
|
|
746
|
+
*/
|
|
747
|
+
async finalize() {
|
|
748
|
+
if (!this.state.temporaryAgentDefinition) return null;
|
|
749
|
+
try {
|
|
750
|
+
const definition = await this.options.definitionRepository.createAgentDef(
|
|
751
|
+
this.state.temporaryAgentDefinition
|
|
752
|
+
);
|
|
753
|
+
const instance = await this.options.agentInstanceClient.createAgent(definition.id);
|
|
754
|
+
return instance.id;
|
|
755
|
+
} catch {
|
|
756
|
+
return null;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
/** Clean up temporary resources. */
|
|
760
|
+
async cleanup() {
|
|
761
|
+
if (this.state.previewAgentId) {
|
|
762
|
+
try {
|
|
763
|
+
await this.options.agentInstanceClient.deleteAgent(this.state.previewAgentId);
|
|
764
|
+
} catch {
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
// ── Subscription ──────────────────────────────────────────────
|
|
769
|
+
subscribe(listener) {
|
|
770
|
+
this.listener = listener;
|
|
771
|
+
listener({ ...this.state });
|
|
772
|
+
return () => {
|
|
773
|
+
if (this.listener === listener) this.listener = null;
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
getState() {
|
|
777
|
+
return this.state;
|
|
778
|
+
}
|
|
779
|
+
// ── Private ───────────────────────────────────────────────────
|
|
780
|
+
emit(change) {
|
|
781
|
+
this.state = { ...this.state, ...change };
|
|
782
|
+
this.listener?.({ ...this.state });
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
|
|
786
|
+
// src/agent-management/PromptPreviewController.ts
|
|
787
|
+
var PromptPreviewController = class {
|
|
788
|
+
options;
|
|
789
|
+
listener = null;
|
|
790
|
+
state = {
|
|
791
|
+
open: false,
|
|
792
|
+
baseMode: "preview",
|
|
793
|
+
activeTab: "tree",
|
|
794
|
+
loading: false,
|
|
795
|
+
progress: 0,
|
|
796
|
+
currentStep: "",
|
|
797
|
+
currentPlugin: null,
|
|
798
|
+
result: null,
|
|
799
|
+
lastUpdated: null,
|
|
800
|
+
formFieldsToScrollTo: []
|
|
801
|
+
};
|
|
802
|
+
constructor(options) {
|
|
803
|
+
this.options = options;
|
|
804
|
+
}
|
|
805
|
+
/** Open the dialog with an optional base mode. */
|
|
806
|
+
open(baseMode) {
|
|
807
|
+
this.state = {
|
|
808
|
+
...this.state,
|
|
809
|
+
open: true,
|
|
810
|
+
baseMode: baseMode ?? "preview",
|
|
811
|
+
loading: false,
|
|
812
|
+
progress: 0,
|
|
813
|
+
currentStep: "Starting...",
|
|
814
|
+
currentPlugin: null,
|
|
815
|
+
result: null,
|
|
816
|
+
lastUpdated: null,
|
|
817
|
+
formFieldsToScrollTo: []
|
|
818
|
+
};
|
|
819
|
+
this.emit();
|
|
820
|
+
}
|
|
821
|
+
/** Close the dialog. */
|
|
822
|
+
close() {
|
|
823
|
+
this.state = {
|
|
824
|
+
...this.state,
|
|
825
|
+
open: false,
|
|
826
|
+
baseMode: "preview",
|
|
827
|
+
lastUpdated: null,
|
|
828
|
+
formFieldsToScrollTo: []
|
|
829
|
+
};
|
|
830
|
+
this.emit();
|
|
831
|
+
}
|
|
832
|
+
/** Set the active tab in the dialog. */
|
|
833
|
+
setActiveTab(tab) {
|
|
834
|
+
this.state = { ...this.state, activeTab: tab };
|
|
835
|
+
this.emit();
|
|
836
|
+
}
|
|
837
|
+
/** Set form fields to scroll to (for edit mode navigation). */
|
|
838
|
+
setFormFieldsToScrollTo(fieldPaths) {
|
|
839
|
+
this.state = { ...this.state, formFieldsToScrollTo: fieldPaths };
|
|
840
|
+
this.emit();
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Generate a preview of the prompt tree.
|
|
844
|
+
* @param agentFrameworkConfig The agent's framework configuration
|
|
845
|
+
* @param messages Current conversation messages
|
|
846
|
+
* @param inputText Optional input text to include in the preview
|
|
847
|
+
*/
|
|
848
|
+
async generate(agentFrameworkConfig, messages, inputText) {
|
|
849
|
+
this.state = {
|
|
850
|
+
...this.state,
|
|
851
|
+
loading: true,
|
|
852
|
+
progress: 0,
|
|
853
|
+
currentStep: "Preparing..."
|
|
854
|
+
};
|
|
855
|
+
this.emit();
|
|
856
|
+
try {
|
|
857
|
+
const result = await this.options.previewClient.generatePreview(
|
|
858
|
+
agentFrameworkConfig,
|
|
859
|
+
messages,
|
|
860
|
+
inputText,
|
|
861
|
+
(progress) => {
|
|
862
|
+
this.state = {
|
|
863
|
+
...this.state,
|
|
864
|
+
progress: progress.progress,
|
|
865
|
+
currentStep: progress.step,
|
|
866
|
+
currentPlugin: progress.currentPlugin ?? null
|
|
867
|
+
};
|
|
868
|
+
this.emit();
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
this.state = {
|
|
872
|
+
...this.state,
|
|
873
|
+
loading: false,
|
|
874
|
+
progress: 1,
|
|
875
|
+
currentStep: "Complete",
|
|
876
|
+
currentPlugin: null,
|
|
877
|
+
result,
|
|
878
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
879
|
+
};
|
|
880
|
+
this.emit();
|
|
881
|
+
return result;
|
|
882
|
+
} catch {
|
|
883
|
+
this.state = {
|
|
884
|
+
...this.state,
|
|
885
|
+
loading: false,
|
|
886
|
+
progress: 0,
|
|
887
|
+
currentStep: "Error occurred",
|
|
888
|
+
currentPlugin: null,
|
|
889
|
+
result: null
|
|
890
|
+
};
|
|
891
|
+
this.emit();
|
|
892
|
+
return null;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
// ── Subscription ──────────────────────────────────────────────
|
|
896
|
+
subscribe(listener) {
|
|
897
|
+
this.listener = listener;
|
|
898
|
+
listener({ ...this.state });
|
|
899
|
+
return () => {
|
|
900
|
+
if (this.listener === listener) this.listener = null;
|
|
901
|
+
};
|
|
902
|
+
}
|
|
903
|
+
getState() {
|
|
904
|
+
return this.state;
|
|
905
|
+
}
|
|
906
|
+
// ── Private ───────────────────────────────────────────────────
|
|
907
|
+
emit() {
|
|
908
|
+
this.listener?.({ ...this.state });
|
|
909
|
+
}
|
|
910
|
+
};
|
|
911
|
+
|
|
912
|
+
// src/orchestration/remoteClient.ts
|
|
913
|
+
var REMOTE_ORCHESTRATION_PROTOCOL = "memeloop.resource.v1";
|
|
914
|
+
var REMOTE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
915
|
+
"capabilities",
|
|
916
|
+
"apply",
|
|
917
|
+
"get",
|
|
918
|
+
"list",
|
|
919
|
+
"watch",
|
|
920
|
+
"delete"
|
|
921
|
+
]);
|
|
922
|
+
function isRecord(value) {
|
|
923
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
924
|
+
}
|
|
925
|
+
function errorData(error) {
|
|
926
|
+
if (error instanceof OrchestrationError) {
|
|
927
|
+
return {
|
|
928
|
+
code: error.code,
|
|
929
|
+
message: error.message,
|
|
930
|
+
retryable: error.retryable,
|
|
931
|
+
...error.retryAfterMs !== void 0 ? { retryAfterMs: error.retryAfterMs } : {},
|
|
932
|
+
...error.reason !== void 0 ? { reason: error.reason } : {},
|
|
933
|
+
...error.details !== void 0 ? { details: error.details } : {}
|
|
934
|
+
};
|
|
935
|
+
}
|
|
936
|
+
return {
|
|
937
|
+
code: "INTERNAL",
|
|
938
|
+
message: error instanceof Error ? error.message : String(error),
|
|
939
|
+
retryable: false
|
|
940
|
+
};
|
|
941
|
+
}
|
|
942
|
+
function throwResponseError(response) {
|
|
943
|
+
throw new OrchestrationError(response.error);
|
|
944
|
+
}
|
|
945
|
+
function assertResponse(request, response) {
|
|
946
|
+
if (!isRecord(response) || response.protocol !== REMOTE_ORCHESTRATION_PROTOCOL || response.requestId !== request.requestId || typeof response.ok !== "boolean" || response.ok && !("result" in response) || !response.ok && (!isRecord(response.error) || typeof response.error.code !== "string" || typeof response.error.message !== "string" || typeof response.error.retryable !== "boolean")) {
|
|
947
|
+
throw new OrchestrationError({
|
|
948
|
+
code: "INVALID",
|
|
949
|
+
message: "remote orchestration response correlation or protocol mismatch",
|
|
950
|
+
retryable: false
|
|
951
|
+
});
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
var requestSequence = 0;
|
|
955
|
+
function createRemoteOrchestrationClient(transport, options = {}) {
|
|
956
|
+
const createRequestId = options.createRequestId ?? (() => `resource-${Date.now().toString(36)}-${(++requestSequence).toString(36)}`);
|
|
957
|
+
function makeRequest(operation, payload) {
|
|
958
|
+
return {
|
|
959
|
+
protocol: REMOTE_ORCHESTRATION_PROTOCOL,
|
|
960
|
+
requestId: createRequestId(),
|
|
961
|
+
operation,
|
|
962
|
+
payload
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
async function request(operation, payload, signal) {
|
|
966
|
+
const envelope = makeRequest(operation, payload);
|
|
967
|
+
const response = await transport.request(envelope, { signal });
|
|
968
|
+
assertResponse(envelope, response);
|
|
969
|
+
if (!response.ok) throwResponseError(response);
|
|
970
|
+
return response.result;
|
|
971
|
+
}
|
|
972
|
+
return {
|
|
973
|
+
getCapabilities() {
|
|
974
|
+
return request("capabilities", {});
|
|
975
|
+
},
|
|
976
|
+
apply(resource, applyOptions) {
|
|
977
|
+
return request("apply", {
|
|
978
|
+
resource,
|
|
979
|
+
...applyOptions ? { options: applyOptions } : {}
|
|
980
|
+
});
|
|
981
|
+
},
|
|
982
|
+
get(reference, getOptions) {
|
|
983
|
+
return request("get", {
|
|
984
|
+
reference,
|
|
985
|
+
...getOptions ? { options: getOptions } : {}
|
|
986
|
+
});
|
|
987
|
+
},
|
|
988
|
+
list(query, listOptions) {
|
|
989
|
+
return request("list", {
|
|
990
|
+
query,
|
|
991
|
+
...listOptions ? { options: listOptions } : {}
|
|
992
|
+
});
|
|
993
|
+
},
|
|
994
|
+
async *watch(query, watchOptions) {
|
|
995
|
+
const envelope = makeRequest("watch", {
|
|
996
|
+
query,
|
|
997
|
+
...watchOptions ? {
|
|
998
|
+
options: {
|
|
999
|
+
...watchOptions,
|
|
1000
|
+
signal: void 0
|
|
1001
|
+
}
|
|
1002
|
+
} : {}
|
|
1003
|
+
});
|
|
1004
|
+
for await (const response of transport.watch(envelope, {
|
|
1005
|
+
signal: watchOptions?.signal
|
|
1006
|
+
})) {
|
|
1007
|
+
assertResponse(envelope, response);
|
|
1008
|
+
if (!response.ok) throwResponseError(response);
|
|
1009
|
+
yield response.result;
|
|
1010
|
+
}
|
|
1011
|
+
},
|
|
1012
|
+
delete(reference, deleteOptions) {
|
|
1013
|
+
return request("delete", {
|
|
1014
|
+
reference,
|
|
1015
|
+
...deleteOptions ? { options: deleteOptions } : {}
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
function createReadOnlyOrchestrationClient(client, options = {}) {
|
|
1021
|
+
const allowedKinds = options.allowedResourceKinds ? new Set(options.allowedResourceKinds) : void 0;
|
|
1022
|
+
function assertAllowedKind(kind) {
|
|
1023
|
+
if (!allowedKinds || allowedKinds.has(kind)) return;
|
|
1024
|
+
throw new OrchestrationError({
|
|
1025
|
+
code: "FORBIDDEN",
|
|
1026
|
+
message: `remote orchestration access to resource kind '${kind}' is forbidden`,
|
|
1027
|
+
retryable: false
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
function forbidden(operation) {
|
|
1031
|
+
throw new OrchestrationError({
|
|
1032
|
+
code: "FORBIDDEN",
|
|
1033
|
+
message: `remote orchestration operation '${operation}' is read-only`,
|
|
1034
|
+
retryable: false
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
return {
|
|
1038
|
+
async getCapabilities() {
|
|
1039
|
+
const capabilities = await client.getCapabilities();
|
|
1040
|
+
return {
|
|
1041
|
+
operations: ["get", "list", "watch"],
|
|
1042
|
+
resourceKinds: capabilities.resourceKinds.filter((kind) => allowedKinds ? allowedKinds.has(kind) : true),
|
|
1043
|
+
interfaces: capabilities.interfaces.includes("resource") ? ["resource"] : []
|
|
1044
|
+
};
|
|
1045
|
+
},
|
|
1046
|
+
async apply() {
|
|
1047
|
+
forbidden("apply");
|
|
1048
|
+
},
|
|
1049
|
+
async get(reference, getOptions) {
|
|
1050
|
+
assertAllowedKind(reference.kind);
|
|
1051
|
+
return await client.get(reference, getOptions);
|
|
1052
|
+
},
|
|
1053
|
+
async list(query, listOptions) {
|
|
1054
|
+
assertAllowedKind(query.kind);
|
|
1055
|
+
return await client.list(query, listOptions);
|
|
1056
|
+
},
|
|
1057
|
+
async *watch(query, watchOptions) {
|
|
1058
|
+
assertAllowedKind(query.kind);
|
|
1059
|
+
yield* client.watch(query, watchOptions);
|
|
1060
|
+
},
|
|
1061
|
+
async delete() {
|
|
1062
|
+
forbidden("delete");
|
|
1063
|
+
}
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
1066
|
+
function createNamespacedOrchestrationClient(client, options) {
|
|
1067
|
+
const namespace = options.namespace.trim();
|
|
1068
|
+
if (!namespace || namespace.length > 253) {
|
|
1069
|
+
throw new TypeError("namespace must contain between 1 and 253 characters");
|
|
1070
|
+
}
|
|
1071
|
+
const allowedKinds = new Set(options.allowedResourceKinds);
|
|
1072
|
+
const mutableKinds = new Set(options.mutableResourceKinds ?? options.allowedResourceKinds);
|
|
1073
|
+
for (const kind of mutableKinds) {
|
|
1074
|
+
if (!allowedKinds.has(kind)) {
|
|
1075
|
+
throw new TypeError(`mutable resource kind '${kind}' must also be allowed`);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function assertAllowedKind(kind) {
|
|
1079
|
+
if (allowedKinds.has(kind)) return;
|
|
1080
|
+
throw new OrchestrationError({
|
|
1081
|
+
code: "FORBIDDEN",
|
|
1082
|
+
message: `remote orchestration access to resource kind '${kind}' is forbidden`,
|
|
1083
|
+
retryable: false
|
|
1084
|
+
});
|
|
1085
|
+
}
|
|
1086
|
+
function bindNamespace(metadata) {
|
|
1087
|
+
if (metadata.namespace !== void 0 && metadata.namespace !== namespace) {
|
|
1088
|
+
throw new OrchestrationError({
|
|
1089
|
+
code: "FORBIDDEN",
|
|
1090
|
+
message: `remote orchestration access outside namespace '${namespace}' is forbidden`,
|
|
1091
|
+
retryable: false
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
return { ...metadata, namespace };
|
|
1095
|
+
}
|
|
1096
|
+
function assertMutableKind(kind) {
|
|
1097
|
+
assertAllowedKind(kind);
|
|
1098
|
+
if (mutableKinds.has(kind)) return;
|
|
1099
|
+
throw new OrchestrationError({
|
|
1100
|
+
code: "FORBIDDEN",
|
|
1101
|
+
message: `remote orchestration mutation of resource kind '${kind}' is forbidden`,
|
|
1102
|
+
retryable: false
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
return {
|
|
1106
|
+
async getCapabilities() {
|
|
1107
|
+
const capabilities = await client.getCapabilities();
|
|
1108
|
+
const resourceKinds = capabilities.resourceKinds.filter((kind) => allowedKinds.has(kind));
|
|
1109
|
+
const resourceOperations = Object.fromEntries(
|
|
1110
|
+
resourceKinds.map((kind) => {
|
|
1111
|
+
const sourceOperations = capabilities.resourceOperations?.[kind] ?? capabilities.operations;
|
|
1112
|
+
return [
|
|
1113
|
+
kind,
|
|
1114
|
+
sourceOperations.filter((operation) => mutableKinds.has(kind) || operation !== "apply" && operation !== "delete")
|
|
1115
|
+
];
|
|
1116
|
+
})
|
|
1117
|
+
);
|
|
1118
|
+
return {
|
|
1119
|
+
operations: capabilities.operations,
|
|
1120
|
+
resourceKinds,
|
|
1121
|
+
resourceOperations,
|
|
1122
|
+
interfaces: capabilities.interfaces.includes("resource") ? ["resource"] : []
|
|
1123
|
+
};
|
|
1124
|
+
},
|
|
1125
|
+
async apply(resource, applyOptions) {
|
|
1126
|
+
assertMutableKind(resource.kind);
|
|
1127
|
+
return await client.apply(
|
|
1128
|
+
{
|
|
1129
|
+
...resource,
|
|
1130
|
+
metadata: bindNamespace(resource.metadata)
|
|
1131
|
+
},
|
|
1132
|
+
applyOptions
|
|
1133
|
+
);
|
|
1134
|
+
},
|
|
1135
|
+
async get(reference, getOptions) {
|
|
1136
|
+
assertAllowedKind(reference.kind);
|
|
1137
|
+
return await client.get(bindNamespace(reference), getOptions);
|
|
1138
|
+
},
|
|
1139
|
+
async list(query, listOptions) {
|
|
1140
|
+
assertAllowedKind(query.kind);
|
|
1141
|
+
return await client.list(bindNamespace(query), listOptions);
|
|
1142
|
+
},
|
|
1143
|
+
watch(query, watchOptions) {
|
|
1144
|
+
assertAllowedKind(query.kind);
|
|
1145
|
+
return client.watch(bindNamespace(query), watchOptions);
|
|
1146
|
+
},
|
|
1147
|
+
async delete(reference, deleteOptions) {
|
|
1148
|
+
assertMutableKind(reference.kind);
|
|
1149
|
+
return await client.delete(bindNamespace(reference), deleteOptions);
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function requirePayload(payload, key) {
|
|
1154
|
+
if (!(key in payload)) {
|
|
1155
|
+
throw new OrchestrationError({
|
|
1156
|
+
code: "INVALID",
|
|
1157
|
+
message: `remote orchestration request is missing payload.${key}`,
|
|
1158
|
+
retryable: false
|
|
1159
|
+
});
|
|
1160
|
+
}
|
|
1161
|
+
return payload[key];
|
|
1162
|
+
}
|
|
1163
|
+
function success(request, result) {
|
|
1164
|
+
return {
|
|
1165
|
+
protocol: REMOTE_ORCHESTRATION_PROTOCOL,
|
|
1166
|
+
requestId: request.requestId,
|
|
1167
|
+
ok: true,
|
|
1168
|
+
result
|
|
1169
|
+
};
|
|
1170
|
+
}
|
|
1171
|
+
function failure(request, error) {
|
|
1172
|
+
const requestRecord = isRecord(request) ? request : void 0;
|
|
1173
|
+
return {
|
|
1174
|
+
protocol: REMOTE_ORCHESTRATION_PROTOCOL,
|
|
1175
|
+
requestId: typeof requestRecord?.requestId === "string" ? requestRecord.requestId : "invalid",
|
|
1176
|
+
ok: false,
|
|
1177
|
+
error: errorData(error)
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
function createRemoteOrchestrationHandler(client) {
|
|
1181
|
+
function validate(request) {
|
|
1182
|
+
if (!isRecord(request) || request.protocol !== REMOTE_ORCHESTRATION_PROTOCOL || typeof request.requestId !== "string" || !request.requestId || request.requestId.length > 256 || !REMOTE_OPERATIONS.has(request.operation) || !isRecord(request.payload)) {
|
|
1183
|
+
throw new OrchestrationError({
|
|
1184
|
+
code: "INVALID",
|
|
1185
|
+
message: "invalid remote orchestration request envelope",
|
|
1186
|
+
retryable: false
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
return {
|
|
1191
|
+
async request(request) {
|
|
1192
|
+
try {
|
|
1193
|
+
validate(request);
|
|
1194
|
+
const payload = request.payload;
|
|
1195
|
+
switch (request.operation) {
|
|
1196
|
+
case "capabilities":
|
|
1197
|
+
return success(request, await client.getCapabilities());
|
|
1198
|
+
case "apply":
|
|
1199
|
+
return success(
|
|
1200
|
+
request,
|
|
1201
|
+
await client.apply(
|
|
1202
|
+
requirePayload(payload, "resource"),
|
|
1203
|
+
payload.options
|
|
1204
|
+
)
|
|
1205
|
+
);
|
|
1206
|
+
case "get":
|
|
1207
|
+
return success(
|
|
1208
|
+
request,
|
|
1209
|
+
await client.get(
|
|
1210
|
+
requirePayload(payload, "reference"),
|
|
1211
|
+
payload.options
|
|
1212
|
+
)
|
|
1213
|
+
);
|
|
1214
|
+
case "list":
|
|
1215
|
+
return success(
|
|
1216
|
+
request,
|
|
1217
|
+
await client.list(
|
|
1218
|
+
requirePayload(payload, "query"),
|
|
1219
|
+
payload.options
|
|
1220
|
+
)
|
|
1221
|
+
);
|
|
1222
|
+
case "delete":
|
|
1223
|
+
return success(
|
|
1224
|
+
request,
|
|
1225
|
+
await client.delete(
|
|
1226
|
+
requirePayload(payload, "reference"),
|
|
1227
|
+
payload.options
|
|
1228
|
+
)
|
|
1229
|
+
);
|
|
1230
|
+
case "watch":
|
|
1231
|
+
throw new OrchestrationError({
|
|
1232
|
+
code: "INVALID",
|
|
1233
|
+
message: "watch requests require the streaming protocol method",
|
|
1234
|
+
retryable: false
|
|
1235
|
+
});
|
|
1236
|
+
default:
|
|
1237
|
+
throw new OrchestrationError({
|
|
1238
|
+
code: "UNSUPPORTED",
|
|
1239
|
+
message: `unsupported remote orchestration operation '${String(request.operation)}'`,
|
|
1240
|
+
retryable: false
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
} catch (error) {
|
|
1244
|
+
return failure(request, error);
|
|
1245
|
+
}
|
|
1246
|
+
},
|
|
1247
|
+
async *watch(request, options = {}) {
|
|
1248
|
+
try {
|
|
1249
|
+
validate(request);
|
|
1250
|
+
if (request.operation !== "watch") {
|
|
1251
|
+
throw new OrchestrationError({
|
|
1252
|
+
code: "INVALID",
|
|
1253
|
+
message: "streaming protocol accepts only watch operations",
|
|
1254
|
+
retryable: false
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
const watchOptions = request.payload.options;
|
|
1258
|
+
for await (const event of client.watch(
|
|
1259
|
+
requirePayload(request.payload, "query"),
|
|
1260
|
+
{
|
|
1261
|
+
...watchOptions,
|
|
1262
|
+
signal: options.signal
|
|
1263
|
+
}
|
|
1264
|
+
)) {
|
|
1265
|
+
yield success(request, event);
|
|
1266
|
+
}
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
yield failure(request, error);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
function createFetchOrchestrationTransport(options) {
|
|
1274
|
+
const fetch_ = options.fetch ?? globalThis.fetch;
|
|
1275
|
+
const maxResponseBytes = options.maxResponseBytes ?? 1024 * 1024;
|
|
1276
|
+
const maxWatchLineBytes = options.maxWatchLineBytes ?? 1024 * 1024;
|
|
1277
|
+
function assertWatchLineSize(line) {
|
|
1278
|
+
if (new TextEncoder().encode(line).byteLength > maxWatchLineBytes) {
|
|
1279
|
+
throw new OrchestrationError({
|
|
1280
|
+
code: "EXHAUSTED",
|
|
1281
|
+
message: `remote orchestration watch line exceeds ${maxWatchLineBytes} bytes`,
|
|
1282
|
+
retryable: false
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
async function headers(accept) {
|
|
1287
|
+
const additional = typeof options.headers === "function" ? await options.headers() : options.headers ?? {};
|
|
1288
|
+
return {
|
|
1289
|
+
Accept: accept,
|
|
1290
|
+
"Content-Type": "application/json",
|
|
1291
|
+
...additional
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
async function post(request, accept, signal) {
|
|
1295
|
+
const response = await fetch_(options.endpoint, {
|
|
1296
|
+
method: "POST",
|
|
1297
|
+
headers: await headers(accept),
|
|
1298
|
+
body: JSON.stringify(request),
|
|
1299
|
+
signal,
|
|
1300
|
+
...options.credentials ? { credentials: options.credentials } : {}
|
|
1301
|
+
});
|
|
1302
|
+
if (!response.ok) {
|
|
1303
|
+
throw new OrchestrationError({
|
|
1304
|
+
code: response.status === 401 || response.status === 403 ? "FORBIDDEN" : "UNAVAILABLE",
|
|
1305
|
+
message: `remote orchestration endpoint returned HTTP ${response.status}`,
|
|
1306
|
+
retryable: response.status >= 500
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
return response;
|
|
1310
|
+
}
|
|
1311
|
+
async function readBoundedText(response, limit) {
|
|
1312
|
+
if (!response.body) return "";
|
|
1313
|
+
const reader = response.body.getReader();
|
|
1314
|
+
const decoder = new TextDecoder();
|
|
1315
|
+
let size = 0;
|
|
1316
|
+
let text = "";
|
|
1317
|
+
try {
|
|
1318
|
+
for (; ; ) {
|
|
1319
|
+
const { done, value } = await reader.read();
|
|
1320
|
+
if (done) break;
|
|
1321
|
+
size += value.byteLength;
|
|
1322
|
+
if (size > limit) {
|
|
1323
|
+
await reader.cancel();
|
|
1324
|
+
throw new OrchestrationError({
|
|
1325
|
+
code: "EXHAUSTED",
|
|
1326
|
+
message: `remote orchestration response exceeds ${limit} bytes`,
|
|
1327
|
+
retryable: false
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
text += decoder.decode(value, { stream: true });
|
|
1331
|
+
}
|
|
1332
|
+
return text + decoder.decode();
|
|
1333
|
+
} finally {
|
|
1334
|
+
reader.releaseLock();
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return {
|
|
1338
|
+
async request(request, transportOptions = {}) {
|
|
1339
|
+
const response = await post(request, "application/json", transportOptions.signal);
|
|
1340
|
+
const text = await readBoundedText(response, maxResponseBytes);
|
|
1341
|
+
return JSON.parse(text);
|
|
1342
|
+
},
|
|
1343
|
+
async *watch(request, transportOptions = {}) {
|
|
1344
|
+
const response = await post(request, "application/x-ndjson", transportOptions.signal);
|
|
1345
|
+
if (!response.body) {
|
|
1346
|
+
throw new OrchestrationError({
|
|
1347
|
+
code: "UNAVAILABLE",
|
|
1348
|
+
message: "remote orchestration watch response has no body",
|
|
1349
|
+
retryable: true
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
const reader = response.body.getReader();
|
|
1353
|
+
const decoder = new TextDecoder();
|
|
1354
|
+
let pending = "";
|
|
1355
|
+
let streamCompleted = false;
|
|
1356
|
+
try {
|
|
1357
|
+
for (; ; ) {
|
|
1358
|
+
const { done, value } = await reader.read();
|
|
1359
|
+
if (done) {
|
|
1360
|
+
streamCompleted = true;
|
|
1361
|
+
break;
|
|
1362
|
+
}
|
|
1363
|
+
pending += decoder.decode(value, { stream: true });
|
|
1364
|
+
let newline = pending.indexOf("\n");
|
|
1365
|
+
while (newline >= 0) {
|
|
1366
|
+
const line = pending.slice(0, newline).trim();
|
|
1367
|
+
pending = pending.slice(newline + 1);
|
|
1368
|
+
assertWatchLineSize(line);
|
|
1369
|
+
if (line) yield JSON.parse(line);
|
|
1370
|
+
newline = pending.indexOf("\n");
|
|
1371
|
+
}
|
|
1372
|
+
if (pending.length > maxWatchLineBytes) {
|
|
1373
|
+
throw new OrchestrationError({
|
|
1374
|
+
code: "EXHAUSTED",
|
|
1375
|
+
message: `remote orchestration watch line exceeds ${maxWatchLineBytes} bytes`,
|
|
1376
|
+
retryable: false
|
|
1377
|
+
});
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
pending += decoder.decode();
|
|
1381
|
+
if (pending.trim()) {
|
|
1382
|
+
assertWatchLineSize(pending.trim());
|
|
1383
|
+
yield JSON.parse(pending);
|
|
1384
|
+
}
|
|
1385
|
+
} finally {
|
|
1386
|
+
if (!streamCompleted) {
|
|
1387
|
+
await reader.cancel().catch(() => void 0);
|
|
1388
|
+
}
|
|
1389
|
+
reader.releaseLock();
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
}
|
|
1394
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
1395
|
+
0 && (module.exports = {
|
|
1396
|
+
ALL_CATEGORIES,
|
|
1397
|
+
AgentCreationController,
|
|
1398
|
+
AgentDefinitionEditorController,
|
|
1399
|
+
AgentSessionController,
|
|
1400
|
+
OrchestrationError,
|
|
1401
|
+
PromptPreviewController,
|
|
1402
|
+
REMOTE_ORCHESTRATION_PROTOCOL,
|
|
1403
|
+
TiddlyWikiHttpStorage,
|
|
1404
|
+
createFetchOrchestrationTransport,
|
|
1405
|
+
createNamespacedOrchestrationClient,
|
|
1406
|
+
createReadOnlyOrchestrationClient,
|
|
1407
|
+
createRemoteOrchestrationClient,
|
|
1408
|
+
createRemoteOrchestrationHandler,
|
|
1409
|
+
getCategoryConfig,
|
|
1410
|
+
isTaskCategory,
|
|
1411
|
+
resolveCategory
|
|
1412
|
+
});
|
|
1413
|
+
//# sourceMappingURL=browser.cjs.map
|