@standardagents/builder 0.38.0 → 0.38.2
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 +1243 -418
- 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-BBu-Osn5.d.ts → index-CF-lgN47.d.ts} +74 -11
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1064 -304
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +106 -69
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +68 -11
- package/dist/runtime.js +950 -225
- 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
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -14705,6 +14875,7 @@ var init_image_processing = __esm({
|
|
|
14705
14875
|
init_ThreadStateImpl();
|
|
14706
14876
|
|
|
14707
14877
|
// src/utils/auth.ts
|
|
14878
|
+
var SUPER_ADMIN_TOKEN_TTL_SECONDS = 12 * 60 * 60;
|
|
14708
14879
|
async function hashToken(token) {
|
|
14709
14880
|
const encoder = new TextEncoder();
|
|
14710
14881
|
const data = encoder.encode(token);
|
|
@@ -14770,9 +14941,12 @@ async function verifySuperAdminToken(token, encryptionKey) {
|
|
|
14770
14941
|
return false;
|
|
14771
14942
|
}
|
|
14772
14943
|
const timestamp = parseInt(parts[1], 10);
|
|
14944
|
+
if (!Number.isFinite(timestamp)) {
|
|
14945
|
+
return false;
|
|
14946
|
+
}
|
|
14773
14947
|
const age = Date.now() - timestamp;
|
|
14774
|
-
const maxAge =
|
|
14775
|
-
if (age > maxAge) {
|
|
14948
|
+
const maxAge = SUPER_ADMIN_TOKEN_TTL_SECONDS * 1e3;
|
|
14949
|
+
if (age < 0 || age > maxAge) {
|
|
14776
14950
|
return false;
|
|
14777
14951
|
}
|
|
14778
14952
|
return true;
|
|
@@ -14786,13 +14960,178 @@ function base64ToBuffer(base64) {
|
|
|
14786
14960
|
return bytes;
|
|
14787
14961
|
}
|
|
14788
14962
|
|
|
14789
|
-
// src/
|
|
14790
|
-
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 = {
|
|
14791
15075
|
"Access-Control-Allow-Origin": "*",
|
|
14792
15076
|
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
|
|
14793
15077
|
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
|
|
14794
15078
|
"Access-Control-Max-Age": "86400"
|
|
14795
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
|
|
14796
15135
|
function endpointCallerFromAuth(auth) {
|
|
14797
15136
|
if (!auth) return null;
|
|
14798
15137
|
const { id, username, role, permissions, email, display_name, avatar_url } = auth.user;
|
|
@@ -14826,43 +15165,88 @@ function extractBearerToken(request) {
|
|
|
14826
15165
|
if (cookieToken) {
|
|
14827
15166
|
return cookieToken;
|
|
14828
15167
|
}
|
|
14829
|
-
const isWebSocket = request.headers.get("upgrade")?.toLowerCase() === "websocket";
|
|
14830
|
-
if (isWebSocket) {
|
|
14831
|
-
try {
|
|
14832
|
-
const url = new URL(request.url);
|
|
14833
|
-
const token = url.searchParams.get("token");
|
|
14834
|
-
if (token) {
|
|
14835
|
-
return token;
|
|
14836
|
-
}
|
|
14837
|
-
} catch (err) {
|
|
14838
|
-
}
|
|
14839
|
-
}
|
|
14840
15168
|
return null;
|
|
14841
15169
|
}
|
|
14842
15170
|
function getAgentBuilder(env) {
|
|
14843
15171
|
const agentBuilderId = env.AGENT_BUILDER.idFromName("singleton");
|
|
14844
15172
|
return env.AGENT_BUILDER.get(agentBuilderId);
|
|
14845
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
|
+
}
|
|
14846
15224
|
async function authenticate(request, env) {
|
|
15225
|
+
const ticketAuth = await consumeWebSocketTicket(request, env);
|
|
15226
|
+
if (ticketAuth) return ticketAuth;
|
|
14847
15227
|
const token = extractBearerToken(request);
|
|
14848
15228
|
if (!token) {
|
|
14849
15229
|
return null;
|
|
14850
15230
|
}
|
|
14851
|
-
if (env.SUPER_ADMIN_PASSWORD && env.ENCRYPTION_KEY) {
|
|
15231
|
+
if (typeof env.SUPER_ADMIN_PASSWORD === "string" && typeof env.ENCRYPTION_KEY === "string") {
|
|
14852
15232
|
if (token.includes(".")) {
|
|
14853
15233
|
const isValidSuperAdmin = await verifySuperAdminToken(
|
|
14854
15234
|
token,
|
|
14855
15235
|
env.ENCRYPTION_KEY
|
|
14856
15236
|
);
|
|
14857
15237
|
if (isValidSuperAdmin) {
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
14861
|
-
|
|
14862
|
-
|
|
14863
|
-
|
|
14864
|
-
|
|
14865
|
-
|
|
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
|
+
}
|
|
14866
15250
|
}
|
|
14867
15251
|
}
|
|
14868
15252
|
}
|
|
@@ -14907,7 +15291,8 @@ async function authenticate(request, env) {
|
|
|
14907
15291
|
display_name: user.display_name ?? null,
|
|
14908
15292
|
avatar_url: user.avatar_url ?? null
|
|
14909
15293
|
},
|
|
14910
|
-
authType: "api_key"
|
|
15294
|
+
authType: "api_key",
|
|
15295
|
+
credentialId: apiKey.id
|
|
14911
15296
|
};
|
|
14912
15297
|
}
|
|
14913
15298
|
}
|
|
@@ -14919,7 +15304,10 @@ async function requireAuth(request, env) {
|
|
|
14919
15304
|
if (!authContext) {
|
|
14920
15305
|
return new Response(JSON.stringify({ error: "Unauthorized" }), {
|
|
14921
15306
|
status: 401,
|
|
14922
|
-
headers: {
|
|
15307
|
+
headers: {
|
|
15308
|
+
"Content-Type": "application/json",
|
|
15309
|
+
...runtimeCorsHeaders(request, env)
|
|
15310
|
+
}
|
|
14923
15311
|
});
|
|
14924
15312
|
}
|
|
14925
15313
|
return authContext;
|
|
@@ -14934,7 +15322,10 @@ async function requireAdmin(request, env) {
|
|
|
14934
15322
|
JSON.stringify({ error: "Forbidden: Admin access required" }),
|
|
14935
15323
|
{
|
|
14936
15324
|
status: 403,
|
|
14937
|
-
headers: {
|
|
15325
|
+
headers: {
|
|
15326
|
+
"Content-Type": "application/json",
|
|
15327
|
+
...runtimeCorsHeaders(request, env)
|
|
15328
|
+
}
|
|
14938
15329
|
}
|
|
14939
15330
|
);
|
|
14940
15331
|
}
|
|
@@ -15007,73 +15398,6 @@ function canAccessThread(auth, thread) {
|
|
|
15007
15398
|
return thread.user_id === auth.user.id;
|
|
15008
15399
|
}
|
|
15009
15400
|
|
|
15010
|
-
// src/routing/access-policy.ts
|
|
15011
|
-
var PUBLIC_ROUTES = /* @__PURE__ */ new Set([
|
|
15012
|
-
"/api/auth/bootstrap",
|
|
15013
|
-
"/api/auth/login",
|
|
15014
|
-
"/api/auth/config",
|
|
15015
|
-
"/api/auth/brolly-control",
|
|
15016
|
-
"/api/auth/platform-cleanup",
|
|
15017
|
-
"/api/auth/platform-replica",
|
|
15018
|
-
"/api/auth/sa/start",
|
|
15019
|
-
"/api/auth/sa/callback",
|
|
15020
|
-
"/api/config",
|
|
15021
|
-
"/api/auth/oauth/github",
|
|
15022
|
-
"/api/auth/oauth/google",
|
|
15023
|
-
"/api/auth/oauth/github/callback",
|
|
15024
|
-
"/api/auth/oauth/google/callback",
|
|
15025
|
-
"/api/hooks"
|
|
15026
|
-
]);
|
|
15027
|
-
function isProviderIconRoute(routePath) {
|
|
15028
|
-
return /^\/api\/providers\/[^/]+\/icon$/.test(routePath);
|
|
15029
|
-
}
|
|
15030
|
-
function isHostedInstance(env) {
|
|
15031
|
-
const value = env?.STANDARD_AGENTS_HOSTED;
|
|
15032
|
-
if (typeof value === "string") {
|
|
15033
|
-
const normalized = value.trim().toLowerCase();
|
|
15034
|
-
return normalized !== "" && normalized !== "0" && normalized !== "false";
|
|
15035
|
-
}
|
|
15036
|
-
return Boolean(value);
|
|
15037
|
-
}
|
|
15038
|
-
function isTrustedLocalDevelopmentRequest(request, env) {
|
|
15039
|
-
if (isHostedInstance(env)) return false;
|
|
15040
|
-
let hostname;
|
|
15041
|
-
try {
|
|
15042
|
-
hostname = new URL(request.url).hostname.toLowerCase();
|
|
15043
|
-
} catch {
|
|
15044
|
-
return false;
|
|
15045
|
-
}
|
|
15046
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
|
|
15047
|
-
}
|
|
15048
|
-
function isPublicApiRoute(routePath, request, env) {
|
|
15049
|
-
if (PUBLIC_ROUTES.has(routePath)) return true;
|
|
15050
|
-
if (routePath === "/api/auth/device/start" || routePath.startsWith("/api/auth/device/")) {
|
|
15051
|
-
return true;
|
|
15052
|
-
}
|
|
15053
|
-
if (isProviderIconRoute(routePath)) {
|
|
15054
|
-
return true;
|
|
15055
|
-
}
|
|
15056
|
-
if (!isTrustedLocalDevelopmentRequest(request, env)) return false;
|
|
15057
|
-
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/");
|
|
15058
|
-
}
|
|
15059
|
-
function isAdminOnlyApiRoute(routePath, method = "GET") {
|
|
15060
|
-
if (routePath === "/api/skills" || routePath.startsWith("/api/skills/")) return true;
|
|
15061
|
-
if (routePath === "/api/pack" || routePath.startsWith("/api/pack/")) return true;
|
|
15062
|
-
if (routePath === "/api/unpack" || routePath.startsWith("/api/unpack/")) return true;
|
|
15063
|
-
if (routePath === "/api/prompts" || routePath.startsWith("/api/prompts/")) return true;
|
|
15064
|
-
if (routePath === "/api/tools" || routePath.startsWith("/api/tools/")) return true;
|
|
15065
|
-
if (routePath === "/api/models" || routePath.startsWith("/api/models/")) return true;
|
|
15066
|
-
if (routePath === "/api/providers") return true;
|
|
15067
|
-
if (routePath.startsWith("/api/providers/")) {
|
|
15068
|
-
return !isProviderIconRoute(routePath);
|
|
15069
|
-
}
|
|
15070
|
-
if (routePath.startsWith("/api/agents/")) {
|
|
15071
|
-
return !/^\/api\/agents\/[^/]+\/tenvs$/.test(routePath);
|
|
15072
|
-
}
|
|
15073
|
-
if (routePath === "/api/agents" && method.toUpperCase() !== "GET") return true;
|
|
15074
|
-
return false;
|
|
15075
|
-
}
|
|
15076
|
-
|
|
15077
15401
|
// src/runtime.ts
|
|
15078
15402
|
init_client_forwarding();
|
|
15079
15403
|
|
|
@@ -15986,8 +16310,37 @@ var migration35 = {
|
|
|
15986
16310
|
}
|
|
15987
16311
|
};
|
|
15988
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
|
+
|
|
15989
16342
|
// src/durable-objects/migrations/index.ts
|
|
15990
|
-
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];
|
|
15991
16344
|
var LATEST_SCHEMA_VERSION = migrations.length;
|
|
15992
16345
|
|
|
15993
16346
|
// src/durable-objects/subagent-reconcile.ts
|
|
@@ -16823,7 +17176,7 @@ function eventSocketCanReceive(attachment, ownerUserId) {
|
|
|
16823
17176
|
}
|
|
16824
17177
|
|
|
16825
17178
|
// src/durable-objects/agentbuilder-migrations/0001_initial.ts
|
|
16826
|
-
var
|
|
17179
|
+
var migration37 = {
|
|
16827
17180
|
version: 1,
|
|
16828
17181
|
async up(sql) {
|
|
16829
17182
|
sql.exec(`
|
|
@@ -16922,7 +17275,7 @@ var migration36 = {
|
|
|
16922
17275
|
};
|
|
16923
17276
|
|
|
16924
17277
|
// src/durable-objects/agentbuilder-migrations/0002_add_tenvs_properties.ts
|
|
16925
|
-
var
|
|
17278
|
+
var migration38 = {
|
|
16926
17279
|
version: 2,
|
|
16927
17280
|
async up(sql) {
|
|
16928
17281
|
sql.exec(`ALTER TABLE threads ADD COLUMN tenvs TEXT`);
|
|
@@ -16934,7 +17287,7 @@ var migration37 = {
|
|
|
16934
17287
|
};
|
|
16935
17288
|
|
|
16936
17289
|
// src/durable-objects/agentbuilder-migrations/0003_add_parent_and_terminated.ts
|
|
16937
|
-
var
|
|
17290
|
+
var migration39 = {
|
|
16938
17291
|
version: 3,
|
|
16939
17292
|
async up(sql) {
|
|
16940
17293
|
sql.exec(`ALTER TABLE threads ADD COLUMN parent TEXT REFERENCES threads(id)`);
|
|
@@ -16947,7 +17300,7 @@ var migration38 = {
|
|
|
16947
17300
|
};
|
|
16948
17301
|
|
|
16949
17302
|
// src/durable-objects/agentbuilder-migrations/0004_add_env_tables.ts
|
|
16950
|
-
var
|
|
17303
|
+
var migration40 = {
|
|
16951
17304
|
version: 4,
|
|
16952
17305
|
async up(sql) {
|
|
16953
17306
|
sql.exec(`ALTER TABLE threads ADD COLUMN env TEXT`);
|
|
@@ -16971,7 +17324,7 @@ var migration39 = {
|
|
|
16971
17324
|
};
|
|
16972
17325
|
|
|
16973
17326
|
// src/durable-objects/agentbuilder-migrations/0005_add_pending_subagent_env_requests.ts
|
|
16974
|
-
var
|
|
17327
|
+
var migration41 = {
|
|
16975
17328
|
version: 5,
|
|
16976
17329
|
async up(sql) {
|
|
16977
17330
|
sql.exec(`
|
|
@@ -16997,7 +17350,7 @@ var migration40 = {
|
|
|
16997
17350
|
};
|
|
16998
17351
|
|
|
16999
17352
|
// src/durable-objects/agentbuilder-migrations/0006_add_env_value_types.ts
|
|
17000
|
-
var
|
|
17353
|
+
var migration42 = {
|
|
17001
17354
|
version: 6,
|
|
17002
17355
|
async up(sql) {
|
|
17003
17356
|
sql.exec(
|
|
@@ -17012,7 +17365,7 @@ var migration41 = {
|
|
|
17012
17365
|
};
|
|
17013
17366
|
|
|
17014
17367
|
// src/durable-objects/agentbuilder-migrations/0007_platform_identity_replica.ts
|
|
17015
|
-
var
|
|
17368
|
+
var migration43 = {
|
|
17016
17369
|
version: 7,
|
|
17017
17370
|
async up(sql) {
|
|
17018
17371
|
sql.exec(`ALTER TABLE users ADD COLUMN platform_user_id TEXT`);
|
|
@@ -17041,7 +17394,7 @@ var migration42 = {
|
|
|
17041
17394
|
};
|
|
17042
17395
|
|
|
17043
17396
|
// src/durable-objects/agentbuilder-migrations/0008_add_skills.ts
|
|
17044
|
-
var
|
|
17397
|
+
var migration44 = {
|
|
17045
17398
|
version: 8,
|
|
17046
17399
|
async up(sql) {
|
|
17047
17400
|
sql.exec(`
|
|
@@ -17072,7 +17425,7 @@ var migration43 = {
|
|
|
17072
17425
|
};
|
|
17073
17426
|
|
|
17074
17427
|
// src/durable-objects/agentbuilder-migrations/0009_add_user_permissions.ts
|
|
17075
|
-
var
|
|
17428
|
+
var migration45 = {
|
|
17076
17429
|
version: 9,
|
|
17077
17430
|
async up(sql) {
|
|
17078
17431
|
sql.exec(`ALTER TABLE users ADD COLUMN permissions TEXT`);
|
|
@@ -17083,7 +17436,7 @@ var migration44 = {
|
|
|
17083
17436
|
};
|
|
17084
17437
|
|
|
17085
17438
|
// src/durable-objects/agentbuilder-migrations/0010_add_device_logins.ts
|
|
17086
|
-
var
|
|
17439
|
+
var migration46 = {
|
|
17087
17440
|
version: 10,
|
|
17088
17441
|
async up(sql) {
|
|
17089
17442
|
sql.exec(`
|
|
@@ -17103,7 +17456,7 @@ var migration45 = {
|
|
|
17103
17456
|
};
|
|
17104
17457
|
|
|
17105
17458
|
// src/durable-objects/agentbuilder-migrations/0011_add_user_values.ts
|
|
17106
|
-
var
|
|
17459
|
+
var migration47 = {
|
|
17107
17460
|
version: 11,
|
|
17108
17461
|
async up(sql) {
|
|
17109
17462
|
sql.exec(`
|
|
@@ -17126,7 +17479,7 @@ var migration46 = {
|
|
|
17126
17479
|
};
|
|
17127
17480
|
|
|
17128
17481
|
// src/durable-objects/agentbuilder-migrations/0012_allow_api_instance_role.ts
|
|
17129
|
-
var
|
|
17482
|
+
var migration48 = {
|
|
17130
17483
|
version: 12,
|
|
17131
17484
|
async up(sql) {
|
|
17132
17485
|
sql.exec(`CREATE TABLE oauth_accounts_0012_backup AS SELECT * FROM oauth_accounts`);
|
|
@@ -17236,7 +17589,7 @@ var migration47 = {
|
|
|
17236
17589
|
};
|
|
17237
17590
|
|
|
17238
17591
|
// src/durable-objects/agentbuilder-migrations/0013_add_thread_activity.ts
|
|
17239
|
-
var
|
|
17592
|
+
var migration49 = {
|
|
17240
17593
|
version: 13,
|
|
17241
17594
|
async up(sql) {
|
|
17242
17595
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_activity_at INTEGER`);
|
|
@@ -17252,7 +17605,7 @@ var migration48 = {
|
|
|
17252
17605
|
};
|
|
17253
17606
|
|
|
17254
17607
|
// src/durable-objects/agentbuilder-migrations/0014_thread_activity_scale.ts
|
|
17255
|
-
var
|
|
17608
|
+
var migration50 = {
|
|
17256
17609
|
version: 14,
|
|
17257
17610
|
async up(sql) {
|
|
17258
17611
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_message_preview TEXT`);
|
|
@@ -17270,7 +17623,7 @@ var migration49 = {
|
|
|
17270
17623
|
};
|
|
17271
17624
|
|
|
17272
17625
|
// src/durable-objects/agentbuilder-migrations/0015_clear_envelope_previews.ts
|
|
17273
|
-
var
|
|
17626
|
+
var migration51 = {
|
|
17274
17627
|
version: 15,
|
|
17275
17628
|
async up(sql) {
|
|
17276
17629
|
sql.exec(
|
|
@@ -17284,7 +17637,7 @@ var migration50 = {
|
|
|
17284
17637
|
};
|
|
17285
17638
|
|
|
17286
17639
|
// src/durable-objects/agentbuilder-migrations/0016_add_origin_agent.ts
|
|
17287
|
-
var
|
|
17640
|
+
var migration52 = {
|
|
17288
17641
|
version: 16,
|
|
17289
17642
|
async up(sql) {
|
|
17290
17643
|
sql.exec(`ALTER TABLE threads ADD COLUMN origin_agent_name TEXT`);
|
|
@@ -17299,7 +17652,7 @@ var migration51 = {
|
|
|
17299
17652
|
};
|
|
17300
17653
|
|
|
17301
17654
|
// src/durable-objects/agentbuilder-migrations/0017_add_thread_message_recency.ts
|
|
17302
|
-
var
|
|
17655
|
+
var migration53 = {
|
|
17303
17656
|
version: 17,
|
|
17304
17657
|
async up(sql) {
|
|
17305
17658
|
sql.exec(`ALTER TABLE threads ADD COLUMN last_message_at INTEGER`);
|
|
@@ -17310,10 +17663,132 @@ var migration52 = {
|
|
|
17310
17663
|
}
|
|
17311
17664
|
};
|
|
17312
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
|
+
|
|
17313
17788
|
// src/durable-objects/agentbuilder-migrations/index.ts
|
|
17314
|
-
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];
|
|
17315
17790
|
var LATEST_SCHEMA_VERSION2 = migrations2.reduce(
|
|
17316
|
-
(max,
|
|
17791
|
+
(max, migration58) => Math.max(max, migration58.version),
|
|
17317
17792
|
0
|
|
17318
17793
|
);
|
|
17319
17794
|
|
|
@@ -17818,6 +18293,7 @@ function validateSkillFiles(files) {
|
|
|
17818
18293
|
}
|
|
17819
18294
|
|
|
17820
18295
|
// src/durable-objects/DurableAgentBuilder.ts
|
|
18296
|
+
init_scope();
|
|
17821
18297
|
var ENV_TYPES_PROPERTY = "__agentbuilder_env_types";
|
|
17822
18298
|
function parseStoredPermissions(value) {
|
|
17823
18299
|
if (typeof value !== "string" || !value.trim()) return null;
|
|
@@ -18410,9 +18886,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
18410
18886
|
}
|
|
18411
18887
|
}
|
|
18412
18888
|
async runMigrations(fromVersion) {
|
|
18413
|
-
for (const
|
|
18414
|
-
if (
|
|
18415
|
-
await
|
|
18889
|
+
for (const migration58 of migrations2) {
|
|
18890
|
+
if (migration58.version > fromVersion) {
|
|
18891
|
+
await migration58.up(this.ctx.storage.sql);
|
|
18416
18892
|
}
|
|
18417
18893
|
}
|
|
18418
18894
|
}
|
|
@@ -20361,6 +20837,150 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20361
20837
|
tokenHash
|
|
20362
20838
|
);
|
|
20363
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
|
+
}
|
|
20364
20984
|
// ============================================================
|
|
20365
20985
|
// API Key Methods
|
|
20366
20986
|
// ============================================================
|
|
@@ -20678,40 +21298,61 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20678
21298
|
}
|
|
20679
21299
|
}
|
|
20680
21300
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20681
|
-
// Skills —
|
|
20682
|
-
// Installed once, visible to every thread; file contents live here so
|
|
20683
|
-
// nothing about a skill is stored on a client machine.
|
|
21301
|
+
// Skills — owner-scoped Agent Skills plus explicitly shared admin skills.
|
|
20684
21302
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20685
21303
|
/** Installed skills, metadata only (no file contents). */
|
|
20686
|
-
async listSkills(options = {}) {
|
|
21304
|
+
async listSkills(scope, options = {}) {
|
|
20687
21305
|
await this.ensureMigrated();
|
|
20688
|
-
const where = options.includeDisabled ? "" : "WHERE enabled = 1";
|
|
20689
21306
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20690
21307
|
`SELECT s.name, s.description, s.version, s.enabled, s.updated_at,
|
|
20691
|
-
|
|
20692
|
-
|
|
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
|
|
20693
21319
|
);
|
|
20694
|
-
|
|
20695
|
-
|
|
20696
|
-
|
|
20697
|
-
|
|
20698
|
-
|
|
20699
|
-
|
|
20700
|
-
|
|
20701
|
-
|
|
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()];
|
|
20702
21335
|
}
|
|
20703
21336
|
/** One skill's metadata (null when not installed). */
|
|
20704
|
-
async getSkill(name) {
|
|
20705
|
-
const all = await this.listSkills({ includeDisabled: true });
|
|
21337
|
+
async getSkill(scope, name) {
|
|
21338
|
+
const all = await this.listSkills(scope, { includeDisabled: true });
|
|
20706
21339
|
return all.find((s) => s.name === name) ?? null;
|
|
20707
21340
|
}
|
|
20708
21341
|
/** One bundled file's text (null when the skill or file is missing). */
|
|
20709
|
-
async getSkillFile(name, path) {
|
|
21342
|
+
async getSkillFile(scope, name, path) {
|
|
20710
21343
|
await this.ensureMigrated();
|
|
20711
21344
|
const cursor = await this.ctx.storage.sql.exec(
|
|
20712
|
-
`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`,
|
|
20713
21351
|
name,
|
|
20714
|
-
path.replace(/^\.\//, "")
|
|
21352
|
+
path.replace(/^\.\//, ""),
|
|
21353
|
+
scope.ownerId,
|
|
21354
|
+
scope.includeShared ? 1 : 0,
|
|
21355
|
+
scope.ownerId
|
|
20715
21356
|
);
|
|
20716
21357
|
const rows = cursor.toArray();
|
|
20717
21358
|
return rows.length ? rows[0].content : null;
|
|
@@ -20722,44 +21363,56 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20722
21363
|
* that frontmatter. Throws SkillValidationError with an actionable message
|
|
20723
21364
|
* on any standard violation.
|
|
20724
21365
|
*/
|
|
20725
|
-
async upsertSkill(files) {
|
|
21366
|
+
async upsertSkill(scope, files) {
|
|
20726
21367
|
await this.ensureMigrated();
|
|
20727
21368
|
const frontmatter = validateSkillFiles(files);
|
|
20728
21369
|
const name = frontmatter.name;
|
|
20729
|
-
const
|
|
20730
|
-
await this.
|
|
21370
|
+
const ownScope = { ownerId: scope.ownerId };
|
|
21371
|
+
const existing = await this.getSkill(ownScope, name);
|
|
20731
21372
|
await this.ctx.storage.sql.exec(
|
|
20732
|
-
`
|
|
20733
|
-
|
|
20734
|
-
|
|
21373
|
+
`DELETE FROM skill_files WHERE owner_id = ? AND skill_name = ?`,
|
|
21374
|
+
scope.ownerId,
|
|
21375
|
+
name
|
|
21376
|
+
);
|
|
21377
|
+
await this.ctx.storage.sql.exec(
|
|
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
|
|
20735
21381
|
description = excluded.description,
|
|
20736
21382
|
version = excluded.version,
|
|
20737
21383
|
updated_at = excluded.updated_at`,
|
|
21384
|
+
scope.ownerId,
|
|
20738
21385
|
name,
|
|
20739
21386
|
frontmatter.description,
|
|
20740
21387
|
frontmatter.version ?? null,
|
|
20741
|
-
existing ? existing.enabled ? 1 : 0 : 1
|
|
21388
|
+
existing ? existing.enabled ? 1 : 0 : 1,
|
|
21389
|
+
scope.ownerId === SHARED_SKILL_OWNER ? 1 : 0
|
|
20742
21390
|
);
|
|
20743
21391
|
for (const f of files) {
|
|
20744
21392
|
const p = f.path.replace(/^\.\//, "");
|
|
20745
21393
|
await this.ctx.storage.sql.exec(
|
|
20746
|
-
`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,
|
|
20747
21396
|
name,
|
|
20748
21397
|
p,
|
|
20749
21398
|
f.content,
|
|
20750
21399
|
f.content.length
|
|
20751
21400
|
);
|
|
20752
21401
|
}
|
|
20753
|
-
|
|
21402
|
+
const installed = await this.getSkill(ownScope, name);
|
|
21403
|
+
if (!installed) throw new Error(`Installed skill was not found: ${name}`);
|
|
21404
|
+
return installed;
|
|
20754
21405
|
}
|
|
20755
21406
|
/** Enable/disable an installed skill. Returns false when not installed. */
|
|
20756
|
-
async setSkillEnabled(name, enabled) {
|
|
21407
|
+
async setSkillEnabled(scope, name, enabled) {
|
|
20757
21408
|
await this.ensureMigrated();
|
|
20758
|
-
const existing = await this.getSkill(name);
|
|
21409
|
+
const existing = await this.getSkill({ ownerId: scope.ownerId }, name);
|
|
20759
21410
|
if (!existing) return false;
|
|
20760
21411
|
await this.ctx.storage.sql.exec(
|
|
20761
|
-
`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 = ?`,
|
|
20762
21414
|
enabled ? 1 : 0,
|
|
21415
|
+
scope.ownerId,
|
|
20763
21416
|
name
|
|
20764
21417
|
);
|
|
20765
21418
|
return true;
|
|
@@ -20834,12 +21487,20 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20834
21487
|
return true;
|
|
20835
21488
|
}
|
|
20836
21489
|
/** Uninstall a skill and its files. Returns false when not installed. */
|
|
20837
|
-
async deleteSkill(name) {
|
|
21490
|
+
async deleteSkill(scope, name) {
|
|
20838
21491
|
await this.ensureMigrated();
|
|
20839
|
-
const existing = await this.getSkill(name);
|
|
21492
|
+
const existing = await this.getSkill({ ownerId: scope.ownerId }, name);
|
|
20840
21493
|
if (!existing) return false;
|
|
20841
|
-
await this.ctx.storage.sql.exec(
|
|
20842
|
-
|
|
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
|
+
);
|
|
20843
21504
|
return true;
|
|
20844
21505
|
}
|
|
20845
21506
|
};
|
|
@@ -20931,8 +21592,38 @@ function selectBridgeSocket(candidates, ownerClientId) {
|
|
|
20931
21592
|
|
|
20932
21593
|
// src/durable-objects/DurableThread.ts
|
|
20933
21594
|
init_code_execution();
|
|
21595
|
+
init_remoteAttachment();
|
|
20934
21596
|
var DEFAULT_CLIENT_TOOL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
20935
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
|
+
}
|
|
20936
21627
|
var RUNTIME_STORAGE_PREFIX = "__agentbuilder_runtime_storage__:";
|
|
20937
21628
|
function normalizeEndpointThreadPath(path) {
|
|
20938
21629
|
if (!path || /^[A-Za-z][A-Za-z\d+\-.]*:/.test(path)) {
|
|
@@ -21083,6 +21774,30 @@ function createEndpointThreadStateBridge(state) {
|
|
|
21083
21774
|
getFileThumbnail: (path) => state.getFileThumbnail(normalizeEndpointThreadPath(path))
|
|
21084
21775
|
};
|
|
21085
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
|
+
}
|
|
21086
21801
|
var DurableThread = class _DurableThread extends DurableObject {
|
|
21087
21802
|
migratedToVersion = null;
|
|
21088
21803
|
logSockets = /* @__PURE__ */ new Set();
|
|
@@ -22477,9 +23192,9 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22477
23192
|
* Each migration is run in order, starting from the current version + 1.
|
|
22478
23193
|
*/
|
|
22479
23194
|
async runMigrations(fromVersion) {
|
|
22480
|
-
for (const
|
|
22481
|
-
if (
|
|
22482
|
-
await
|
|
23195
|
+
for (const migration58 of migrations) {
|
|
23196
|
+
if (migration58.version > fromVersion) {
|
|
23197
|
+
await migration58.up(this.ctx.storage.sql);
|
|
22483
23198
|
}
|
|
22484
23199
|
}
|
|
22485
23200
|
}
|
|
@@ -23163,14 +23878,17 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
23163
23878
|
return null;
|
|
23164
23879
|
}
|
|
23165
23880
|
const location = sourceFile.location;
|
|
23166
|
-
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) {
|
|
23167
23889
|
return null;
|
|
23168
23890
|
}
|
|
23169
23891
|
try {
|
|
23170
|
-
const response = await fetch(location);
|
|
23171
|
-
if (!response.ok) {
|
|
23172
|
-
return null;
|
|
23173
|
-
}
|
|
23174
23892
|
const buffer = await response.arrayBuffer();
|
|
23175
23893
|
return this.arrayBufferToBase64(buffer);
|
|
23176
23894
|
} catch {
|
|
@@ -24867,7 +25585,9 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24867
25585
|
void 0,
|
|
24868
25586
|
"The client executing this operation was replaced before it finished. Retry if the work is still needed.",
|
|
24869
25587
|
previous.client_id,
|
|
24870
|
-
previous.generation
|
|
25588
|
+
previous.generation,
|
|
25589
|
+
void 0,
|
|
25590
|
+
INTERNAL_TOOL_DELIVERY
|
|
24871
25591
|
);
|
|
24872
25592
|
if (delivered) sides.add(delivered.side);
|
|
24873
25593
|
}
|
|
@@ -24897,18 +25617,21 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24897
25617
|
data: { noClient: true }
|
|
24898
25618
|
};
|
|
24899
25619
|
}
|
|
25620
|
+
let deliveryToken;
|
|
24900
25621
|
if (durability) {
|
|
24901
25622
|
try {
|
|
24902
25623
|
await this.ensureMigrated();
|
|
24903
25624
|
await this.ensurePendingClientTable();
|
|
25625
|
+
const capability = await createToolDeliveryCapability();
|
|
25626
|
+
deliveryToken = capability.token;
|
|
24904
25627
|
const ownerId = owner?.client_id ?? null;
|
|
24905
25628
|
const socketClientId = this.bridgeClientInfo.get(socket)?.clientId ?? null;
|
|
24906
25629
|
const fenced = owner && socketClientId === owner.client_id;
|
|
24907
25630
|
await this.ctx.storage.sql.exec(
|
|
24908
25631
|
`INSERT OR REPLACE INTO pending_client_calls
|
|
24909
25632
|
(tool_call_id, tool, args, request_permission, risk, side, status, created_at,
|
|
24910
|
-
dispatched_client_id, dispatched_generation)
|
|
24911
|
-
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?)`,
|
|
25633
|
+
dispatched_client_id, dispatched_generation, delivery_token_hash)
|
|
25634
|
+
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?)`,
|
|
24912
25635
|
durability.toolCallId,
|
|
24913
25636
|
request.tool,
|
|
24914
25637
|
JSON.stringify(request.args ?? {}),
|
|
@@ -24917,7 +25640,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24917
25640
|
durability.side,
|
|
24918
25641
|
Date.now(),
|
|
24919
25642
|
fenced ? ownerId : null,
|
|
24920
|
-
fenced ? owner.generation : 0
|
|
25643
|
+
fenced ? owner.generation : 0,
|
|
25644
|
+
capability.tokenHash
|
|
24921
25645
|
);
|
|
24922
25646
|
} catch (error) {
|
|
24923
25647
|
console.error("[DurableThread] Failed to persist fast-path call (continuing):", error);
|
|
@@ -24953,7 +25677,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24953
25677
|
tool: request.tool,
|
|
24954
25678
|
args: request.args ?? {},
|
|
24955
25679
|
requestPermission: request.requestPermission ?? null,
|
|
24956
|
-
risk: typeof request.risk === "number" ? request.risk : null
|
|
25680
|
+
risk: typeof request.risk === "number" ? request.risk : null,
|
|
25681
|
+
deliveryToken: deliveryToken ?? null
|
|
24957
25682
|
});
|
|
24958
25683
|
try {
|
|
24959
25684
|
socket.send(frame);
|
|
@@ -25076,7 +25801,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25076
25801
|
status TEXT NOT NULL DEFAULT 'pending',
|
|
25077
25802
|
created_at INTEGER NOT NULL,
|
|
25078
25803
|
dispatched_client_id TEXT,
|
|
25079
|
-
dispatched_generation INTEGER NOT NULL DEFAULT 0
|
|
25804
|
+
dispatched_generation INTEGER NOT NULL DEFAULT 0,
|
|
25805
|
+
delivery_token_hash TEXT
|
|
25080
25806
|
)
|
|
25081
25807
|
`);
|
|
25082
25808
|
}
|
|
@@ -25117,13 +25843,15 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25117
25843
|
const socketClientId = this.bridgeClientInfo.get(socket)?.clientId ?? null;
|
|
25118
25844
|
const fenced = owner && socketClientId === owner.client_id;
|
|
25119
25845
|
const generation = fenced ? owner.generation : 0;
|
|
25846
|
+
const capability = await createToolDeliveryCapability();
|
|
25120
25847
|
try {
|
|
25121
25848
|
await this.ctx.storage.sql.exec(
|
|
25122
25849
|
`UPDATE pending_client_calls
|
|
25123
|
-
SET dispatched_client_id = ?, dispatched_generation = ?
|
|
25850
|
+
SET dispatched_client_id = ?, dispatched_generation = ?, delivery_token_hash = ?
|
|
25124
25851
|
WHERE tool_call_id = ? AND status = 'pending'`,
|
|
25125
25852
|
fenced ? owner.client_id : null,
|
|
25126
25853
|
generation,
|
|
25854
|
+
capability.tokenHash,
|
|
25127
25855
|
toolCallId
|
|
25128
25856
|
);
|
|
25129
25857
|
socket.send(
|
|
@@ -25135,7 +25863,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25135
25863
|
args: request.args ?? {},
|
|
25136
25864
|
requestPermission: request.requestPermission ?? null,
|
|
25137
25865
|
risk: typeof request.risk === "number" ? request.risk : null,
|
|
25138
|
-
generation
|
|
25866
|
+
generation,
|
|
25867
|
+
deliveryToken: capability.token
|
|
25139
25868
|
})
|
|
25140
25869
|
);
|
|
25141
25870
|
this.bridgeLastSeen.set(socket, Date.now());
|
|
@@ -25258,12 +25987,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25258
25987
|
const pending = await this.getPendingClientCalls();
|
|
25259
25988
|
for (const p of pending) {
|
|
25260
25989
|
if (socket.readyState !== WebSocket.OPEN) break;
|
|
25990
|
+
const capability = await createToolDeliveryCapability();
|
|
25261
25991
|
await this.ctx.storage.sql.exec(
|
|
25262
25992
|
`UPDATE pending_client_calls
|
|
25263
|
-
SET dispatched_client_id = ?, dispatched_generation = ?
|
|
25993
|
+
SET dispatched_client_id = ?, dispatched_generation = ?, delivery_token_hash = ?
|
|
25264
25994
|
WHERE tool_call_id = ? AND status = 'pending'`,
|
|
25265
25995
|
fenced ? owner.client_id : null,
|
|
25266
25996
|
generation,
|
|
25997
|
+
capability.tokenHash,
|
|
25267
25998
|
p.toolCallId
|
|
25268
25999
|
);
|
|
25269
26000
|
socket.send(
|
|
@@ -25275,7 +26006,8 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25275
26006
|
args: p.args,
|
|
25276
26007
|
requestPermission: p.requestPermission,
|
|
25277
26008
|
risk: p.risk,
|
|
25278
|
-
generation
|
|
26009
|
+
generation,
|
|
26010
|
+
deliveryToken: capability.token
|
|
25279
26011
|
})
|
|
25280
26012
|
);
|
|
25281
26013
|
}
|
|
@@ -25288,20 +26020,25 @@ ${resultContent}${attachmentSummary}`;
|
|
|
25288
26020
|
* call resolved. Returns the side to continue, or null if there is no pending
|
|
25289
26021
|
* call (unknown id or already resolved — the delivery is idempotent).
|
|
25290
26022
|
*/
|
|
25291
|
-
async deliverClientToolResult(toolCallId, ok, result, error, deliveredByClientId, deliveredGeneration) {
|
|
26023
|
+
async deliverClientToolResult(toolCallId, ok, result, error, deliveredByClientId, deliveredGeneration, deliveryToken, internalAuthorization) {
|
|
25292
26024
|
await this.ensureMigrated();
|
|
25293
26025
|
await this.ensurePendingClientTable();
|
|
25294
26026
|
const pendingCursor = await this.ctx.storage.sql.exec(
|
|
25295
|
-
`SELECT side, status, dispatched_client_id, dispatched_generation
|
|
26027
|
+
`SELECT side, status, dispatched_client_id, dispatched_generation, delivery_token_hash
|
|
25296
26028
|
FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
|
|
25297
26029
|
toolCallId
|
|
25298
26030
|
);
|
|
25299
26031
|
const pending = pendingCursor.toArray()[0];
|
|
25300
26032
|
if (!pending || pending.status !== "pending") return null;
|
|
25301
|
-
|
|
25302
|
-
|
|
25303
|
-
|
|
25304
|
-
|
|
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;
|
|
25305
26042
|
}
|
|
25306
26043
|
const side = pending.side === "b" ? "b" : "a";
|
|
25307
26044
|
const content = ok ? result ?? "" : `Error: ${error ?? "tool failed"}`;
|
|
@@ -26018,29 +26755,17 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26018
26755
|
*/
|
|
26019
26756
|
async webSocketMessage(ws, message) {
|
|
26020
26757
|
try {
|
|
26021
|
-
|
|
26022
|
-
this.
|
|
26023
|
-
|
|
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;
|
|
26024
26765
|
if (typeof message === "string" && message === "ping") {
|
|
26025
26766
|
ws.send("pong");
|
|
26026
26767
|
return;
|
|
26027
26768
|
}
|
|
26028
|
-
if (typeof message === "string") {
|
|
26029
|
-
let parsed = null;
|
|
26030
|
-
try {
|
|
26031
|
-
parsed = JSON.parse(message);
|
|
26032
|
-
} catch {
|
|
26033
|
-
parsed = null;
|
|
26034
|
-
}
|
|
26035
|
-
if (parsed && parsed.type === "tool_response") {
|
|
26036
|
-
this.resolveClientCall(ws, parsed);
|
|
26037
|
-
return;
|
|
26038
|
-
}
|
|
26039
|
-
if (parsed && typeof parsed.type === "string" && parsed.type.startsWith("stream_") && parsed.type !== "stream_ping" && parsed.type !== "stream_pong") {
|
|
26040
|
-
this.handleClientStreamFrame(ws, parsed);
|
|
26041
|
-
return;
|
|
26042
|
-
}
|
|
26043
|
-
}
|
|
26044
26769
|
} catch (error) {
|
|
26045
26770
|
console.error("[DurableThread] Error handling WebSocket message:", error);
|
|
26046
26771
|
}
|
|
@@ -29047,6 +29772,6 @@ init_context();
|
|
|
29047
29772
|
init_ProviderRegistry();
|
|
29048
29773
|
init_types2();
|
|
29049
29774
|
|
|
29050
|
-
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, endpointCallerFromAuth, 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 };
|
|
29051
29776
|
//# sourceMappingURL=runtime.js.map
|
|
29052
29777
|
//# sourceMappingURL=runtime.js.map
|