@standardagents/builder 0.37.8 → 0.38.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/dist/built-in-routes.js +1246 -518
- package/dist/built-in-routes.js.map +1 -1
- package/dist/client/{ApiKeysView-L85eJb6G.js → ApiKeysView-AH5i-H6j.js} +1 -1
- package/dist/client/CenteredContentView-DaBp0K-A.js +1 -0
- package/dist/client/{CompositionView-BGp0EJCk.js → CompositionView-yY1Q4M23.js} +1 -1
- package/dist/client/{ConfirmDialog.vue_vue_type_script_setup_true_lang-DgwqZrLV.js → ConfirmDialog.vue_vue_type_script_setup_true_lang-Bwo5CJzF.js} +1 -1
- package/dist/client/{CopyButton.vue_vue_type_script_setup_true_lang-B8cGgU2J.js → CopyButton.vue_vue_type_script_setup_true_lang-D0WYwWyA.js} +1 -1
- package/dist/client/{DataTable.vue_vue_type_script_setup_true_lang-CRBXym9D.js → DataTable.vue_vue_type_script_setup_true_lang-1wwPn2aY.js} +1 -1
- package/dist/client/{JsonViewer-DkHnIfq3.js → JsonViewer-Bi8Zdmir.js} +1 -1
- package/dist/client/LoginView-BIKahEU6.js +1 -0
- package/dist/client/{MarketplaceView-DEnujUBs.js → MarketplaceView-DPDPVH68.js} +1 -1
- package/dist/client/{Modal.vue_vue_type_script_setup_true_lang-keKEwm3K.js → Modal.vue_vue_type_script_setup_true_lang-D1_rfOsy.js} +1 -1
- package/dist/client/{ModelModal.vue_vue_type_script_setup_true_lang-t1n0bbJe.js → ModelModal.vue_vue_type_script_setup_true_lang-DSLeOdxr.js} +1 -1
- package/dist/client/{ModelsView-BkCLr8sp.js → ModelsView-Q2WXu1Gw.js} +1 -1
- package/dist/client/{PromptEditView-BjCfsJQE.js → PromptEditView-BzA-3n1w.js} +1 -1
- package/dist/client/{PromptModal-nxu_LIv6.js → PromptModal-CJWh_cru.js} +1 -1
- package/dist/client/{PromptsView-1yXGCmEZ.js → PromptsView-BezNl-Et.js} +1 -1
- package/dist/client/{ProvidersView-DxF6gafk.js → ProvidersView-BuzSKxuT.js} +1 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-DOxNp_3C.js +22 -0
- package/dist/client/{ThreadsView-CBup_w8u.js → ThreadsView-DPCpZA4J.js} +1 -1
- package/dist/client/{ToolsView-B30TfXU9.js → ToolsView-DMjFMAhH.js} +1 -1
- package/dist/client/{UiCodeBlock.vue_vue_type_script_setup_true_lang-BdyzSxZZ.js → UiCodeBlock.vue_vue_type_script_setup_true_lang-7FgZmkfs.js} +1 -1
- package/dist/client/{UsersView-kE7Xr4f3.js → UsersView-B7jXLNQs.js} +1 -1
- package/dist/client/{VariablesView-yYuynG0M.js → VariablesView-CF7x0G8g.js} +1 -1
- package/dist/client/assets/{ThreadInspectorPane-BRGO_P0_.css → ThreadInspectorPane-CZMdV0Tb.css} +1 -1
- package/dist/client/assets/{index-B-69GGhJ.css → index-DAABRRAA.css} +1 -1
- package/dist/client/{check-YKi1o6p6.js → check-CD2lvcVi.js} +1 -1
- package/dist/client/{chevron-right-T0zzq_GX.js → chevron-right-bWZrmJ5a.js} +1 -1
- package/dist/client/{copy-C_gUGAj1.js → copy-B7nifl6a.js} +1 -1
- package/dist/client/{formkit-CE26dtFp.js → formkit-DJxUzqRQ.js} +1 -1
- package/dist/client/index-eGECJFYe.js +6 -0
- package/dist/client/index.html +6 -6
- package/dist/client/{package-B70IFSDB.js → package-Dyv7fTIQ.js} +1 -1
- package/dist/client/{plus-BN9IHYdt.js → plus-XkSslfF4.js} +1 -1
- package/dist/client/{syntax-D-ZcovVx.js → syntax-D68HCEYm.js} +1 -1
- package/dist/client/{timeAgo-G1ovbWPH.js → timeAgo-DRBdu9ed.js} +1 -1
- package/dist/client/{useActionFeedback-7pfPjKMi.js → useActionFeedback-FN4t6ezB.js} +1 -1
- package/dist/client/{vendor-TPZjEwCU.js → vendor-c_uwtQ-S.js} +13 -13
- package/dist/client/{vue-CZ-ORfS3.js → vue-BuvSxRmI.js} +1 -1
- package/dist/{index-Lfan8QMN.d.ts → index-CF-lgN47.d.ts} +83 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1155 -360
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +131 -72
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +69 -11
- package/dist/runtime.js +1018 -280
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +7 -6
- package/dist/client/CenteredContentView-D9jkWoLc.js +0 -1
- package/dist/client/LoginView-BXD9Odc-.js +0 -1
- package/dist/client/ThreadInspectorPane.vue_vue_type_script_setup_true_lang-CjwWJ3uw.js +0 -22
- package/dist/client/index-AUGwDdSH.js +0 -6
package/dist/runtime.js
CHANGED
|
@@ -28,6 +28,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
28
28
|
};
|
|
29
29
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
30
|
|
|
31
|
+
// src/skills/scope.ts
|
|
32
|
+
var SHARED_SKILL_OWNER;
|
|
33
|
+
var init_scope = __esm({
|
|
34
|
+
"src/skills/scope.ts"() {
|
|
35
|
+
SHARED_SKILL_OWNER = "__instance_shared__";
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
31
39
|
// src/agents/client-forwarding.ts
|
|
32
40
|
function asForwarding(state) {
|
|
33
41
|
return state;
|
|
@@ -3150,6 +3158,104 @@ var init_sessionTools = __esm({
|
|
|
3150
3158
|
}
|
|
3151
3159
|
});
|
|
3152
3160
|
|
|
3161
|
+
// src/utils/remoteAttachment.ts
|
|
3162
|
+
function parseAllowedHosts(value) {
|
|
3163
|
+
if (typeof value !== "string") {
|
|
3164
|
+
return /* @__PURE__ */ new Set();
|
|
3165
|
+
}
|
|
3166
|
+
return new Set(
|
|
3167
|
+
value.split(",").map((host) => host.trim().toLowerCase().replace(/\.$/, "")).filter(Boolean)
|
|
3168
|
+
);
|
|
3169
|
+
}
|
|
3170
|
+
function isForbiddenHostname(hostname) {
|
|
3171
|
+
const normalized = hostname.toLowerCase().replace(/\.$/, "");
|
|
3172
|
+
if (/^\d{1,3}(?:\.\d{1,3}){3}$/.test(normalized)) {
|
|
3173
|
+
return true;
|
|
3174
|
+
}
|
|
3175
|
+
if (normalized.startsWith("[") && normalized.endsWith("]")) {
|
|
3176
|
+
return true;
|
|
3177
|
+
}
|
|
3178
|
+
if (!normalized.includes(".")) {
|
|
3179
|
+
return true;
|
|
3180
|
+
}
|
|
3181
|
+
return FORBIDDEN_HOST_SUFFIXES.some(
|
|
3182
|
+
(suffix) => normalized === suffix.slice(1) || normalized.endsWith(suffix)
|
|
3183
|
+
);
|
|
3184
|
+
}
|
|
3185
|
+
function validateRemoteAttachmentUrl(value, allowedHostsValue) {
|
|
3186
|
+
let url;
|
|
3187
|
+
try {
|
|
3188
|
+
url = new URL(value);
|
|
3189
|
+
} catch {
|
|
3190
|
+
return null;
|
|
3191
|
+
}
|
|
3192
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.port !== "" && url.port !== "443") {
|
|
3193
|
+
return null;
|
|
3194
|
+
}
|
|
3195
|
+
const hostname = url.hostname.toLowerCase().replace(/\.$/, "");
|
|
3196
|
+
if (isForbiddenHostname(hostname)) {
|
|
3197
|
+
return null;
|
|
3198
|
+
}
|
|
3199
|
+
const allowedHosts = parseAllowedHosts(allowedHostsValue);
|
|
3200
|
+
if (!allowedHosts.has(hostname)) {
|
|
3201
|
+
return null;
|
|
3202
|
+
}
|
|
3203
|
+
return url;
|
|
3204
|
+
}
|
|
3205
|
+
async function fetchRemoteAttachment(location, allowedHostsValue, fetchImpl = fetch) {
|
|
3206
|
+
let url = validateRemoteAttachmentUrl(location, allowedHostsValue);
|
|
3207
|
+
if (!url) {
|
|
3208
|
+
return null;
|
|
3209
|
+
}
|
|
3210
|
+
for (let redirectCount = 0; redirectCount <= MAX_REDIRECTS; redirectCount++) {
|
|
3211
|
+
let response;
|
|
3212
|
+
try {
|
|
3213
|
+
response = await fetchImpl(url.toString(), {
|
|
3214
|
+
redirect: "manual"
|
|
3215
|
+
});
|
|
3216
|
+
} catch {
|
|
3217
|
+
return null;
|
|
3218
|
+
}
|
|
3219
|
+
if (!REDIRECT_STATUSES.has(response.status)) {
|
|
3220
|
+
return response.ok ? response : null;
|
|
3221
|
+
}
|
|
3222
|
+
await response.body?.cancel().catch(() => void 0);
|
|
3223
|
+
if (redirectCount === MAX_REDIRECTS) {
|
|
3224
|
+
return null;
|
|
3225
|
+
}
|
|
3226
|
+
const redirectLocation = response.headers.get("Location");
|
|
3227
|
+
if (!redirectLocation) {
|
|
3228
|
+
return null;
|
|
3229
|
+
}
|
|
3230
|
+
let resolvedLocation;
|
|
3231
|
+
try {
|
|
3232
|
+
resolvedLocation = new URL(redirectLocation, url).toString();
|
|
3233
|
+
} catch {
|
|
3234
|
+
return null;
|
|
3235
|
+
}
|
|
3236
|
+
url = validateRemoteAttachmentUrl(resolvedLocation, allowedHostsValue);
|
|
3237
|
+
if (!url) {
|
|
3238
|
+
return null;
|
|
3239
|
+
}
|
|
3240
|
+
}
|
|
3241
|
+
return null;
|
|
3242
|
+
}
|
|
3243
|
+
var REDIRECT_STATUSES, MAX_REDIRECTS, FORBIDDEN_HOST_SUFFIXES;
|
|
3244
|
+
var init_remoteAttachment = __esm({
|
|
3245
|
+
"src/utils/remoteAttachment.ts"() {
|
|
3246
|
+
REDIRECT_STATUSES = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
|
|
3247
|
+
MAX_REDIRECTS = 3;
|
|
3248
|
+
FORBIDDEN_HOST_SUFFIXES = [
|
|
3249
|
+
".internal",
|
|
3250
|
+
".lan",
|
|
3251
|
+
".local",
|
|
3252
|
+
".localhost",
|
|
3253
|
+
".home",
|
|
3254
|
+
".test"
|
|
3255
|
+
];
|
|
3256
|
+
}
|
|
3257
|
+
});
|
|
3258
|
+
|
|
3153
3259
|
// src/durable-objects/files.ts
|
|
3154
3260
|
var files_exports = {};
|
|
3155
3261
|
__export(files_exports, {
|
|
@@ -3887,6 +3993,7 @@ var init_ToolExecutor = __esm({
|
|
|
3887
3993
|
init_types();
|
|
3888
3994
|
init_ThreadStateImpl();
|
|
3889
3995
|
init_sessionTools();
|
|
3996
|
+
init_remoteAttachment();
|
|
3890
3997
|
SUBAGENT_CREATE_TOOL = "subagent_create";
|
|
3891
3998
|
SUBAGENT_MESSAGE_TOOL = "subagent_message";
|
|
3892
3999
|
SUBAGENTS_LIST_TOOL = "subagents";
|
|
@@ -4935,7 +5042,8 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4935
5042
|
stub,
|
|
4936
5043
|
state.thread.instance,
|
|
4937
5044
|
childResult.attachments,
|
|
4938
|
-
`from-subagent-${childThreadId}
|
|
5045
|
+
`from-subagent-${childThreadId}`,
|
|
5046
|
+
state.env.AGENT_BUILDER_ATTACHMENT_FETCH_HOSTS
|
|
4939
5047
|
);
|
|
4940
5048
|
if (resumable) {
|
|
4941
5049
|
await this.settleResumableChildAfterRun(
|
|
@@ -4968,7 +5076,8 @@ Message one with subagent_message(referenceId, message).`
|
|
|
4968
5076
|
stub,
|
|
4969
5077
|
state.thread.instance,
|
|
4970
5078
|
childResult.attachments,
|
|
4971
|
-
`from-subagent-${childThreadId}
|
|
5079
|
+
`from-subagent-${childThreadId}`,
|
|
5080
|
+
state.env.AGENT_BUILDER_ATTACHMENT_FETCH_HOSTS
|
|
4972
5081
|
);
|
|
4973
5082
|
const messageContent = this.formatSubagentTerminalMessage(
|
|
4974
5083
|
childThreadId,
|
|
@@ -5382,7 +5491,8 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5382
5491
|
state.thread.instance,
|
|
5383
5492
|
childThread,
|
|
5384
5493
|
parentAttachments,
|
|
5385
|
-
`from-parent-${state.threadId}
|
|
5494
|
+
`from-parent-${state.threadId}`,
|
|
5495
|
+
state.env.AGENT_BUILDER_ATTACHMENT_FETCH_HOSTS
|
|
5386
5496
|
);
|
|
5387
5497
|
const targetRole = receivesMessages === "side_a" ? "user" : "assistant";
|
|
5388
5498
|
const baseTimestamp = Date.now() * 1e3;
|
|
@@ -5642,7 +5752,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5642
5752
|
const shortId = crypto.randomUUID().slice(0, 8);
|
|
5643
5753
|
return `/attachments/${normalizedStem}-${shortId}.${finalExt}`;
|
|
5644
5754
|
}
|
|
5645
|
-
static async copyAttachmentsBetweenThreads(sourceThread, targetThread, attachments, _pathPrefix) {
|
|
5755
|
+
static async copyAttachmentsBetweenThreads(sourceThread, targetThread, attachments, _pathPrefix, allowedAttachmentFetchHosts) {
|
|
5646
5756
|
if (!attachments || attachments.length === 0) {
|
|
5647
5757
|
return [];
|
|
5648
5758
|
}
|
|
@@ -5670,7 +5780,8 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5670
5780
|
const copiedData = await this.readAttachmentDataFromSource(
|
|
5671
5781
|
sourceThread,
|
|
5672
5782
|
attachment.path,
|
|
5673
|
-
sourceFile
|
|
5783
|
+
sourceFile,
|
|
5784
|
+
allowedAttachmentFetchHosts
|
|
5674
5785
|
);
|
|
5675
5786
|
if (!copiedData) {
|
|
5676
5787
|
continue;
|
|
@@ -5727,7 +5838,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5727
5838
|
}
|
|
5728
5839
|
return copied;
|
|
5729
5840
|
}
|
|
5730
|
-
static async readAttachmentDataFromSource(sourceThread, path, sourceFile) {
|
|
5841
|
+
static async readAttachmentDataFromSource(sourceThread, path, sourceFile, allowedAttachmentFetchHosts) {
|
|
5731
5842
|
const sourceData = await sourceThread.readFile(path);
|
|
5732
5843
|
if (sourceData.success && sourceData.data) {
|
|
5733
5844
|
return sourceData.data;
|
|
@@ -5736,14 +5847,17 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5736
5847
|
return null;
|
|
5737
5848
|
}
|
|
5738
5849
|
const location = sourceFile.location;
|
|
5739
|
-
if (!location
|
|
5850
|
+
if (!location) {
|
|
5851
|
+
return null;
|
|
5852
|
+
}
|
|
5853
|
+
const response = await fetchRemoteAttachment(
|
|
5854
|
+
location,
|
|
5855
|
+
allowedAttachmentFetchHosts
|
|
5856
|
+
);
|
|
5857
|
+
if (!response) {
|
|
5740
5858
|
return null;
|
|
5741
5859
|
}
|
|
5742
5860
|
try {
|
|
5743
|
-
const response = await fetch(location);
|
|
5744
|
-
if (!response.ok) {
|
|
5745
|
-
return null;
|
|
5746
|
-
}
|
|
5747
5861
|
const buffer = await response.arrayBuffer();
|
|
5748
5862
|
return this.arrayBufferToBase64(buffer);
|
|
5749
5863
|
} catch {
|
|
@@ -5997,7 +6111,8 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
5997
6111
|
state.thread.instance,
|
|
5998
6112
|
childStub,
|
|
5999
6113
|
sourceAttachments,
|
|
6000
|
-
`from-parent-${state.threadId}
|
|
6114
|
+
`from-parent-${state.threadId}`,
|
|
6115
|
+
state.env.AGENT_BUILDER_ATTACHMENT_FETCH_HOSTS
|
|
6001
6116
|
);
|
|
6002
6117
|
await childStub.queueMessage(referenceId, {
|
|
6003
6118
|
role: receivesMessages === "side_a" ? "user" : "assistant",
|
|
@@ -12979,6 +13094,32 @@ var ThreadStateImpl_exports = {};
|
|
|
12979
13094
|
__export(ThreadStateImpl_exports, {
|
|
12980
13095
|
ThreadStateImpl: () => ThreadStateImpl
|
|
12981
13096
|
});
|
|
13097
|
+
function isRuntimeDurableNamespace(value) {
|
|
13098
|
+
return value !== null && typeof value === "object" && "idFromName" in value && typeof value.idFromName === "function" && "get" in value && typeof value.get === "function";
|
|
13099
|
+
}
|
|
13100
|
+
function isThreadStateRuntimeEnvironment(value) {
|
|
13101
|
+
return value !== null && typeof value === "object" && "AGENT_BUILDER" in value && isRuntimeDurableNamespace(value.AGENT_BUILDER) && (!("AGENT_BUILDER_USER_HUB" in value) || value.AGENT_BUILDER_USER_HUB === void 0 || isRuntimeDurableNamespace(value.AGENT_BUILDER_USER_HUB));
|
|
13102
|
+
}
|
|
13103
|
+
function confinedUserEndpointUrl(userId, endpoint) {
|
|
13104
|
+
const base = new URL(
|
|
13105
|
+
`https://user-hub/users/${encodeURIComponent(userId)}/endpoints/`
|
|
13106
|
+
);
|
|
13107
|
+
const relative = endpoint.replace(/^\/+/, "");
|
|
13108
|
+
let decoded;
|
|
13109
|
+
try {
|
|
13110
|
+
decoded = decodeURIComponent(relative);
|
|
13111
|
+
} catch {
|
|
13112
|
+
throw new Error("Invalid user endpoint path: malformed percent encoding.");
|
|
13113
|
+
}
|
|
13114
|
+
if (decoded.includes("\\") || decoded.includes("?") || decoded.includes("#") || /[\u0000-\u001f\u007f]/.test(decoded) || decoded.split("/").some((segment) => segment === "." || segment === "..")) {
|
|
13115
|
+
throw new Error("Invalid user endpoint path: traversal and URL syntax are not allowed.");
|
|
13116
|
+
}
|
|
13117
|
+
const resolved = new URL(relative, base);
|
|
13118
|
+
if (resolved.origin !== base.origin || !resolved.pathname.startsWith(base.pathname)) {
|
|
13119
|
+
throw new Error("Invalid user endpoint path: endpoint escaped the user namespace.");
|
|
13120
|
+
}
|
|
13121
|
+
return resolved.toString();
|
|
13122
|
+
}
|
|
12982
13123
|
function hasLocalCodeExecutionRuntime(threadInstance) {
|
|
12983
13124
|
const candidate = threadInstance;
|
|
12984
13125
|
return Boolean(candidate.env && candidate.ctx);
|
|
@@ -13159,6 +13300,7 @@ function runCodeViaThreadRpc(threadInstance, threadId, source, options) {
|
|
|
13159
13300
|
var ThreadStateImpl, ExecutionStateImpl;
|
|
13160
13301
|
var init_ThreadStateImpl = __esm({
|
|
13161
13302
|
"src/agents/ThreadStateImpl.ts"() {
|
|
13303
|
+
init_scope();
|
|
13162
13304
|
init_client_forwarding();
|
|
13163
13305
|
init_types();
|
|
13164
13306
|
init_utilities();
|
|
@@ -13392,6 +13534,14 @@ var init_ThreadStateImpl = __esm({
|
|
|
13392
13534
|
}
|
|
13393
13535
|
return value;
|
|
13394
13536
|
}
|
|
13537
|
+
async instanceEnv(propertyName) {
|
|
13538
|
+
const agentBuilder = this._getAgentBuilderStub();
|
|
13539
|
+
if (typeof agentBuilder.getInstanceEnv !== "function") {
|
|
13540
|
+
throw new Error("instanceEnv is not supported by this runtime");
|
|
13541
|
+
}
|
|
13542
|
+
const values = await agentBuilder.getInstanceEnv();
|
|
13543
|
+
return values[propertyName];
|
|
13544
|
+
}
|
|
13395
13545
|
async envType(propertyName) {
|
|
13396
13546
|
const agentBuilder = this._getAgentBuilderStub();
|
|
13397
13547
|
if (typeof agentBuilder.resolveThreadEnvType === "function") {
|
|
@@ -14422,12 +14572,11 @@ var init_ThreadStateImpl = __esm({
|
|
|
14422
14572
|
* dispatcher recorded in the runtime context instead.
|
|
14423
14573
|
*/
|
|
14424
14574
|
_getRuntimeEnv() {
|
|
14425
|
-
|
|
14426
|
-
|
|
14427
|
-
return contextEnv;
|
|
14575
|
+
if (isThreadStateRuntimeEnvironment(this._runtimeContext.env)) {
|
|
14576
|
+
return this._runtimeContext.env;
|
|
14428
14577
|
}
|
|
14429
14578
|
const instanceEnv = this._threadInstance.env;
|
|
14430
|
-
if (!instanceEnv
|
|
14579
|
+
if (!isThreadStateRuntimeEnvironment(instanceEnv)) {
|
|
14431
14580
|
throw new Error(
|
|
14432
14581
|
"No runtime environment available on this ThreadState. Stub-backed states must be constructed with runtimeContext.env."
|
|
14433
14582
|
);
|
|
@@ -14444,9 +14593,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
14444
14593
|
return namespace.get(namespace.idFromName(userId));
|
|
14445
14594
|
}
|
|
14446
14595
|
// ─────────────────────────────────────────────────────────────────────────
|
|
14447
|
-
// Skills —
|
|
14448
|
-
// DurableAgentBuilder singleton (skills are never stored per-thread or on
|
|
14449
|
-
// a client machine).
|
|
14596
|
+
// Skills — owner-scoped library plus explicitly shared administrator skills.
|
|
14450
14597
|
// ─────────────────────────────────────────────────────────────────────────
|
|
14451
14598
|
/**
|
|
14452
14599
|
* The profile of the user this thread belongs to (identity fields only —
|
|
@@ -14469,9 +14616,8 @@ var init_ThreadStateImpl = __esm({
|
|
|
14469
14616
|
"Reentrant user-scope call: this ThreadState was raised from user-scope code; state.user().call() is unavailable here."
|
|
14470
14617
|
);
|
|
14471
14618
|
}
|
|
14472
|
-
const path = endpoint.replace(/^\/+/, "");
|
|
14473
14619
|
return hub().fetch(
|
|
14474
|
-
new Request(
|
|
14620
|
+
new Request(confinedUserEndpointUrl(userId, endpoint), {
|
|
14475
14621
|
method: "POST",
|
|
14476
14622
|
headers: {
|
|
14477
14623
|
"Content-Type": "application/json",
|
|
@@ -14531,18 +14677,42 @@ var init_ThreadStateImpl = __esm({
|
|
|
14531
14677
|
}
|
|
14532
14678
|
get skills() {
|
|
14533
14679
|
const stub = this._getAgentBuilderStub();
|
|
14680
|
+
const ownerId = this._metadata.user_id ?? SHARED_SKILL_OWNER;
|
|
14681
|
+
const scope = {
|
|
14682
|
+
ownerId,
|
|
14683
|
+
includeShared: ownerId !== SHARED_SKILL_OWNER
|
|
14684
|
+
};
|
|
14685
|
+
const requireMutationAdmin = async () => {
|
|
14686
|
+
const userId = this._metadata.user_id;
|
|
14687
|
+
if (!userId) {
|
|
14688
|
+
throw new Error("Skill mutations require an authenticated instance admin.");
|
|
14689
|
+
}
|
|
14690
|
+
const user = await stub.getUserById(userId);
|
|
14691
|
+
if (user?.role !== "admin") {
|
|
14692
|
+
throw new Error("Skill mutations require an instance admin.");
|
|
14693
|
+
}
|
|
14694
|
+
};
|
|
14534
14695
|
return {
|
|
14535
|
-
list: (options) => stub.listSkills(options),
|
|
14696
|
+
list: (options) => stub.listSkills(scope, options),
|
|
14536
14697
|
get: async (name) => {
|
|
14537
|
-
const metadata = await stub.getSkill(name);
|
|
14698
|
+
const metadata = await stub.getSkill(scope, name);
|
|
14538
14699
|
if (!metadata) return null;
|
|
14539
|
-
const skillMd = await stub.getSkillFile(name, "SKILL.md") ?? "";
|
|
14700
|
+
const skillMd = await stub.getSkillFile(scope, name, "SKILL.md") ?? "";
|
|
14540
14701
|
return { metadata, skillMd };
|
|
14541
14702
|
},
|
|
14542
|
-
readFile: (name, path) => stub.getSkillFile(name, path),
|
|
14543
|
-
install: (files) =>
|
|
14544
|
-
|
|
14545
|
-
|
|
14703
|
+
readFile: (name, path) => stub.getSkillFile(scope, name, path),
|
|
14704
|
+
install: async (files) => {
|
|
14705
|
+
await requireMutationAdmin();
|
|
14706
|
+
return stub.upsertSkill(scope, files);
|
|
14707
|
+
},
|
|
14708
|
+
setEnabled: async (name, enabled) => {
|
|
14709
|
+
await requireMutationAdmin();
|
|
14710
|
+
return stub.setSkillEnabled(scope, name, enabled);
|
|
14711
|
+
},
|
|
14712
|
+
remove: async (name) => {
|
|
14713
|
+
await requireMutationAdmin();
|
|
14714
|
+
return stub.deleteSkill(scope, name);
|
|
14715
|
+
}
|
|
14546
14716
|
};
|
|
14547
14717
|
}
|
|
14548
14718
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -14703,56 +14873,9 @@ var init_image_processing = __esm({
|
|
|
14703
14873
|
|
|
14704
14874
|
// src/router/index.ts
|
|
14705
14875
|
init_ThreadStateImpl();
|
|
14706
|
-
function defineController2(controller) {
|
|
14707
|
-
return controller;
|
|
14708
|
-
}
|
|
14709
|
-
function createThreadEndpointHandler(handler) {
|
|
14710
|
-
return (async ({ req, params, env }) => {
|
|
14711
|
-
const threadId = params.threadId ?? params.id;
|
|
14712
|
-
if (!threadId) {
|
|
14713
|
-
return Response.json({ error: "Thread ID required" }, { status: 400 });
|
|
14714
|
-
}
|
|
14715
|
-
try {
|
|
14716
|
-
const agentBuilderId = env.AGENT_BUILDER.idFromName("singleton");
|
|
14717
|
-
const agentBuilder = env.AGENT_BUILDER.get(agentBuilderId);
|
|
14718
|
-
const metadata = await agentBuilder.getThread(threadId);
|
|
14719
|
-
if (!metadata) {
|
|
14720
|
-
return Response.json(
|
|
14721
|
-
{ error: `Thread not found: ${threadId}` },
|
|
14722
|
-
{ status: 404 }
|
|
14723
|
-
);
|
|
14724
|
-
}
|
|
14725
|
-
const meta = metadata;
|
|
14726
|
-
if (!meta.agent_id && meta.agent_name) {
|
|
14727
|
-
meta.agent_id = meta.agent_name;
|
|
14728
|
-
}
|
|
14729
|
-
const durableId = env.AGENT_BUILDER_THREAD.idFromName(threadId);
|
|
14730
|
-
const stub = env.AGENT_BUILDER_THREAD.get(durableId);
|
|
14731
|
-
const instance = stub;
|
|
14732
|
-
const threadState = ThreadStateImpl.fromThreadInstance(instance, metadata, {
|
|
14733
|
-
env
|
|
14734
|
-
});
|
|
14735
|
-
const endpointParams = {};
|
|
14736
|
-
for (const [key, value] of Object.entries(params)) {
|
|
14737
|
-
if (key === "threadId" || key === "id" && !params.threadId) {
|
|
14738
|
-
continue;
|
|
14739
|
-
}
|
|
14740
|
-
endpointParams[key === "_" ? "*" : key] = value;
|
|
14741
|
-
}
|
|
14742
|
-
const response = await handler(req, threadState, endpointParams);
|
|
14743
|
-
await threadState.flushPendingEventDeliveries();
|
|
14744
|
-
return response;
|
|
14745
|
-
} catch (error) {
|
|
14746
|
-
console.error(`Error in thread endpoint for ${threadId}:`, error);
|
|
14747
|
-
return Response.json(
|
|
14748
|
-
{ error: error.message || "Internal server error" },
|
|
14749
|
-
{ status: 500 }
|
|
14750
|
-
);
|
|
14751
|
-
}
|
|
14752
|
-
});
|
|
14753
|
-
}
|
|
14754
14876
|
|
|
14755
14877
|
// src/utils/auth.ts
|
|
14878
|
+
var SUPER_ADMIN_TOKEN_TTL_SECONDS = 12 * 60 * 60;
|
|
14756
14879
|
async function hashToken(token) {
|
|
14757
14880
|
const encoder = new TextEncoder();
|
|
14758
14881
|
const data = encoder.encode(token);
|
|
@@ -14818,9 +14941,12 @@ async function verifySuperAdminToken(token, encryptionKey) {
|
|
|
14818
14941
|
return false;
|
|
14819
14942
|
}
|
|
14820
14943
|
const timestamp = parseInt(parts[1], 10);
|
|
14944
|
+
if (!Number.isFinite(timestamp)) {
|
|
14945
|
+
return false;
|
|
14946
|
+
}
|
|
14821
14947
|
const age = Date.now() - timestamp;
|
|
14822
|
-
const maxAge =
|
|
14823
|
-
if (age > maxAge) {
|
|
14948
|
+
const maxAge = SUPER_ADMIN_TOKEN_TTL_SECONDS * 1e3;
|
|
14949
|
+
if (age < 0 || age > maxAge) {
|
|
14824
14950
|
return false;
|
|
14825
14951
|
}
|
|
14826
14952
|
return true;
|
|
@@ -14834,13 +14960,191 @@ function base64ToBuffer(base64) {
|
|
|
14834
14960
|
return bytes;
|
|
14835
14961
|
}
|
|
14836
14962
|
|
|
14837
|
-
// src/
|
|
14838
|
-
var
|
|
14963
|
+
// src/routing/access-policy.ts
|
|
14964
|
+
var PUBLIC_ROUTES = /* @__PURE__ */ new Set([
|
|
14965
|
+
"/api/auth/bootstrap",
|
|
14966
|
+
"/api/auth/login",
|
|
14967
|
+
"/api/auth/config",
|
|
14968
|
+
"/api/auth/brolly-control",
|
|
14969
|
+
"/api/auth/platform-cleanup",
|
|
14970
|
+
"/api/auth/platform-replica",
|
|
14971
|
+
"/api/auth/sa/start",
|
|
14972
|
+
"/api/auth/sa/callback",
|
|
14973
|
+
"/api/config",
|
|
14974
|
+
"/api/auth/oauth/github",
|
|
14975
|
+
"/api/auth/oauth/google",
|
|
14976
|
+
"/api/auth/oauth/github/callback",
|
|
14977
|
+
"/api/auth/oauth/google/callback"
|
|
14978
|
+
]);
|
|
14979
|
+
function isProviderIconRoute(routePath) {
|
|
14980
|
+
return /^\/api\/providers\/[^/]+\/icon$/.test(routePath);
|
|
14981
|
+
}
|
|
14982
|
+
function isHostedInstance(env) {
|
|
14983
|
+
const value = env && typeof env === "object" ? Reflect.get(env, "STANDARD_AGENTS_HOSTED") : void 0;
|
|
14984
|
+
if (typeof value === "string") {
|
|
14985
|
+
const normalized = value.trim().toLowerCase();
|
|
14986
|
+
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
14987
|
+
}
|
|
14988
|
+
return Boolean(value);
|
|
14989
|
+
}
|
|
14990
|
+
function isTrustedLocalDevelopmentRequest(request, env) {
|
|
14991
|
+
if (isHostedInstance(env)) return false;
|
|
14992
|
+
let hostname;
|
|
14993
|
+
try {
|
|
14994
|
+
hostname = new URL(request.url).hostname.toLowerCase();
|
|
14995
|
+
} catch {
|
|
14996
|
+
return false;
|
|
14997
|
+
}
|
|
14998
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
|
|
14999
|
+
}
|
|
15000
|
+
function isPublicApiRoute(routePath, request, env) {
|
|
15001
|
+
if (PUBLIC_ROUTES.has(routePath)) return true;
|
|
15002
|
+
if (routePath === "/api/auth/device/start" || routePath.startsWith("/api/auth/device/")) {
|
|
15003
|
+
return true;
|
|
15004
|
+
}
|
|
15005
|
+
if (isProviderIconRoute(routePath)) {
|
|
15006
|
+
return true;
|
|
15007
|
+
}
|
|
15008
|
+
return routePath === "/api/platform-auth/bootstrap" && isTrustedLocalDevelopmentRequest(request, env);
|
|
15009
|
+
}
|
|
15010
|
+
function requestObservedOrigins(request) {
|
|
15011
|
+
const origins = /* @__PURE__ */ new Set();
|
|
15012
|
+
let url = null;
|
|
15013
|
+
try {
|
|
15014
|
+
url = new URL(request.url);
|
|
15015
|
+
origins.add(url.origin);
|
|
15016
|
+
} catch {
|
|
15017
|
+
url = null;
|
|
15018
|
+
}
|
|
15019
|
+
const forwardedHost = request.headers.get("x-forwarded-host")?.split(",")[0]?.trim();
|
|
15020
|
+
const host = forwardedHost || request.headers.get("host")?.trim();
|
|
15021
|
+
if (!host) return origins;
|
|
15022
|
+
const forwardedProto = request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim().toLowerCase();
|
|
15023
|
+
const schemes = /* @__PURE__ */ new Set();
|
|
15024
|
+
if (forwardedProto === "http" || forwardedProto === "https") schemes.add(forwardedProto);
|
|
15025
|
+
if (url) schemes.add(url.protocol.replace(":", ""));
|
|
15026
|
+
if (schemes.size === 0) {
|
|
15027
|
+
schemes.add(host.endsWith(".orb.local") ? "https" : "http");
|
|
15028
|
+
}
|
|
15029
|
+
for (const scheme of schemes) {
|
|
15030
|
+
try {
|
|
15031
|
+
origins.add(new URL(`${scheme}://${host}`).origin);
|
|
15032
|
+
} catch {
|
|
15033
|
+
}
|
|
15034
|
+
}
|
|
15035
|
+
return origins;
|
|
15036
|
+
}
|
|
15037
|
+
function isSameOriginBrowserRequest(request) {
|
|
15038
|
+
const fetchSite = request.headers.get("Sec-Fetch-Site")?.trim().toLowerCase();
|
|
15039
|
+
if (fetchSite === "same-origin" || fetchSite === "none") {
|
|
15040
|
+
return true;
|
|
15041
|
+
}
|
|
15042
|
+
if (fetchSite) {
|
|
15043
|
+
return false;
|
|
15044
|
+
}
|
|
15045
|
+
const origin = request.headers.get("Origin")?.trim();
|
|
15046
|
+
if (!origin) return true;
|
|
15047
|
+
if (origin === "null") return false;
|
|
15048
|
+
try {
|
|
15049
|
+
return requestObservedOrigins(request).has(new URL(origin).origin);
|
|
15050
|
+
} catch {
|
|
15051
|
+
return false;
|
|
15052
|
+
}
|
|
15053
|
+
}
|
|
15054
|
+
function isAdminOnlyApiRoute(routePath, method = "GET") {
|
|
15055
|
+
if (routePath === "/api/hooks") return true;
|
|
15056
|
+
if (routePath === "/api/skills" || routePath.startsWith("/api/skills/")) return true;
|
|
15057
|
+
if (routePath === "/api/pack" || routePath.startsWith("/api/pack/")) return true;
|
|
15058
|
+
if (routePath === "/api/unpack" || routePath.startsWith("/api/unpack/")) return true;
|
|
15059
|
+
if (routePath === "/api/prompts" || routePath.startsWith("/api/prompts/")) return true;
|
|
15060
|
+
if (routePath === "/api/tools" || routePath.startsWith("/api/tools/")) return true;
|
|
15061
|
+
if (routePath === "/api/models" || routePath.startsWith("/api/models/")) return true;
|
|
15062
|
+
if (routePath === "/api/providers") return true;
|
|
15063
|
+
if (routePath.startsWith("/api/providers/")) {
|
|
15064
|
+
return !isProviderIconRoute(routePath);
|
|
15065
|
+
}
|
|
15066
|
+
if (routePath.startsWith("/api/agents/")) {
|
|
15067
|
+
return !/^\/api\/agents\/[^/]+\/tenvs$/.test(routePath);
|
|
15068
|
+
}
|
|
15069
|
+
if (routePath === "/api/agents" && method.toUpperCase() !== "GET") return true;
|
|
15070
|
+
return false;
|
|
15071
|
+
}
|
|
15072
|
+
|
|
15073
|
+
// src/routing/cors.ts
|
|
15074
|
+
var RUNTIME_CORS_HEADERS = {
|
|
14839
15075
|
"Access-Control-Allow-Origin": "*",
|
|
14840
15076
|
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
14841
15077
|
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
|
|
14842
15078
|
"Access-Control-Max-Age": "86400"
|
|
14843
15079
|
};
|
|
15080
|
+
var CORS_RESPONSE_HEADERS = [
|
|
15081
|
+
"Access-Control-Allow-Origin",
|
|
15082
|
+
"Access-Control-Allow-Methods",
|
|
15083
|
+
"Access-Control-Allow-Headers",
|
|
15084
|
+
"Access-Control-Max-Age",
|
|
15085
|
+
"Access-Control-Allow-Credentials",
|
|
15086
|
+
"Access-Control-Expose-Headers"
|
|
15087
|
+
];
|
|
15088
|
+
function mutateCorsHeaders(headers, exposeCors) {
|
|
15089
|
+
if (exposeCors) {
|
|
15090
|
+
for (const [key, value] of Object.entries(RUNTIME_CORS_HEADERS)) {
|
|
15091
|
+
if (!headers.has(key)) headers.set(key, value);
|
|
15092
|
+
}
|
|
15093
|
+
return;
|
|
15094
|
+
}
|
|
15095
|
+
for (const key of CORS_RESPONSE_HEADERS) {
|
|
15096
|
+
headers.delete(key);
|
|
15097
|
+
}
|
|
15098
|
+
}
|
|
15099
|
+
function exposesRuntimeCors(request, env) {
|
|
15100
|
+
return !isTrustedLocalDevelopmentRequest(request, env);
|
|
15101
|
+
}
|
|
15102
|
+
function runtimeCorsHeaders(request, env) {
|
|
15103
|
+
return exposesRuntimeCors(request, env) ? { ...RUNTIME_CORS_HEADERS } : {};
|
|
15104
|
+
}
|
|
15105
|
+
function applyRuntimeCors(response, request, env) {
|
|
15106
|
+
if (response.status === 101) return response;
|
|
15107
|
+
const exposeCors = exposesRuntimeCors(request, env);
|
|
15108
|
+
try {
|
|
15109
|
+
mutateCorsHeaders(response.headers, exposeCors);
|
|
15110
|
+
return response;
|
|
15111
|
+
} catch {
|
|
15112
|
+
}
|
|
15113
|
+
const headers = new Headers(response.headers);
|
|
15114
|
+
mutateCorsHeaders(headers, exposeCors);
|
|
15115
|
+
return new Response(response.body, {
|
|
15116
|
+
status: response.status,
|
|
15117
|
+
statusText: response.statusText,
|
|
15118
|
+
headers
|
|
15119
|
+
});
|
|
15120
|
+
}
|
|
15121
|
+
function runtimePreflightResponse(request, env) {
|
|
15122
|
+
if (!exposesRuntimeCors(request, env)) {
|
|
15123
|
+
return Response.json(
|
|
15124
|
+
{ error: "Cross-origin access is disabled for local development" },
|
|
15125
|
+
{ status: 403, headers: { "Cache-Control": "no-store" } }
|
|
15126
|
+
);
|
|
15127
|
+
}
|
|
15128
|
+
return new Response(null, {
|
|
15129
|
+
status: 204,
|
|
15130
|
+
headers: RUNTIME_CORS_HEADERS
|
|
15131
|
+
});
|
|
15132
|
+
}
|
|
15133
|
+
|
|
15134
|
+
// src/middleware/auth.ts
|
|
15135
|
+
function endpointCallerFromAuth(auth) {
|
|
15136
|
+
if (!auth) return null;
|
|
15137
|
+
const { id, username, role, permissions, email, display_name, avatar_url } = auth.user;
|
|
15138
|
+
return {
|
|
15139
|
+
id,
|
|
15140
|
+
username,
|
|
15141
|
+
role,
|
|
15142
|
+
permissions: permissions ?? null,
|
|
15143
|
+
email: email ?? null,
|
|
15144
|
+
display_name: display_name ?? null,
|
|
15145
|
+
avatar_url: avatar_url ?? null
|
|
15146
|
+
};
|
|
15147
|
+
}
|
|
14844
15148
|
function parsePermissions(value) {
|
|
14845
15149
|
if (Array.isArray(value)) return value.filter((p) => typeof p === "string");
|
|
14846
15150
|
if (typeof value === "string" && value.trim()) {
|
|
@@ -14861,43 +15165,88 @@ function extractBearerToken(request) {
|
|
|
14861
15165
|
if (cookieToken) {
|
|
14862
15166
|
return cookieToken;
|
|
14863
15167
|
}
|
|
14864
|
-
const isWebSocket = request.headers.get("upgrade")?.toLowerCase() === "websocket";
|
|
14865
|
-
if (isWebSocket) {
|
|
14866
|
-
try {
|
|
14867
|
-
const url = new URL(request.url);
|
|
14868
|
-
const token = url.searchParams.get("token");
|
|
14869
|
-
if (token) {
|
|
14870
|
-
return token;
|
|
14871
|
-
}
|
|
14872
|
-
} catch (err) {
|
|
14873
|
-
}
|
|
14874
|
-
}
|
|
14875
15168
|
return null;
|
|
14876
15169
|
}
|
|
14877
15170
|
function getAgentBuilder(env) {
|
|
14878
15171
|
const agentBuilderId = env.AGENT_BUILDER.idFromName("singleton");
|
|
14879
15172
|
return env.AGENT_BUILDER.get(agentBuilderId);
|
|
14880
15173
|
}
|
|
15174
|
+
function parseWebSocketTicketAuth(authJson) {
|
|
15175
|
+
let parsed;
|
|
15176
|
+
try {
|
|
15177
|
+
parsed = JSON.parse(authJson);
|
|
15178
|
+
} catch {
|
|
15179
|
+
return null;
|
|
15180
|
+
}
|
|
15181
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
15182
|
+
const record = parsed;
|
|
15183
|
+
if (!record.user || typeof record.user !== "object") return null;
|
|
15184
|
+
const user = record.user;
|
|
15185
|
+
if (typeof user.id !== "string" || typeof user.username !== "string" || typeof user.role !== "string" || record.authType !== "super_admin" && record.authType !== "session" && record.authType !== "api_key") {
|
|
15186
|
+
return null;
|
|
15187
|
+
}
|
|
15188
|
+
const permissions = user.permissions;
|
|
15189
|
+
if (permissions !== void 0 && permissions !== null && (!Array.isArray(permissions) || !permissions.every((permission) => typeof permission === "string"))) {
|
|
15190
|
+
return null;
|
|
15191
|
+
}
|
|
15192
|
+
if (record.credentialId !== void 0 && typeof record.credentialId !== "string") return null;
|
|
15193
|
+
return {
|
|
15194
|
+
user: {
|
|
15195
|
+
id: user.id,
|
|
15196
|
+
username: user.username,
|
|
15197
|
+
role: user.role,
|
|
15198
|
+
permissions,
|
|
15199
|
+
platform_user_id: typeof user.platform_user_id === "string" ? user.platform_user_id : null,
|
|
15200
|
+
email: typeof user.email === "string" ? user.email : null,
|
|
15201
|
+
display_name: typeof user.display_name === "string" ? user.display_name : null,
|
|
15202
|
+
avatar_url: typeof user.avatar_url === "string" ? user.avatar_url : null
|
|
15203
|
+
},
|
|
15204
|
+
authType: record.authType,
|
|
15205
|
+
credentialId: record.credentialId
|
|
15206
|
+
};
|
|
15207
|
+
}
|
|
15208
|
+
async function consumeWebSocketTicket(request, env) {
|
|
15209
|
+
if (request.headers.get("upgrade")?.toLowerCase() !== "websocket") return null;
|
|
15210
|
+
let url;
|
|
15211
|
+
try {
|
|
15212
|
+
url = new URL(request.url);
|
|
15213
|
+
} catch {
|
|
15214
|
+
return null;
|
|
15215
|
+
}
|
|
15216
|
+
const ticket = url.searchParams.get("ticket");
|
|
15217
|
+
if (!ticket) return null;
|
|
15218
|
+
const authJson = await getAgentBuilder(env).consumeWebSocketTicket({
|
|
15219
|
+
ticket_hash: await hashToken(ticket),
|
|
15220
|
+
pathname: url.pathname
|
|
15221
|
+
});
|
|
15222
|
+
return typeof authJson === "string" ? parseWebSocketTicketAuth(authJson) : null;
|
|
15223
|
+
}
|
|
14881
15224
|
async function authenticate(request, env) {
|
|
15225
|
+
const ticketAuth = await consumeWebSocketTicket(request, env);
|
|
15226
|
+
if (ticketAuth) return ticketAuth;
|
|
14882
15227
|
const token = extractBearerToken(request);
|
|
14883
15228
|
if (!token) {
|
|
14884
15229
|
return null;
|
|
14885
15230
|
}
|
|
14886
|
-
if (env.SUPER_ADMIN_PASSWORD && env.ENCRYPTION_KEY) {
|
|
15231
|
+
if (typeof env.SUPER_ADMIN_PASSWORD === "string" && typeof env.ENCRYPTION_KEY === "string") {
|
|
14887
15232
|
if (token.includes(".")) {
|
|
14888
15233
|
const isValidSuperAdmin = await verifySuperAdminToken(
|
|
14889
15234
|
token,
|
|
14890
15235
|
env.ENCRYPTION_KEY
|
|
14891
15236
|
);
|
|
14892
15237
|
if (isValidSuperAdmin) {
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
15238
|
+
const tokenHash = await hashToken(token);
|
|
15239
|
+
const agentBuilder = getAgentBuilder(env);
|
|
15240
|
+
if (await agentBuilder.validateSuperAdminSession(tokenHash)) {
|
|
15241
|
+
return {
|
|
15242
|
+
user: {
|
|
15243
|
+
id: "super_admin",
|
|
15244
|
+
username: "admin",
|
|
15245
|
+
role: "admin"
|
|
15246
|
+
},
|
|
15247
|
+
authType: "super_admin"
|
|
15248
|
+
};
|
|
15249
|
+
}
|
|
14901
15250
|
}
|
|
14902
15251
|
}
|
|
14903
15252
|
}
|
|
@@ -14942,7 +15291,8 @@ async function authenticate(request, env) {
|
|
|
14942
15291
|
display_name: user.display_name ?? null,
|
|
14943
15292
|
avatar_url: user.avatar_url ?? null
|
|
14944
15293
|
},
|
|
14945
|
-
authType: "api_key"
|
|
15294
|
+
authType: "api_key",
|
|
15295
|
+
credentialId: apiKey.id
|
|
14946
15296
|
};
|
|
14947
15297
|
}
|
|
14948
15298
|
}
|
|
@@ -14954,7 +15304,10 @@ async function requireAuth(request, env) {
|
|
|
14954
15304
|
if (!authContext) {
|
|
14955
15305
|
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
14956
15306
|
status: 401,
|
|
14957
|
-
headers: {
|
|
15307
|
+
headers: {
|
|
15308
|
+
"Content-Type": "application/json",
|
|
15309
|
+
...runtimeCorsHeaders(request, env)
|
|
15310
|
+
}
|
|
14958
15311
|
});
|
|
14959
15312
|
}
|
|
14960
15313
|
return authContext;
|
|
@@ -14969,12 +15322,70 @@ async function requireAdmin(request, env) {
|
|
|
14969
15322
|
JSON.stringify({ error: "Forbidden: Admin access required" }),
|
|
14970
15323
|
{
|
|
14971
15324
|
status: 403,
|
|
14972
|
-
headers: {
|
|
15325
|
+
headers: {
|
|
15326
|
+
"Content-Type": "application/json",
|
|
15327
|
+
...runtimeCorsHeaders(request, env)
|
|
15328
|
+
}
|
|
14973
15329
|
}
|
|
14974
15330
|
);
|
|
14975
15331
|
}
|
|
14976
15332
|
return result;
|
|
14977
15333
|
}
|
|
15334
|
+
function defineController2(controller) {
|
|
15335
|
+
return controller;
|
|
15336
|
+
}
|
|
15337
|
+
function createThreadEndpointHandler(handler) {
|
|
15338
|
+
return (async (context) => {
|
|
15339
|
+
const { req, params, env } = context;
|
|
15340
|
+
const threadId = params.threadId ?? params.id;
|
|
15341
|
+
if (!threadId) {
|
|
15342
|
+
return Response.json({ error: "Thread ID required" }, { status: 400 });
|
|
15343
|
+
}
|
|
15344
|
+
const endpointAuth = {
|
|
15345
|
+
caller: endpointCallerFromAuth(context.auth),
|
|
15346
|
+
threadAccess: Boolean(
|
|
15347
|
+
context.threadAccess && context.threadAccess.threadId === threadId
|
|
15348
|
+
)
|
|
15349
|
+
};
|
|
15350
|
+
try {
|
|
15351
|
+
const agentBuilderId = env.AGENT_BUILDER.idFromName("singleton");
|
|
15352
|
+
const agentBuilder = env.AGENT_BUILDER.get(agentBuilderId);
|
|
15353
|
+
const metadata = await agentBuilder.getThread(threadId);
|
|
15354
|
+
if (!metadata) {
|
|
15355
|
+
return Response.json(
|
|
15356
|
+
{ error: `Thread not found: ${threadId}` },
|
|
15357
|
+
{ status: 404 }
|
|
15358
|
+
);
|
|
15359
|
+
}
|
|
15360
|
+
const meta = metadata;
|
|
15361
|
+
if (!meta.agent_id && meta.agent_name) {
|
|
15362
|
+
meta.agent_id = meta.agent_name;
|
|
15363
|
+
}
|
|
15364
|
+
const durableId = env.AGENT_BUILDER_THREAD.idFromName(threadId);
|
|
15365
|
+
const stub = env.AGENT_BUILDER_THREAD.get(durableId);
|
|
15366
|
+
const instance = stub;
|
|
15367
|
+
const threadState = ThreadStateImpl.fromThreadInstance(instance, metadata, {
|
|
15368
|
+
env
|
|
15369
|
+
});
|
|
15370
|
+
const endpointParams = {};
|
|
15371
|
+
for (const [key, value] of Object.entries(params)) {
|
|
15372
|
+
if (key === "threadId" || key === "id" && !params.threadId) {
|
|
15373
|
+
continue;
|
|
15374
|
+
}
|
|
15375
|
+
endpointParams[key === "_" ? "*" : key] = value;
|
|
15376
|
+
}
|
|
15377
|
+
const response = await handler(req, threadState, endpointParams, endpointAuth);
|
|
15378
|
+
await threadState.flushPendingEventDeliveries();
|
|
15379
|
+
return response;
|
|
15380
|
+
} catch (error) {
|
|
15381
|
+
console.error(`Error in thread endpoint for ${threadId}:`, error);
|
|
15382
|
+
return Response.json(
|
|
15383
|
+
{ error: error.message || "Internal server error" },
|
|
15384
|
+
{ status: 500 }
|
|
15385
|
+
);
|
|
15386
|
+
}
|
|
15387
|
+
});
|
|
15388
|
+
}
|
|
14978
15389
|
|
|
14979
15390
|
// src/utils/permissions.ts
|
|
14980
15391
|
function canAccessThread(auth, thread) {
|
|
@@ -14987,80 +15398,6 @@ function canAccessThread(auth, thread) {
|
|
|
14987
15398
|
return thread.user_id === auth.user.id;
|
|
14988
15399
|
}
|
|
14989
15400
|
|
|
14990
|
-
// src/routing/access-policy.ts
|
|
14991
|
-
var PUBLIC_ROUTES = /* @__PURE__ */ new Set([
|
|
14992
|
-
"/api/auth/bootstrap",
|
|
14993
|
-
"/api/auth/login",
|
|
14994
|
-
"/api/auth/config",
|
|
14995
|
-
"/api/auth/brolly-control",
|
|
14996
|
-
"/api/auth/platform-cleanup",
|
|
14997
|
-
"/api/auth/platform-replica",
|
|
14998
|
-
"/api/auth/sa/start",
|
|
14999
|
-
"/api/auth/sa/callback",
|
|
15000
|
-
"/api/config",
|
|
15001
|
-
"/api/auth/oauth/github",
|
|
15002
|
-
"/api/auth/oauth/google",
|
|
15003
|
-
"/api/auth/oauth/github/callback",
|
|
15004
|
-
"/api/auth/oauth/google/callback",
|
|
15005
|
-
"/api/hooks"
|
|
15006
|
-
]);
|
|
15007
|
-
function isProviderIconRoute(routePath) {
|
|
15008
|
-
return /^\/api\/providers\/[^/]+\/icon$/.test(routePath);
|
|
15009
|
-
}
|
|
15010
|
-
function isPublicThreadFileRoute(routePath, method) {
|
|
15011
|
-
if (method !== "GET" && method !== "HEAD") return false;
|
|
15012
|
-
return /^\/api\/threads\/[^/]+\/public\/.+/.test(routePath);
|
|
15013
|
-
}
|
|
15014
|
-
function isHostedInstance(env) {
|
|
15015
|
-
const value = env?.STANDARD_AGENTS_HOSTED;
|
|
15016
|
-
if (typeof value === "string") {
|
|
15017
|
-
const normalized = value.trim().toLowerCase();
|
|
15018
|
-
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
15019
|
-
}
|
|
15020
|
-
return Boolean(value);
|
|
15021
|
-
}
|
|
15022
|
-
function isTrustedLocalDevelopmentRequest(request, env) {
|
|
15023
|
-
if (isHostedInstance(env)) return false;
|
|
15024
|
-
let hostname;
|
|
15025
|
-
try {
|
|
15026
|
-
hostname = new URL(request.url).hostname.toLowerCase();
|
|
15027
|
-
} catch {
|
|
15028
|
-
return false;
|
|
15029
|
-
}
|
|
15030
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
|
|
15031
|
-
}
|
|
15032
|
-
function isPublicApiRoute(routePath, request, env) {
|
|
15033
|
-
if (PUBLIC_ROUTES.has(routePath)) return true;
|
|
15034
|
-
if (routePath === "/api/auth/device/start" || routePath.startsWith("/api/auth/device/")) {
|
|
15035
|
-
return true;
|
|
15036
|
-
}
|
|
15037
|
-
if (isProviderIconRoute(routePath)) {
|
|
15038
|
-
return true;
|
|
15039
|
-
}
|
|
15040
|
-
if (isPublicThreadFileRoute(routePath, request.method.toUpperCase())) {
|
|
15041
|
-
return true;
|
|
15042
|
-
}
|
|
15043
|
-
if (!isTrustedLocalDevelopmentRequest(request, env)) return false;
|
|
15044
|
-
return routePath === "/api/threads" || routePath.startsWith("/api/threads/") || routePath === "/api/platform" || routePath.startsWith("/api/platform/") || routePath === "/api/platform-session" || routePath.startsWith("/api/platform-session/") || routePath === "/api/platform-auth" || routePath.startsWith("/api/platform-auth/");
|
|
15045
|
-
}
|
|
15046
|
-
function isAdminOnlyApiRoute(routePath, method = "GET") {
|
|
15047
|
-
if (routePath === "/api/skills" || routePath.startsWith("/api/skills/")) return true;
|
|
15048
|
-
if (routePath === "/api/pack" || routePath.startsWith("/api/pack/")) return true;
|
|
15049
|
-
if (routePath === "/api/unpack" || routePath.startsWith("/api/unpack/")) return true;
|
|
15050
|
-
if (routePath === "/api/prompts" || routePath.startsWith("/api/prompts/")) return true;
|
|
15051
|
-
if (routePath === "/api/tools" || routePath.startsWith("/api/tools/")) return true;
|
|
15052
|
-
if (routePath === "/api/models" || routePath.startsWith("/api/models/")) return true;
|
|
15053
|
-
if (routePath === "/api/providers") return true;
|
|
15054
|
-
if (routePath.startsWith("/api/providers/")) {
|
|
15055
|
-
return !isProviderIconRoute(routePath);
|
|
15056
|
-
}
|
|
15057
|
-
if (routePath.startsWith("/api/agents/")) {
|
|
15058
|
-
return !/^\/api\/agents\/[^/]+\/tenvs$/.test(routePath);
|
|
15059
|
-
}
|
|
15060
|
-
if (routePath === "/api/agents" && method.toUpperCase() !== "GET") return true;
|
|
15061
|
-
return false;
|
|
15062
|
-
}
|
|
15063
|
-
|
|
15064
15401
|
// src/runtime.ts
|
|
15065
15402
|
init_client_forwarding();
|
|
15066
15403
|
|
|
@@ -15973,8 +16310,37 @@ var migration35 = {
|
|
|
15973
16310
|
}
|
|
15974
16311
|
};
|
|
15975
16312
|
|
|
16313
|
+
// src/durable-objects/migrations/036_add_tool_delivery_tokens.ts
|
|
16314
|
+
var migration36 = {
|
|
16315
|
+
version: 36,
|
|
16316
|
+
name: "add_tool_delivery_tokens",
|
|
16317
|
+
async up(sql) {
|
|
16318
|
+
sql.exec(`
|
|
16319
|
+
CREATE TABLE IF NOT EXISTS pending_client_calls (
|
|
16320
|
+
tool_call_id TEXT PRIMARY KEY,
|
|
16321
|
+
tool TEXT NOT NULL,
|
|
16322
|
+
args TEXT,
|
|
16323
|
+
request_permission TEXT,
|
|
16324
|
+
risk INTEGER,
|
|
16325
|
+
side TEXT NOT NULL DEFAULT 'a',
|
|
16326
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
16327
|
+
created_at INTEGER NOT NULL,
|
|
16328
|
+
dispatched_client_id TEXT,
|
|
16329
|
+
dispatched_generation INTEGER NOT NULL DEFAULT 0
|
|
16330
|
+
)
|
|
16331
|
+
`);
|
|
16332
|
+
const columns = sql.exec(
|
|
16333
|
+
`PRAGMA table_info(pending_client_calls)`
|
|
16334
|
+
).toArray();
|
|
16335
|
+
if (!columns.some((column) => column.name === "delivery_token_hash")) {
|
|
16336
|
+
sql.exec(`ALTER TABLE pending_client_calls ADD COLUMN delivery_token_hash TEXT`);
|
|
16337
|
+
}
|
|
16338
|
+
sql.exec(`UPDATE _metadata SET value = '36' WHERE key = 'schema_version'`);
|
|
16339
|
+
}
|
|
16340
|
+
};
|
|
16341
|
+
|
|
15976
16342
|
// src/durable-objects/migrations/index.ts
|
|
15977
|
-
var migrations = [migration, migration2, migration3, migration4, migration5, migration6, migration7, migration8, migration9, migration10, migration11, migration12, migration13, migration14, migration15, migration16, migration17, migration18, migration19, migration20, migration21, migration22, migration23, migration24, migration25, migration26, migration27, migration28, migration29, migration30, migration31, migration32, migration33, migration34, migration35];
|
|
16343
|
+
var migrations = [migration, migration2, migration3, migration4, migration5, migration6, migration7, migration8, migration9, migration10, migration11, migration12, migration13, migration14, migration15, migration16, migration17, migration18, migration19, migration20, migration21, migration22, migration23, migration24, migration25, migration26, migration27, migration28, migration29, migration30, migration31, migration32, migration33, migration34, migration35, migration36];
|
|
15978
16344
|
var LATEST_SCHEMA_VERSION = migrations.length;
|
|
15979
16345
|
|
|
15980
16346
|
// src/durable-objects/subagent-reconcile.ts
|
|
@@ -16810,7 +17176,7 @@ function eventSocketCanReceive(attachment, ownerUserId) {
|
|
|
16810
17176
|
}
|
|
16811
17177
|
|
|
16812
17178
|
// src/durable-objects/agentbuilder-migrations/0001_initial.ts
|
|
16813
|
-
var
|
|
17179
|
+
var migration37 = {
|
|
16814
17180
|
version: 1,
|
|
16815
17181
|
async up(sql) {
|
|
16816
17182
|
sql.exec(`
|
|
@@ -16909,7 +17275,7 @@ var migration36 = {
|
|
|
16909
17275
|
};
|
|
16910
17276
|
|
|
16911
17277
|
// src/durable-objects/agentbuilder-migrations/0002_add_tenvs_properties.ts
|
|
16912
|
-
var
|
|
17278
|
+
var migration38 = {
|
|
16913
17279
|
version: 2,
|
|
16914
17280
|
async up(sql) {
|
|
16915
17281
|
sql.exec(`ALTER TABLE threads ADD COLUMN tenvs TEXT`);
|
|
@@ -16921,7 +17287,7 @@ var migration37 = {
|
|
|
16921
17287
|
};
|
|
16922
17288
|
|
|
16923
17289
|
// src/durable-objects/agentbuilder-migrations/0003_add_parent_and_terminated.ts
|
|
16924
|
-
var
|
|
17290
|
+
var migration39 = {
|
|
16925
17291
|
version: 3,
|
|
16926
17292
|
async up(sql) {
|
|
16927
17293
|
sql.exec(`ALTER TABLE threads ADD COLUMN parent TEXT REFERENCES threads(id)`);
|
|
@@ -16934,7 +17300,7 @@ var migration38 = {
|
|
|
16934
17300
|
};
|
|
16935
17301
|
|
|
16936
17302
|
// src/durable-objects/agentbuilder-migrations/0004_add_env_tables.ts
|
|
16937
|
-
var
|
|
17303
|
+
var migration40 = {
|
|
16938
17304
|
version: 4,
|
|
16939
17305
|
async up(sql) {
|
|
16940
17306
|
sql.exec(`ALTER TABLE threads ADD COLUMN env TEXT`);
|
|
@@ -16958,7 +17324,7 @@ var migration39 = {
|
|
|
16958
17324
|
};
|
|
16959
17325
|
|
|
16960
17326
|
// src/durable-objects/agentbuilder-migrations/0005_add_pending_subagent_env_requests.ts
|
|
16961
|
-
var
|
|
17327
|
+
var migration41 = {
|
|
16962
17328
|
version: 5,
|
|
16963
17329
|
async up(sql) {
|
|
16964
17330
|
sql.exec(`
|
|
@@ -16984,7 +17350,7 @@ var migration40 = {
|
|
|
16984
17350
|
};
|
|
16985
17351
|
|
|
16986
17352
|
// src/durable-objects/agentbuilder-migrations/0006_add_env_value_types.ts
|
|
16987
|
-
var
|
|
17353
|
+
var migration42 = {
|
|
16988
17354
|
version: 6,
|
|
16989
17355
|
async up(sql) {
|
|
16990
17356
|
sql.exec(
|
|
@@ -16999,7 +17365,7 @@ var migration41 = {
|
|
|
16999
17365
|
};
|
|
17000
17366
|
|
|
17001
17367
|
// src/durable-objects/agentbuilder-migrations/0007_platform_identity_replica.ts
|
|
17002
|
-
var
|
|
17368
|
+
var migration43 = {
|
|
17003
17369
|
version: 7,
|
|
17004
17370
|
async up(sql) {
|
|
17005
17371
|
sql.exec(`ALTER TABLE users ADD COLUMN platform_user_id TEXT`);
|
|
@@ -17028,7 +17394,7 @@ var migration42 = {
|
|
|
17028
17394
|
};
|
|
17029
17395
|
|
|
17030
17396
|
// src/durable-objects/agentbuilder-migrations/0008_add_skills.ts
|
|
17031
|
-
var
|
|
17397
|
+
var migration44 = {
|
|
17032
17398
|
version: 8,
|
|
17033
17399
|
async up(sql) {
|
|
17034
17400
|
sql.exec(`
|
|
@@ -17059,7 +17425,7 @@ var migration43 = {
|
|
|
17059
17425
|
};
|
|
17060
17426
|
|
|
17061
17427
|
// src/durable-objects/agentbuilder-migrations/0009_add_user_permissions.ts
|
|
17062
|
-
var
|
|
17428
|
+
var migration45 = {
|
|
17063
17429
|
version: 9,
|
|
17064
17430
|
async up(sql) {
|
|
17065
17431
|
sql.exec(`ALTER TABLE users ADD COLUMN permissions TEXT`);
|
|
@@ -17070,7 +17436,7 @@ var migration44 = {
|
|
|
17070
17436
|
};
|
|
17071
17437
|
|
|
17072
17438
|
// src/durable-objects/agentbuilder-migrations/0010_add_device_logins.ts
|
|
17073
|
-
var
|
|
17439
|
+
var migration46 = {
|
|
17074
17440
|
version: 10,
|
|
17075
17441
|
async up(sql) {
|
|
17076
17442
|
sql.exec(`
|
|
@@ -17090,7 +17456,7 @@ var migration45 = {
|
|
|
17090
17456
|
};
|
|
17091
17457
|
|
|
17092
17458
|
// src/durable-objects/agentbuilder-migrations/0011_add_user_values.ts
|
|
17093
|
-
var
|
|
17459
|
+
var migration47 = {
|
|
17094
17460
|
version: 11,
|
|
17095
17461
|
async up(sql) {
|
|
17096
17462
|
sql.exec(`
|
|
@@ -17113,7 +17479,7 @@ var migration46 = {
|
|
|
17113
17479
|
};
|
|
17114
17480
|
|
|
17115
17481
|
// src/durable-objects/agentbuilder-migrations/0012_allow_api_instance_role.ts
|
|
17116
|
-
var
|
|
17482
|
+
var migration48 = {
|
|
17117
17483
|
version: 12,
|
|
17118
17484
|
async up(sql) {
|
|
17119
17485
|
sql.exec(`CREATE TABLE oauth_accounts_0012_backup AS SELECT * FROM oauth_accounts`);
|
|
@@ -17223,7 +17589,7 @@ var migration47 = {
|
|
|
17223
17589
|
};
|
|
17224
17590
|
|
|
17225
17591
|
// src/durable-objects/agentbuilder-migrations/0013_add_thread_activity.ts
|
|
17226
|
-
var
|
|
17592
|
+
var migration49 = {
|
|
17227
17593
|
version: 13,
|
|
17228
17594
|
async up(sql) {
|
|
17229
17595
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_activity_at INTEGER`);
|
|
@@ -17239,7 +17605,7 @@ var migration48 = {
|
|
|
17239
17605
|
};
|
|
17240
17606
|
|
|
17241
17607
|
// src/durable-objects/agentbuilder-migrations/0014_thread_activity_scale.ts
|
|
17242
|
-
var
|
|
17608
|
+
var migration50 = {
|
|
17243
17609
|
version: 14,
|
|
17244
17610
|
async up(sql) {
|
|
17245
17611
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_message_preview TEXT`);
|
|
@@ -17257,7 +17623,7 @@ var migration49 = {
|
|
|
17257
17623
|
};
|
|
17258
17624
|
|
|
17259
17625
|
// src/durable-objects/agentbuilder-migrations/0015_clear_envelope_previews.ts
|
|
17260
|
-
var
|
|
17626
|
+
var migration51 = {
|
|
17261
17627
|
version: 15,
|
|
17262
17628
|
async up(sql) {
|
|
17263
17629
|
sql.exec(
|
|
@@ -17271,7 +17637,7 @@ var migration50 = {
|
|
|
17271
17637
|
};
|
|
17272
17638
|
|
|
17273
17639
|
// src/durable-objects/agentbuilder-migrations/0016_add_origin_agent.ts
|
|
17274
|
-
var
|
|
17640
|
+
var migration52 = {
|
|
17275
17641
|
version: 16,
|
|
17276
17642
|
async up(sql) {
|
|
17277
17643
|
sql.exec(`ALTER TABLE threads ADD COLUMN origin_agent_name TEXT`);
|
|
@@ -17286,7 +17652,7 @@ var migration51 = {
|
|
|
17286
17652
|
};
|
|
17287
17653
|
|
|
17288
17654
|
// src/durable-objects/agentbuilder-migrations/0017_add_thread_message_recency.ts
|
|
17289
|
-
var
|
|
17655
|
+
var migration53 = {
|
|
17290
17656
|
version: 17,
|
|
17291
17657
|
async up(sql) {
|
|
17292
17658
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_message_at INTEGER`);
|
|
@@ -17297,10 +17663,132 @@ var migration52 = {
|
|
|
17297
17663
|
}
|
|
17298
17664
|
};
|
|
17299
17665
|
|
|
17666
|
+
// src/durable-objects/agentbuilder-migrations/0018_auth_security.ts
|
|
17667
|
+
var migration54 = {
|
|
17668
|
+
version: 18,
|
|
17669
|
+
async up(sql) {
|
|
17670
|
+
sql.exec(`
|
|
17671
|
+
CREATE TABLE IF NOT EXISTS super_admin_sessions (
|
|
17672
|
+
token_hash TEXT PRIMARY KEY,
|
|
17673
|
+
created_at INTEGER NOT NULL,
|
|
17674
|
+
expires_at INTEGER NOT NULL
|
|
17675
|
+
)
|
|
17676
|
+
`);
|
|
17677
|
+
sql.exec(`
|
|
17678
|
+
CREATE INDEX IF NOT EXISTS idx_super_admin_sessions_expires
|
|
17679
|
+
ON super_admin_sessions(expires_at)
|
|
17680
|
+
`);
|
|
17681
|
+
sql.exec(`
|
|
17682
|
+
CREATE TABLE IF NOT EXISTS auth_rate_limits (
|
|
17683
|
+
bucket_key TEXT PRIMARY KEY,
|
|
17684
|
+
attempts INTEGER NOT NULL,
|
|
17685
|
+
reset_at INTEGER NOT NULL
|
|
17686
|
+
)
|
|
17687
|
+
`);
|
|
17688
|
+
sql.exec(`
|
|
17689
|
+
CREATE INDEX IF NOT EXISTS idx_auth_rate_limits_reset
|
|
17690
|
+
ON auth_rate_limits(reset_at)
|
|
17691
|
+
`);
|
|
17692
|
+
sql.exec(`
|
|
17693
|
+
INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '18')
|
|
17694
|
+
`);
|
|
17695
|
+
}
|
|
17696
|
+
};
|
|
17697
|
+
|
|
17698
|
+
// src/durable-objects/agentbuilder-migrations/0019_scope_skills.ts
|
|
17699
|
+
var migration55 = {
|
|
17700
|
+
version: 19,
|
|
17701
|
+
async up(sql) {
|
|
17702
|
+
sql.exec(`
|
|
17703
|
+
CREATE TABLE skills_0019 (
|
|
17704
|
+
owner_id TEXT NOT NULL,
|
|
17705
|
+
name TEXT NOT NULL,
|
|
17706
|
+
description TEXT NOT NULL,
|
|
17707
|
+
version TEXT,
|
|
17708
|
+
enabled INTEGER NOT NULL DEFAULT 1,
|
|
17709
|
+
shared INTEGER NOT NULL DEFAULT 0,
|
|
17710
|
+
created_at INTEGER DEFAULT (strftime('%s', 'now')),
|
|
17711
|
+
updated_at INTEGER DEFAULT (strftime('%s', 'now')),
|
|
17712
|
+
PRIMARY KEY (owner_id, name)
|
|
17713
|
+
)
|
|
17714
|
+
`);
|
|
17715
|
+
sql.exec(`
|
|
17716
|
+
INSERT INTO skills_0019 (
|
|
17717
|
+
owner_id, name, description, version, enabled, shared, created_at, updated_at
|
|
17718
|
+
)
|
|
17719
|
+
SELECT '__instance_shared__', name, description, version, enabled, 1, created_at, updated_at
|
|
17720
|
+
FROM skills
|
|
17721
|
+
`);
|
|
17722
|
+
sql.exec(`
|
|
17723
|
+
CREATE TABLE skill_files_0019 (
|
|
17724
|
+
owner_id TEXT NOT NULL,
|
|
17725
|
+
skill_name TEXT NOT NULL,
|
|
17726
|
+
path TEXT NOT NULL,
|
|
17727
|
+
content TEXT NOT NULL,
|
|
17728
|
+
size INTEGER NOT NULL,
|
|
17729
|
+
PRIMARY KEY (owner_id, skill_name, path),
|
|
17730
|
+
FOREIGN KEY (owner_id, skill_name) REFERENCES skills_0019(owner_id, name) ON DELETE CASCADE
|
|
17731
|
+
)
|
|
17732
|
+
`);
|
|
17733
|
+
sql.exec(`
|
|
17734
|
+
INSERT INTO skill_files_0019 (owner_id, skill_name, path, content, size)
|
|
17735
|
+
SELECT '__instance_shared__', skill_name, path, content, size FROM skill_files
|
|
17736
|
+
`);
|
|
17737
|
+
sql.exec(`DROP TABLE skill_files`);
|
|
17738
|
+
sql.exec(`DROP TABLE skills`);
|
|
17739
|
+
sql.exec(`ALTER TABLE skills_0019 RENAME TO skills`);
|
|
17740
|
+
sql.exec(`ALTER TABLE skill_files_0019 RENAME TO skill_files`);
|
|
17741
|
+
sql.exec(`CREATE INDEX idx_skills_owner_enabled ON skills(owner_id, enabled)`);
|
|
17742
|
+
sql.exec(`CREATE INDEX idx_skills_shared_enabled ON skills(shared, enabled)`);
|
|
17743
|
+
sql.exec(`CREATE INDEX idx_skill_files_skill ON skill_files(owner_id, skill_name)`);
|
|
17744
|
+
sql.exec(`INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '19')`);
|
|
17745
|
+
}
|
|
17746
|
+
};
|
|
17747
|
+
|
|
17748
|
+
// src/durable-objects/agentbuilder-migrations/0020_websocket_tickets.ts
|
|
17749
|
+
var migration56 = {
|
|
17750
|
+
version: 20,
|
|
17751
|
+
async up(sql) {
|
|
17752
|
+
sql.exec(`
|
|
17753
|
+
CREATE TABLE websocket_tickets (
|
|
17754
|
+
ticket_hash TEXT PRIMARY KEY,
|
|
17755
|
+
pathname TEXT NOT NULL,
|
|
17756
|
+
auth_json TEXT NOT NULL,
|
|
17757
|
+
created_at INTEGER NOT NULL,
|
|
17758
|
+
expires_at INTEGER NOT NULL
|
|
17759
|
+
)
|
|
17760
|
+
`);
|
|
17761
|
+
sql.exec(`
|
|
17762
|
+
CREATE INDEX idx_websocket_tickets_expires
|
|
17763
|
+
ON websocket_tickets(expires_at)
|
|
17764
|
+
`);
|
|
17765
|
+
sql.exec(`INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '20')`);
|
|
17766
|
+
}
|
|
17767
|
+
};
|
|
17768
|
+
|
|
17769
|
+
// src/durable-objects/agentbuilder-migrations/0021_platform_handoff_jtis.ts
|
|
17770
|
+
var migration57 = {
|
|
17771
|
+
version: 21,
|
|
17772
|
+
async up(sql) {
|
|
17773
|
+
sql.exec(`
|
|
17774
|
+
CREATE TABLE platform_handoff_jtis (
|
|
17775
|
+
jti TEXT PRIMARY KEY,
|
|
17776
|
+
consumed_at INTEGER NOT NULL,
|
|
17777
|
+
expires_at INTEGER NOT NULL
|
|
17778
|
+
)
|
|
17779
|
+
`);
|
|
17780
|
+
sql.exec(`
|
|
17781
|
+
CREATE INDEX idx_platform_handoff_jtis_expires
|
|
17782
|
+
ON platform_handoff_jtis(expires_at)
|
|
17783
|
+
`);
|
|
17784
|
+
sql.exec(`INSERT OR REPLACE INTO _metadata (key, value) VALUES ('schema_version', '21')`);
|
|
17785
|
+
}
|
|
17786
|
+
};
|
|
17787
|
+
|
|
17300
17788
|
// src/durable-objects/agentbuilder-migrations/index.ts
|
|
17301
|
-
var migrations2 = [
|
|
17789
|
+
var migrations2 = [migration37, migration38, migration39, migration40, migration41, migration42, migration43, migration44, migration45, migration46, migration47, migration48, migration49, migration50, migration51, migration52, migration53, migration54, migration55, migration56, migration57];
|
|
17302
17790
|
var LATEST_SCHEMA_VERSION2 = migrations2.reduce(
|
|
17303
|
-
(max,
|
|
17791
|
+
(max, migration58) => Math.max(max, migration58.version),
|
|
17304
17792
|
0
|
|
17305
17793
|
);
|
|
17306
17794
|
|
|
@@ -17805,6 +18293,7 @@ function validateSkillFiles(files) {
|
|
|
17805
18293
|
}
|
|
17806
18294
|
|
|
17807
18295
|
// src/durable-objects/DurableAgentBuilder.ts
|
|
18296
|
+
init_scope();
|
|
17808
18297
|
var ENV_TYPES_PROPERTY = "__agentbuilder_env_types";
|
|
17809
18298
|
function parseStoredPermissions(value) {
|
|
17810
18299
|
if (typeof value !== "string" || !value.trim()) return null;
|
|
@@ -18397,9 +18886,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
18397
18886
|
}
|
|
18398
18887
|
}
|
|
18399
18888
|
async runMigrations(fromVersion) {
|
|
18400
|
-
for (const
|
|
18401
|
-
if (
|
|
18402
|
-
await
|
|
18889
|
+
for (const migration58 of migrations2) {
|
|
18890
|
+
if (migration58.version > fromVersion) {
|
|
18891
|
+
await migration58.up(this.ctx.storage.sql);
|
|
18403
18892
|
}
|
|
18404
18893
|
}
|
|
18405
18894
|
}
|
|
@@ -20348,6 +20837,150 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20348
20837
|
tokenHash
|
|
20349
20838
|
);
|
|
20350
20839
|
}
|
|
20840
|
+
/** Register a short-lived super-admin token so it can be revoked alone. */
|
|
20841
|
+
async createSuperAdminSession(params) {
|
|
20842
|
+
await this.ensureMigrated();
|
|
20843
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20844
|
+
await this.ctx.storage.sql.exec(
|
|
20845
|
+
`DELETE FROM super_admin_sessions WHERE expires_at <= ?`,
|
|
20846
|
+
now
|
|
20847
|
+
);
|
|
20848
|
+
await this.ctx.storage.sql.exec(
|
|
20849
|
+
`INSERT INTO super_admin_sessions (token_hash, created_at, expires_at)
|
|
20850
|
+
VALUES (?, ?, ?)`,
|
|
20851
|
+
params.token_hash,
|
|
20852
|
+
now,
|
|
20853
|
+
params.expires_at
|
|
20854
|
+
);
|
|
20855
|
+
}
|
|
20856
|
+
/** A valid signature is insufficient: the session must still be registered. */
|
|
20857
|
+
async validateSuperAdminSession(tokenHash) {
|
|
20858
|
+
await this.ensureMigrated();
|
|
20859
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20860
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
20861
|
+
`SELECT 1 AS found FROM super_admin_sessions
|
|
20862
|
+
WHERE token_hash = ? AND expires_at > ?`,
|
|
20863
|
+
tokenHash,
|
|
20864
|
+
now
|
|
20865
|
+
);
|
|
20866
|
+
return cursor.toArray().length > 0;
|
|
20867
|
+
}
|
|
20868
|
+
/** Revoke only the presented super-admin session; no key rotation required. */
|
|
20869
|
+
async deleteSuperAdminSession(tokenHash) {
|
|
20870
|
+
await this.ensureMigrated();
|
|
20871
|
+
await this.ctx.storage.sql.exec(
|
|
20872
|
+
`DELETE FROM super_admin_sessions WHERE token_hash = ?`,
|
|
20873
|
+
tokenHash
|
|
20874
|
+
);
|
|
20875
|
+
}
|
|
20876
|
+
/** Register a path-bound bearer ticket for one WebSocket handshake. */
|
|
20877
|
+
async createWebSocketTicket(params) {
|
|
20878
|
+
await this.ensureMigrated();
|
|
20879
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20880
|
+
this.ctx.storage.sql.exec(
|
|
20881
|
+
`DELETE FROM websocket_tickets WHERE expires_at <= ?`,
|
|
20882
|
+
now
|
|
20883
|
+
);
|
|
20884
|
+
this.ctx.storage.sql.exec(
|
|
20885
|
+
`INSERT INTO websocket_tickets (ticket_hash, pathname, auth_json, created_at, expires_at)
|
|
20886
|
+
VALUES (?, ?, ?, ?, ?)`,
|
|
20887
|
+
params.ticket_hash,
|
|
20888
|
+
params.pathname,
|
|
20889
|
+
params.auth_json,
|
|
20890
|
+
now,
|
|
20891
|
+
params.expires_at
|
|
20892
|
+
);
|
|
20893
|
+
}
|
|
20894
|
+
/**
|
|
20895
|
+
* Atomically consume a WebSocket ticket. Deleting before validating its path
|
|
20896
|
+
* means even a mistaken or malicious first presentation burns the bearer.
|
|
20897
|
+
*/
|
|
20898
|
+
async consumeWebSocketTicket(params) {
|
|
20899
|
+
await this.ensureMigrated();
|
|
20900
|
+
const cursor = this.ctx.storage.sql.exec(
|
|
20901
|
+
`DELETE FROM websocket_tickets
|
|
20902
|
+
WHERE ticket_hash = ?
|
|
20903
|
+
RETURNING pathname, auth_json, expires_at`,
|
|
20904
|
+
params.ticket_hash
|
|
20905
|
+
);
|
|
20906
|
+
const ticket = cursor.toArray()[0];
|
|
20907
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20908
|
+
if (!ticket || ticket.expires_at <= now || ticket.pathname !== params.pathname) {
|
|
20909
|
+
return null;
|
|
20910
|
+
}
|
|
20911
|
+
return ticket.auth_json;
|
|
20912
|
+
}
|
|
20913
|
+
/** Atomically accept an unexpired platform handoff identifier once. */
|
|
20914
|
+
async consumePlatformHandoffJti(params) {
|
|
20915
|
+
await this.ensureMigrated();
|
|
20916
|
+
const jti = params.jti.trim();
|
|
20917
|
+
const expiresAt = Math.floor(params.expires_at);
|
|
20918
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20919
|
+
if (!jti || jti.length > 200 || !Number.isSafeInteger(expiresAt) || expiresAt <= now) {
|
|
20920
|
+
return false;
|
|
20921
|
+
}
|
|
20922
|
+
this.ctx.storage.sql.exec(
|
|
20923
|
+
`DELETE FROM platform_handoff_jtis WHERE expires_at <= ?`,
|
|
20924
|
+
now
|
|
20925
|
+
);
|
|
20926
|
+
const cursor = this.ctx.storage.sql.exec(
|
|
20927
|
+
`INSERT OR IGNORE INTO platform_handoff_jtis (jti, consumed_at, expires_at)
|
|
20928
|
+
VALUES (?, ?, ?)`,
|
|
20929
|
+
jti,
|
|
20930
|
+
now,
|
|
20931
|
+
expiresAt
|
|
20932
|
+
);
|
|
20933
|
+
return cursor.rowsWritten > 0;
|
|
20934
|
+
}
|
|
20935
|
+
/**
|
|
20936
|
+
* Atomically consume one attempt from a fixed-window authentication bucket.
|
|
20937
|
+
* The singleton Durable Object serializes calls, preventing parallel bypass.
|
|
20938
|
+
*/
|
|
20939
|
+
async consumeAuthRateLimit(params) {
|
|
20940
|
+
await this.ensureMigrated();
|
|
20941
|
+
const key = params.key.trim();
|
|
20942
|
+
const limit = Math.floor(params.limit);
|
|
20943
|
+
const windowSeconds = Math.floor(params.window_seconds);
|
|
20944
|
+
if (!key || key.length > 160 || limit < 1 || limit > 1e4 || windowSeconds < 1 || windowSeconds > 86400) {
|
|
20945
|
+
throw new Error("Invalid authentication rate-limit bucket");
|
|
20946
|
+
}
|
|
20947
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
20948
|
+
await this.ctx.storage.sql.exec(
|
|
20949
|
+
`DELETE FROM auth_rate_limits WHERE reset_at <= ?`,
|
|
20950
|
+
now
|
|
20951
|
+
);
|
|
20952
|
+
const cursor = await this.ctx.storage.sql.exec(
|
|
20953
|
+
`SELECT attempts, reset_at FROM auth_rate_limits WHERE bucket_key = ?`,
|
|
20954
|
+
key
|
|
20955
|
+
);
|
|
20956
|
+
const current = cursor.toArray()[0];
|
|
20957
|
+
if (!current || current.reset_at <= now) {
|
|
20958
|
+
const resetAt = now + windowSeconds;
|
|
20959
|
+
await this.ctx.storage.sql.exec(
|
|
20960
|
+
`INSERT INTO auth_rate_limits (bucket_key, attempts, reset_at)
|
|
20961
|
+
VALUES (?, 1, ?)
|
|
20962
|
+
ON CONFLICT(bucket_key) DO UPDATE SET attempts = 1, reset_at = excluded.reset_at`,
|
|
20963
|
+
key,
|
|
20964
|
+
resetAt
|
|
20965
|
+
);
|
|
20966
|
+
return { allowed: true, retry_after: windowSeconds, remaining: limit - 1 };
|
|
20967
|
+
}
|
|
20968
|
+
const retryAfter = Math.max(1, current.reset_at - now);
|
|
20969
|
+
if (current.attempts >= limit) {
|
|
20970
|
+
return { allowed: false, retry_after: retryAfter, remaining: 0 };
|
|
20971
|
+
}
|
|
20972
|
+
const attempts = current.attempts + 1;
|
|
20973
|
+
await this.ctx.storage.sql.exec(
|
|
20974
|
+
`UPDATE auth_rate_limits SET attempts = ? WHERE bucket_key = ?`,
|
|
20975
|
+
attempts,
|
|
20976
|
+
key
|
|
20977
|
+
);
|
|
20978
|
+
return {
|
|
20979
|
+
allowed: true,
|
|
20980
|
+
retry_after: retryAfter,
|
|
20981
|
+
remaining: Math.max(0, limit - attempts)
|
|
20982
|
+
};
|
|
20983
|
+
}
|
|
20351
20984
|
// ============================================================
|
|
20352
20985
|
// API Key Methods
|
|
20353
20986
|
// ============================================================
|
|
@@ -20665,40 +21298,61 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20665
21298
|
}
|
|
20666
21299
|
}
|
|
20667
21300
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20668
|
-
// Skills —
|
|
20669
|
-
// Installed once, visible to every thread; file contents live here so
|
|
20670
|
-
// nothing about a skill is stored on a client machine.
|
|
21301
|
+
// Skills — owner-scoped Agent Skills plus explicitly shared admin skills.
|
|
20671
21302
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20672
21303
|
/** Installed skills, metadata only (no file contents). */
|
|
20673
|
-
async listSkills(options = {}) {
|
|
21304
|
+
async listSkills(scope, options = {}) {
|
|
20674
21305
|
await this.ensureMigrated();
|
|
20675
|
-
const where = options.includeDisabled ? "" : "WHERE enabled = 1";
|
|
20676
21306
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20677
21307
|
`SELECT s.name, s.description, s.version, s.enabled, s.updated_at,
|
|
20678
|
-
|
|
20679
|
-
|
|
21308
|
+
s.owner_id,
|
|
21309
|
+
(SELECT json_group_array(f.path) FROM skill_files f
|
|
21310
|
+
WHERE f.owner_id = s.owner_id AND f.skill_name = s.name) AS files
|
|
21311
|
+
FROM skills s
|
|
21312
|
+
WHERE (s.owner_id = ? OR (? = 1 AND s.shared = 1))
|
|
21313
|
+
AND (? = 1 OR s.enabled = 1)
|
|
21314
|
+
ORDER BY s.name, CASE WHEN s.owner_id = ? THEN 0 ELSE 1 END`,
|
|
21315
|
+
scope.ownerId,
|
|
21316
|
+
scope.includeShared ? 1 : 0,
|
|
21317
|
+
options.includeDisabled ? 1 : 0,
|
|
21318
|
+
scope.ownerId
|
|
20680
21319
|
);
|
|
20681
|
-
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
|
|
20686
|
-
|
|
20687
|
-
|
|
20688
|
-
|
|
21320
|
+
const skills = /* @__PURE__ */ new Map();
|
|
21321
|
+
for (const row of cursor.toArray()) {
|
|
21322
|
+
if (skills.has(row.name)) continue;
|
|
21323
|
+
const parsedFiles = row.files ? JSON.parse(row.files) : [];
|
|
21324
|
+
const files = Array.isArray(parsedFiles) ? parsedFiles.filter((path) => typeof path === "string").sort() : [];
|
|
21325
|
+
skills.set(row.name, {
|
|
21326
|
+
name: row.name,
|
|
21327
|
+
description: row.description,
|
|
21328
|
+
version: row.version ?? void 0,
|
|
21329
|
+
enabled: row.enabled === 1,
|
|
21330
|
+
files,
|
|
21331
|
+
updatedAt: row.updated_at
|
|
21332
|
+
});
|
|
21333
|
+
}
|
|
21334
|
+
return [...skills.values()];
|
|
20689
21335
|
}
|
|
20690
21336
|
/** One skill's metadata (null when not installed). */
|
|
20691
|
-
async getSkill(name) {
|
|
20692
|
-
const all = await this.listSkills({ includeDisabled: true });
|
|
21337
|
+
async getSkill(scope, name) {
|
|
21338
|
+
const all = await this.listSkills(scope, { includeDisabled: true });
|
|
20693
21339
|
return all.find((s) => s.name === name) ?? null;
|
|
20694
21340
|
}
|
|
20695
21341
|
/** One bundled file's text (null when the skill or file is missing). */
|
|
20696
|
-
async getSkillFile(name, path) {
|
|
21342
|
+
async getSkillFile(scope, name, path) {
|
|
20697
21343
|
await this.ensureMigrated();
|
|
20698
21344
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20699
|
-
`SELECT content FROM skill_files
|
|
21345
|
+
`SELECT f.content FROM skill_files f
|
|
21346
|
+
JOIN skills s ON s.owner_id = f.owner_id AND s.name = f.skill_name
|
|
21347
|
+
WHERE f.skill_name = ? AND f.path = ?
|
|
21348
|
+
AND (f.owner_id = ? OR (? = 1 AND s.shared = 1))
|
|
21349
|
+
ORDER BY CASE WHEN f.owner_id = ? THEN 0 ELSE 1 END
|
|
21350
|
+
LIMIT 1`,
|
|
20700
21351
|
name,
|
|
20701
|
-
path.replace(/^\.\//, "")
|
|
21352
|
+
path.replace(/^\.\//, ""),
|
|
21353
|
+
scope.ownerId,
|
|
21354
|
+
scope.includeShared ? 1 : 0,
|
|
21355
|
+
scope.ownerId
|
|
20702
21356
|
);
|
|
20703
21357
|
const rows = cursor.toArray();
|
|
20704
21358
|
return rows.length ? rows[0].content : null;
|
|
@@ -20709,44 +21363,56 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20709
21363
|
* that frontmatter. Throws SkillValidationError with an actionable message
|
|
20710
21364
|
* on any standard violation.
|
|
20711
21365
|
*/
|
|
20712
|
-
async upsertSkill(files) {
|
|
21366
|
+
async upsertSkill(scope, files) {
|
|
20713
21367
|
await this.ensureMigrated();
|
|
20714
21368
|
const frontmatter = validateSkillFiles(files);
|
|
20715
21369
|
const name = frontmatter.name;
|
|
20716
|
-
const
|
|
20717
|
-
await this.
|
|
21370
|
+
const ownScope = { ownerId: scope.ownerId };
|
|
21371
|
+
const existing = await this.getSkill(ownScope, name);
|
|
21372
|
+
await this.ctx.storage.sql.exec(
|
|
21373
|
+
`DELETE FROM skill_files WHERE owner_id = ? AND skill_name = ?`,
|
|
21374
|
+
scope.ownerId,
|
|
21375
|
+
name
|
|
21376
|
+
);
|
|
20718
21377
|
await this.ctx.storage.sql.exec(
|
|
20719
|
-
`INSERT INTO skills (name, description, version, enabled, updated_at)
|
|
20720
|
-
VALUES (?, ?, ?, ?, strftime('%s', 'now'))
|
|
20721
|
-
ON CONFLICT(name) DO UPDATE SET
|
|
21378
|
+
`INSERT INTO skills (owner_id, name, description, version, enabled, shared, updated_at)
|
|
21379
|
+
VALUES (?, ?, ?, ?, ?, ?, strftime('%s', 'now'))
|
|
21380
|
+
ON CONFLICT(owner_id, name) DO UPDATE SET
|
|
20722
21381
|
description = excluded.description,
|
|
20723
21382
|
version = excluded.version,
|
|
20724
21383
|
updated_at = excluded.updated_at`,
|
|
21384
|
+
scope.ownerId,
|
|
20725
21385
|
name,
|
|
20726
21386
|
frontmatter.description,
|
|
20727
21387
|
frontmatter.version ?? null,
|
|
20728
|
-
existing ? existing.enabled ? 1 : 0 : 1
|
|
21388
|
+
existing ? existing.enabled ? 1 : 0 : 1,
|
|
21389
|
+
scope.ownerId === SHARED_SKILL_OWNER ? 1 : 0
|
|
20729
21390
|
);
|
|
20730
21391
|
for (const f of files) {
|
|
20731
21392
|
const p = f.path.replace(/^\.\//, "");
|
|
20732
21393
|
await this.ctx.storage.sql.exec(
|
|
20733
|
-
`INSERT INTO skill_files (skill_name, path, content, size) VALUES (?, ?, ?, ?)`,
|
|
21394
|
+
`INSERT INTO skill_files (owner_id, skill_name, path, content, size) VALUES (?, ?, ?, ?, ?)`,
|
|
21395
|
+
scope.ownerId,
|
|
20734
21396
|
name,
|
|
20735
21397
|
p,
|
|
20736
21398
|
f.content,
|
|
20737
21399
|
f.content.length
|
|
20738
21400
|
);
|
|
20739
21401
|
}
|
|
20740
|
-
|
|
21402
|
+
const installed = await this.getSkill(ownScope, name);
|
|
21403
|
+
if (!installed) throw new Error(`Installed skill was not found: ${name}`);
|
|
21404
|
+
return installed;
|
|
20741
21405
|
}
|
|
20742
21406
|
/** Enable/disable an installed skill. Returns false when not installed. */
|
|
20743
|
-
async setSkillEnabled(name, enabled) {
|
|
21407
|
+
async setSkillEnabled(scope, name, enabled) {
|
|
20744
21408
|
await this.ensureMigrated();
|
|
20745
|
-
const existing = await this.getSkill(name);
|
|
21409
|
+
const existing = await this.getSkill({ ownerId: scope.ownerId }, name);
|
|
20746
21410
|
if (!existing) return false;
|
|
20747
21411
|
await this.ctx.storage.sql.exec(
|
|
20748
|
-
`UPDATE skills SET enabled = ?, updated_at = strftime('%s', 'now')
|
|
21412
|
+
`UPDATE skills SET enabled = ?, updated_at = strftime('%s', 'now')
|
|
21413
|
+
WHERE owner_id = ? AND name = ?`,
|
|
20749
21414
|
enabled ? 1 : 0,
|
|
21415
|
+
scope.ownerId,
|
|
20750
21416
|
name
|
|
20751
21417
|
);
|
|
20752
21418
|
return true;
|
|
@@ -20821,12 +21487,20 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20821
21487
|
return true;
|
|
20822
21488
|
}
|
|
20823
21489
|
/** Uninstall a skill and its files. Returns false when not installed. */
|
|
20824
|
-
async deleteSkill(name) {
|
|
21490
|
+
async deleteSkill(scope, name) {
|
|
20825
21491
|
await this.ensureMigrated();
|
|
20826
|
-
const existing = await this.getSkill(name);
|
|
21492
|
+
const existing = await this.getSkill({ ownerId: scope.ownerId }, name);
|
|
20827
21493
|
if (!existing) return false;
|
|
20828
|
-
await this.ctx.storage.sql.exec(
|
|
20829
|
-
|
|
21494
|
+
await this.ctx.storage.sql.exec(
|
|
21495
|
+
`DELETE FROM skill_files WHERE owner_id = ? AND skill_name = ?`,
|
|
21496
|
+
scope.ownerId,
|
|
21497
|
+
name
|
|
21498
|
+
);
|
|
21499
|
+
await this.ctx.storage.sql.exec(
|
|
21500
|
+
`DELETE FROM skills WHERE owner_id = ? AND name = ?`,
|
|
21501
|
+
scope.ownerId,
|
|
21502
|
+
name
|
|
21503
|
+
);
|
|
20830
21504
|
return true;
|
|
20831
21505
|
}
|
|
20832
21506
|
};
|
|
@@ -20918,8 +21592,38 @@ function selectBridgeSocket(candidates, ownerClientId) {
|
|
|
20918
21592
|
|
|
20919
21593
|
// src/durable-objects/DurableThread.ts
|
|
20920
21594
|
init_code_execution();
|
|
21595
|
+
init_remoteAttachment();
|
|
20921
21596
|
var DEFAULT_CLIENT_TOOL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
20922
21597
|
var BRIDGE_LIVENESS_TIMEOUT_MS = 20 * 1e3;
|
|
21598
|
+
var INTERNAL_TOOL_DELIVERY = Symbol("internal-tool-delivery");
|
|
21599
|
+
function generateToolDeliveryToken() {
|
|
21600
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
21601
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
21602
|
+
}
|
|
21603
|
+
async function hashToolDeliveryToken(token) {
|
|
21604
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(token));
|
|
21605
|
+
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
21606
|
+
}
|
|
21607
|
+
async function createToolDeliveryCapability() {
|
|
21608
|
+
const token = generateToolDeliveryToken();
|
|
21609
|
+
return { token, tokenHash: await hashToolDeliveryToken(token) };
|
|
21610
|
+
}
|
|
21611
|
+
async function matchesToolDeliveryToken(expectedHash, token) {
|
|
21612
|
+
if (!expectedHash || !token || token.length > 256) return false;
|
|
21613
|
+
const actualHash = await hashToolDeliveryToken(token);
|
|
21614
|
+
if (expectedHash.length !== actualHash.length) return false;
|
|
21615
|
+
let difference = 0;
|
|
21616
|
+
for (let index = 0; index < actualHash.length; index++) {
|
|
21617
|
+
difference |= expectedHash.charCodeAt(index) ^ actualHash.charCodeAt(index);
|
|
21618
|
+
}
|
|
21619
|
+
return difference === 0;
|
|
21620
|
+
}
|
|
21621
|
+
function matchesToolDeliveryOwner(pending, proof) {
|
|
21622
|
+
return !pending.dispatched_client_id || pending.dispatched_client_id === proof.clientId && Number(pending.dispatched_generation ?? 0) === (proof.generation ?? -1);
|
|
21623
|
+
}
|
|
21624
|
+
async function authorizesToolDelivery(pending, proof) {
|
|
21625
|
+
return matchesToolDeliveryOwner(pending, proof) && await matchesToolDeliveryToken(pending.delivery_token_hash, proof.token);
|
|
21626
|
+
}
|
|
20923
21627
|
var RUNTIME_STORAGE_PREFIX = "__agentbuilder_runtime_storage__:";
|
|
20924
21628
|
function normalizeEndpointThreadPath(path) {
|
|
20925
21629
|
if (!path || /^[A-Za-z][A-Za-z\d+\-.]*:/.test(path)) {
|
|
@@ -21070,6 +21774,30 @@ function createEndpointThreadStateBridge(state) {
|
|
|
21070
21774
|
getFileThumbnail: (path) => state.getFileThumbnail(normalizeEndpointThreadPath(path))
|
|
21071
21775
|
};
|
|
21072
21776
|
}
|
|
21777
|
+
function routeBridgeClientFrame(socket, message, handlers) {
|
|
21778
|
+
const attachment = socket.deserializeAttachment();
|
|
21779
|
+
const attachedAsBridge = attachment !== null && typeof attachment === "object" && "type" in attachment && attachment.type === "bridge";
|
|
21780
|
+
if (!attachedAsBridge || !handlers.isTracked(socket)) return false;
|
|
21781
|
+
handlers.markSeen(socket);
|
|
21782
|
+
if (typeof message !== "string") return false;
|
|
21783
|
+
let parsed;
|
|
21784
|
+
try {
|
|
21785
|
+
const value = JSON.parse(message);
|
|
21786
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
21787
|
+
parsed = value;
|
|
21788
|
+
} catch {
|
|
21789
|
+
return false;
|
|
21790
|
+
}
|
|
21791
|
+
if (parsed.type === "tool_response") {
|
|
21792
|
+
handlers.resolveToolResponse(socket, parsed);
|
|
21793
|
+
return true;
|
|
21794
|
+
}
|
|
21795
|
+
if (typeof parsed.type === "string" && parsed.type.startsWith("stream_") && parsed.type !== "stream_ping" && parsed.type !== "stream_pong") {
|
|
21796
|
+
handlers.handleStreamFrame(socket, parsed);
|
|
21797
|
+
return true;
|
|
21798
|
+
}
|
|
21799
|
+
return false;
|
|
21800
|
+
}
|
|
21073
21801
|
var DurableThread = class _DurableThread extends DurableObject {
|
|
21074
21802
|
migratedToVersion = null;
|
|
21075
21803
|
logSockets = /* @__PURE__ */ new Set();
|
|
@@ -22464,9 +23192,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22464
23192
|
* Each migration is run in order, starting from the current version + 1.
|
|
22465
23193
|
*/
|
|
22466
23194
|
async runMigrations(fromVersion) {
|
|
22467
|
-
for (const
|
|
22468
|
-
if (
|
|
22469
|
-
await
|
|
23195
|
+
for (const migration58 of migrations) {
|
|
23196
|
+
if (migration58.version > fromVersion) {
|
|
23197
|
+
await migration58.up(this.ctx.storage.sql);
|
|
22470
23198
|
}
|
|
22471
23199
|
}
|
|
22472
23200
|
}
|
|
@@ -23150,14 +23878,17 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
23150
23878
|
return null;
|
|
23151
23879
|
}
|
|
23152
23880
|
const location = sourceFile.location;
|
|
23153
|
-
if (!location
|
|
23881
|
+
if (!location) {
|
|
23882
|
+
return null;
|
|
23883
|
+
}
|
|
23884
|
+
const response = await fetchRemoteAttachment(
|
|
23885
|
+
location,
|
|
23886
|
+
this.env.AGENT_BUILDER_ATTACHMENT_FETCH_HOSTS
|
|
23887
|
+
);
|
|
23888
|
+
if (!response) {
|
|
23154
23889
|
return null;
|
|
23155
23890
|
}
|
|
23156
23891
|
try {
|
|
23157
|
-
const response = await fetch(location);
|
|
23158
|
-
if (!response.ok) {
|
|
23159
|
-
return null;
|
|
23160
|
-
}
|
|
23161
23892
|
const buffer = await response.arrayBuffer();
|
|
23162
23893
|
return this.arrayBufferToBase64(buffer);
|
|
23163
23894
|
} catch {
|
|
@@ -24854,7 +25585,9 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24854
25585
|
void 0,
|
|
24855
25586
|
"The client executing this operation was replaced before it finished. Retry if the work is still needed.",
|
|
24856
25587
|
previous.client_id,
|
|
24857
|
-
previous.generation
|
|
25588
|
+
previous.generation,
|
|
25589
|
+
void 0,
|
|
25590
|
+
INTERNAL_TOOL_DELIVERY
|
|
24858
25591
|
);
|
|
24859
25592
|
if (delivered) sides.add(delivered.side);
|
|
24860
25593
|
}
|
|
@@ -24884,18 +25617,21 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24884
25617
|
data: { noClient: true }
|
|
24885
25618
|
};
|
|
24886
25619
|
}
|
|
25620
|
+
let deliveryToken;
|
|
24887
25621
|
if (durability) {
|
|
24888
25622
|
try {
|
|
24889
25623
|
await this.ensureMigrated();
|
|
24890
25624
|
await this.ensurePendingClientTable();
|
|
25625
|
+
const capability = await createToolDeliveryCapability();
|
|
25626
|
+
deliveryToken = capability.token;
|
|
24891
25627
|
const ownerId = owner?.client_id ?? null;
|
|
24892
25628
|
const socketClientId = this.bridgeClientInfo.get(socket)?.clientId ?? null;
|
|
24893
25629
|
const fenced = owner && socketClientId === owner.client_id;
|
|
24894
25630
|
await this.ctx.storage.sql.exec(
|
|
24895
25631
|
`INSERT OR REPLACE INTO pending_client_calls
|
|
24896
25632
|
(tool_call_id, tool, args, request_permission, risk, side, status, created_at,
|
|
24897
|
-
dispatched_client_id, dispatched_generation)
|
|
24898
|
-
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?)`,
|
|
25633
|
+
dispatched_client_id, dispatched_generation, delivery_token_hash)
|
|
25634
|
+
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?)`,
|
|
24899
25635
|
durability.toolCallId,
|
|
24900
25636
|
request.tool,
|
|
24901
25637
|
JSON.stringify(request.args ?? {}),
|
|
@@ -24904,7 +25640,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24904
25640
|
durability.side,
|
|
24905
25641
|
Date.now(),
|
|
24906
25642
|
fenced ? ownerId : null,
|
|
24907
|
-
fenced ? owner.generation : 0
|
|
25643
|
+
fenced ? owner.generation : 0,
|
|
25644
|
+
capability.tokenHash
|
|
24908
25645
|
);
|
|
24909
25646
|
} catch (error) {
|
|
24910
25647
|
console.error("[DurableThread] Failed to persist fast-path call (continuing):", error);
|
|
@@ -24940,7 +25677,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24940
25677
|
tool: request.tool,
|
|
24941
25678
|
args: request.args ?? {},
|
|
24942
25679
|
requestPermission: request.requestPermission ?? null,
|
|
24943
|
-
risk: typeof request.risk === "number" ? request.risk : null
|
|
25680
|
+
risk: typeof request.risk === "number" ? request.risk : null,
|
|
25681
|
+
deliveryToken: deliveryToken ?? null
|
|
24944
25682
|
});
|
|
24945
25683
|
try {
|
|
24946
25684
|
socket.send(frame);
|
|
@@ -25063,7 +25801,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25063
25801
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
25064
25802
|
created_at INTEGER NOT NULL,
|
|
25065
25803
|
dispatched_client_id TEXT,
|
|
25066
|
-
dispatched_generation INTEGER NOT NULL DEFAULT 0
|
|
25804
|
+
dispatched_generation INTEGER NOT NULL DEFAULT 0,
|
|
25805
|
+
delivery_token_hash TEXT
|
|
25067
25806
|
)
|
|
25068
25807
|
`);
|
|
25069
25808
|
}
|
|
@@ -25104,13 +25843,15 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25104
25843
|
const socketClientId = this.bridgeClientInfo.get(socket)?.clientId ?? null;
|
|
25105
25844
|
const fenced = owner && socketClientId === owner.client_id;
|
|
25106
25845
|
const generation = fenced ? owner.generation : 0;
|
|
25846
|
+
const capability = await createToolDeliveryCapability();
|
|
25107
25847
|
try {
|
|
25108
25848
|
await this.ctx.storage.sql.exec(
|
|
25109
25849
|
`UPDATE pending_client_calls
|
|
25110
|
-
SET dispatched_client_id = ?, dispatched_generation = ?
|
|
25850
|
+
SET dispatched_client_id = ?, dispatched_generation = ?, delivery_token_hash = ?
|
|
25111
25851
|
WHERE tool_call_id = ? AND status = 'pending'`,
|
|
25112
25852
|
fenced ? owner.client_id : null,
|
|
25113
25853
|
generation,
|
|
25854
|
+
capability.tokenHash,
|
|
25114
25855
|
toolCallId
|
|
25115
25856
|
);
|
|
25116
25857
|
socket.send(
|
|
@@ -25122,7 +25863,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25122
25863
|
args: request.args ?? {},
|
|
25123
25864
|
requestPermission: request.requestPermission ?? null,
|
|
25124
25865
|
risk: typeof request.risk === "number" ? request.risk : null,
|
|
25125
|
-
generation
|
|
25866
|
+
generation,
|
|
25867
|
+
deliveryToken: capability.token
|
|
25126
25868
|
})
|
|
25127
25869
|
);
|
|
25128
25870
|
this.bridgeLastSeen.set(socket, Date.now());
|
|
@@ -25245,12 +25987,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25245
25987
|
const pending = await this.getPendingClientCalls();
|
|
25246
25988
|
for (const p of pending) {
|
|
25247
25989
|
if (socket.readyState !== WebSocket.OPEN) break;
|
|
25990
|
+
const capability = await createToolDeliveryCapability();
|
|
25248
25991
|
await this.ctx.storage.sql.exec(
|
|
25249
25992
|
`UPDATE pending_client_calls
|
|
25250
|
-
SET dispatched_client_id = ?, dispatched_generation = ?
|
|
25993
|
+
SET dispatched_client_id = ?, dispatched_generation = ?, delivery_token_hash = ?
|
|
25251
25994
|
WHERE tool_call_id = ? AND status = 'pending'`,
|
|
25252
25995
|
fenced ? owner.client_id : null,
|
|
25253
25996
|
generation,
|
|
25997
|
+
capability.tokenHash,
|
|
25254
25998
|
p.toolCallId
|
|
25255
25999
|
);
|
|
25256
26000
|
socket.send(
|
|
@@ -25262,7 +26006,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25262
26006
|
args: p.args,
|
|
25263
26007
|
requestPermission: p.requestPermission,
|
|
25264
26008
|
risk: p.risk,
|
|
25265
|
-
generation
|
|
26009
|
+
generation,
|
|
26010
|
+
deliveryToken: capability.token
|
|
25266
26011
|
})
|
|
25267
26012
|
);
|
|
25268
26013
|
}
|
|
@@ -25275,20 +26020,25 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25275
26020
|
* call resolved. Returns the side to continue, or null if there is no pending
|
|
25276
26021
|
* call (unknown id or already resolved — the delivery is idempotent).
|
|
25277
26022
|
*/
|
|
25278
|
-
async deliverClientToolResult(toolCallId, ok, result, error, deliveredByClientId, deliveredGeneration) {
|
|
26023
|
+
async deliverClientToolResult(toolCallId, ok, result, error, deliveredByClientId, deliveredGeneration, deliveryToken, internalAuthorization) {
|
|
25279
26024
|
await this.ensureMigrated();
|
|
25280
26025
|
await this.ensurePendingClientTable();
|
|
25281
26026
|
const pendingCursor = await this.ctx.storage.sql.exec(
|
|
25282
|
-
`SELECT side, status, dispatched_client_id, dispatched_generation
|
|
26027
|
+
`SELECT side, status, dispatched_client_id, dispatched_generation, delivery_token_hash
|
|
25283
26028
|
FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
|
|
25284
26029
|
toolCallId
|
|
25285
26030
|
);
|
|
25286
26031
|
const pending = pendingCursor.toArray()[0];
|
|
25287
26032
|
if (!pending || pending.status !== "pending") return null;
|
|
25288
|
-
|
|
25289
|
-
|
|
25290
|
-
|
|
25291
|
-
|
|
26033
|
+
const proof = {
|
|
26034
|
+
token: deliveryToken,
|
|
26035
|
+
clientId: deliveredByClientId,
|
|
26036
|
+
generation: deliveredGeneration
|
|
26037
|
+
};
|
|
26038
|
+
if (internalAuthorization !== INTERNAL_TOOL_DELIVERY) {
|
|
26039
|
+
if (!await authorizesToolDelivery(pending, proof)) return null;
|
|
26040
|
+
} else if (!matchesToolDeliveryOwner(pending, proof)) {
|
|
26041
|
+
return null;
|
|
25292
26042
|
}
|
|
25293
26043
|
const side = pending.side === "b" ? "b" : "a";
|
|
25294
26044
|
const content = ok ? result ?? "" : `Error: ${error ?? "tool failed"}`;
|
|
@@ -26005,29 +26755,17 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26005
26755
|
*/
|
|
26006
26756
|
async webSocketMessage(ws, message) {
|
|
26007
26757
|
try {
|
|
26008
|
-
|
|
26009
|
-
this.
|
|
26010
|
-
|
|
26758
|
+
const handledBridgeFrame = routeBridgeClientFrame(ws, message, {
|
|
26759
|
+
isTracked: (socket) => this.bridgeSockets.has(socket),
|
|
26760
|
+
markSeen: (socket) => this.bridgeLastSeen.set(socket, Date.now()),
|
|
26761
|
+
resolveToolResponse: (socket, payload) => this.resolveClientCall(socket, payload),
|
|
26762
|
+
handleStreamFrame: (socket, payload) => this.handleClientStreamFrame(socket, payload)
|
|
26763
|
+
});
|
|
26764
|
+
if (handledBridgeFrame) return;
|
|
26011
26765
|
if (typeof message === "string" && message === "ping") {
|
|
26012
26766
|
ws.send("pong");
|
|
26013
26767
|
return;
|
|
26014
26768
|
}
|
|
26015
|
-
if (typeof message === "string") {
|
|
26016
|
-
let parsed = null;
|
|
26017
|
-
try {
|
|
26018
|
-
parsed = JSON.parse(message);
|
|
26019
|
-
} catch {
|
|
26020
|
-
parsed = null;
|
|
26021
|
-
}
|
|
26022
|
-
if (parsed && parsed.type === "tool_response") {
|
|
26023
|
-
this.resolveClientCall(ws, parsed);
|
|
26024
|
-
return;
|
|
26025
|
-
}
|
|
26026
|
-
if (parsed && typeof parsed.type === "string" && parsed.type.startsWith("stream_") && parsed.type !== "stream_ping" && parsed.type !== "stream_pong") {
|
|
26027
|
-
this.handleClientStreamFrame(ws, parsed);
|
|
26028
|
-
return;
|
|
26029
|
-
}
|
|
26030
|
-
}
|
|
26031
26769
|
} catch (error) {
|
|
26032
26770
|
console.error("[DurableThread] Error handling WebSocket message:", error);
|
|
26033
26771
|
}
|
|
@@ -29034,6 +29772,6 @@ init_context();
|
|
|
29034
29772
|
init_ProviderRegistry();
|
|
29035
29773
|
init_types2();
|
|
29036
29774
|
|
|
29037
|
-
export { CLIENT_STREAM_CHUNK_BYTES, CodeExecutionBridge, DurableAgentBuilder, DurableThread, DurableUserHub, FlowStateSdk, NamespaceResolutionError, ProviderRegistry, ThreadWatchdog, authenticate, buildImageDescription, callClient, callClientStream, canAccessThread, cat, createNamespaceContext, createThreadEndpointHandler, decodeStreamChunk, defineController2 as defineController, emitThreadEvent, encodeStreamChunk, enhanceFlowState, exists, find, forceTurn, generateImageDescription, getFileStats, getMessages, getMessagesToSummarize, getShortName, getThumbnail, getUnsummarizedImageAttachments, getVisibleAgentNames, getVisibleModelNames, getVisiblePromptNames, getVisibleToolNames, grep, hasImageAttachments, head, injectMessage, isAdminOnlyApiRoute, isHostedInstance, isPublicApiRoute, isQualifiedName, isTrustedLocalDevelopmentRequest, linkFile, mkdir, move, optimizeImageContext, parseQualifiedName, qualifyName, queueTool, readFile, readdir, reloadHistory, rename, replaceImagesWithDescriptions, requireAdmin, requireAuth, resolveAgent, resolveHook, resolveModel, resolvePrompt, resolveTool, rmdir, stat, supportsClientForwarding, tail, unlink, updateThread, writeFile, writeImage };
|
|
29775
|
+
export { CLIENT_STREAM_CHUNK_BYTES, CodeExecutionBridge, DurableAgentBuilder, DurableThread, DurableUserHub, FlowStateSdk, NamespaceResolutionError, ProviderRegistry, ThreadWatchdog, applyRuntimeCors, authenticate, buildImageDescription, callClient, callClientStream, canAccessThread, cat, createNamespaceContext, createThreadEndpointHandler, decodeStreamChunk, defineController2 as defineController, emitThreadEvent, encodeStreamChunk, endpointCallerFromAuth, enhanceFlowState, exists, find, forceTurn, generateImageDescription, getFileStats, getMessages, getMessagesToSummarize, getShortName, getThumbnail, getUnsummarizedImageAttachments, getVisibleAgentNames, getVisibleModelNames, getVisiblePromptNames, getVisibleToolNames, grep, hasImageAttachments, head, injectMessage, isAdminOnlyApiRoute, isHostedInstance, isPublicApiRoute, isQualifiedName, isSameOriginBrowserRequest, isTrustedLocalDevelopmentRequest, linkFile, mkdir, move, optimizeImageContext, parseQualifiedName, qualifyName, queueTool, readFile, readdir, reloadHistory, rename, replaceImagesWithDescriptions, requireAdmin, requireAuth, resolveAgent, resolveHook, resolveModel, resolvePrompt, resolveTool, rmdir, runtimeCorsHeaders, runtimePreflightResponse, stat, supportsClientForwarding, tail, unlink, updateThread, writeFile, writeImage };
|
|
29038
29776
|
//# sourceMappingURL=runtime.js.map
|
|
29039
29777
|
//# sourceMappingURL=runtime.js.map
|