@standardagents/builder 0.40.5-next.3b25e2a → 0.40.6
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 +62 -102
- package/dist/built-in-routes.js.map +1 -1
- package/dist/{index-0NI3m5DR.d.ts → index-DYhbT5Eq.d.ts} +44 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +393 -246
- package/dist/index.js.map +1 -1
- package/dist/plugin.d.ts +7 -0
- package/dist/plugin.js +90 -19
- package/dist/plugin.js.map +1 -1
- package/dist/runtime.d.ts +20 -21
- package/dist/runtime.js +580 -495
- package/dist/runtime.js.map +1 -1
- package/dist/test.d.ts +1 -1
- package/package.json +8 -8
package/dist/runtime.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { getProviderModelPricing } from '@standardagents/provider-pricing';
|
|
2
2
|
import { jsonPathReader } from '@formkit/jsonreader';
|
|
3
3
|
import { ProviderError, mapReasoningLevel, THREAD_STREAM_REASONING_PARAM, isUserEndpoint } from '@standardagents/spec';
|
|
4
|
-
export { ProviderError, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel } from '@standardagents/spec';
|
|
4
|
+
export { ProviderError, belongsToPackage, defineAgent, defineHook, defineModel, definePrompt, defineProvider, defineTool, isPacked, isVisibleInNamespace, mapReasoningLevel, providerConst, providerEnv, providerValue } from '@standardagents/spec';
|
|
5
5
|
import 'virtual:@standardagents-providers';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import { transform, collect } from '@standardagents/sip';
|
|
8
8
|
import { DurableObject, WorkerEntrypoint } from 'cloudflare:workers';
|
|
9
|
+
import 'fs';
|
|
10
|
+
import 'path';
|
|
9
11
|
|
|
10
12
|
var __defProp = Object.defineProperty;
|
|
11
13
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -454,8 +456,8 @@ async function readCompletedArg(partialJson, argName) {
|
|
|
454
456
|
controller.close();
|
|
455
457
|
}
|
|
456
458
|
}).getReader();
|
|
457
|
-
for await (const [value,
|
|
458
|
-
if (
|
|
459
|
+
for await (const [value, path2] of jsonPathReader(reader, [argName])) {
|
|
460
|
+
if (path2 === argName) {
|
|
459
461
|
return typeof value === "string" ? value : void 0;
|
|
460
462
|
}
|
|
461
463
|
}
|
|
@@ -1535,11 +1537,11 @@ function stripBase64FromMessages(messages, imagePathMap) {
|
|
|
1535
1537
|
const data = part.data;
|
|
1536
1538
|
if (typeof data === "string") {
|
|
1537
1539
|
if (data.startsWith("data:") || data.length > 1e3) {
|
|
1538
|
-
const
|
|
1540
|
+
const path2 = imagePathMap?.get(data);
|
|
1539
1541
|
return {
|
|
1540
1542
|
...part,
|
|
1541
1543
|
data: "[base64 omitted]",
|
|
1542
|
-
...
|
|
1544
|
+
...path2 ? { path: path2 } : {}
|
|
1543
1545
|
};
|
|
1544
1546
|
}
|
|
1545
1547
|
}
|
|
@@ -2105,14 +2107,14 @@ var init_LLMRequest = __esm({
|
|
|
2105
2107
|
*/
|
|
2106
2108
|
static async callModel(modelId, context, state, logId) {
|
|
2107
2109
|
const { ProviderRegistry: ProviderRegistry2 } = await Promise.resolve().then(() => (init_providers(), providers_exports));
|
|
2108
|
-
const
|
|
2110
|
+
const providerEnv2 = await ProviderRegistry2.buildThreadScopedEnv(state);
|
|
2109
2111
|
const getThreadState = async () => {
|
|
2110
2112
|
const { ThreadStateImpl: ThreadStateImpl2 } = await Promise.resolve().then(() => (init_ThreadStateImpl(), ThreadStateImpl_exports));
|
|
2111
2113
|
return ThreadStateImpl2.fromFlowState(state);
|
|
2112
2114
|
};
|
|
2113
2115
|
const { provider, modelName, modelDef, viaPlatform, platformProxyOrigin } = await ProviderRegistry2.getProvider(
|
|
2114
2116
|
modelId,
|
|
2115
|
-
|
|
2117
|
+
providerEnv2,
|
|
2116
2118
|
state.thread.instance,
|
|
2117
2119
|
getThreadState
|
|
2118
2120
|
);
|
|
@@ -2755,11 +2757,11 @@ var init_LLMRequest = __esm({
|
|
|
2755
2757
|
...choice.message,
|
|
2756
2758
|
images: choice.message?.images?.map(
|
|
2757
2759
|
(img) => {
|
|
2758
|
-
const
|
|
2759
|
-
if (
|
|
2760
|
+
const path2 = img._id ? imagePathMap.get(img._id) : void 0;
|
|
2761
|
+
if (path2) {
|
|
2760
2762
|
return {
|
|
2761
2763
|
type: img.type,
|
|
2762
|
-
image_url: { url:
|
|
2764
|
+
image_url: { url: path2 }
|
|
2763
2765
|
};
|
|
2764
2766
|
}
|
|
2765
2767
|
return img;
|
|
@@ -3286,20 +3288,20 @@ function detectStorageBackend(location) {
|
|
|
3286
3288
|
return "url";
|
|
3287
3289
|
return "local";
|
|
3288
3290
|
}
|
|
3289
|
-
function basename(
|
|
3290
|
-
const parts =
|
|
3291
|
+
function basename(path2) {
|
|
3292
|
+
const parts = path2.split("/").filter(Boolean);
|
|
3291
3293
|
return parts[parts.length - 1] || "";
|
|
3292
3294
|
}
|
|
3293
|
-
function normalizePath(
|
|
3294
|
-
let normalized =
|
|
3295
|
+
function normalizePath(path2) {
|
|
3296
|
+
let normalized = path2.replace(/\/+/g, "/");
|
|
3295
3297
|
if (!normalized.startsWith("/")) normalized = "/" + normalized;
|
|
3296
3298
|
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
3297
3299
|
normalized = normalized.slice(0, -1);
|
|
3298
3300
|
}
|
|
3299
3301
|
return normalized;
|
|
3300
3302
|
}
|
|
3301
|
-
function dirname(
|
|
3302
|
-
const normalized = normalizePath(
|
|
3303
|
+
function dirname(path2) {
|
|
3304
|
+
const normalized = normalizePath(path2);
|
|
3303
3305
|
const lastSlash = normalized.lastIndexOf("/");
|
|
3304
3306
|
if (lastSlash <= 0) return "/";
|
|
3305
3307
|
return normalized.slice(0, lastSlash);
|
|
@@ -3317,7 +3319,7 @@ function validateMovePaths(source, destination, isDirectory) {
|
|
|
3317
3319
|
);
|
|
3318
3320
|
}
|
|
3319
3321
|
}
|
|
3320
|
-
function resolveRenameDestination(
|
|
3322
|
+
function resolveRenameDestination(path2, newName) {
|
|
3321
3323
|
if (typeof newName !== "string" || newName.length === 0) {
|
|
3322
3324
|
throw new Error("New name must be a non-empty string");
|
|
3323
3325
|
}
|
|
@@ -3327,7 +3329,7 @@ function resolveRenameDestination(path, newName) {
|
|
|
3327
3329
|
if (newName === "." || newName === "..") {
|
|
3328
3330
|
throw new Error("New name must not be '.' or '..'");
|
|
3329
3331
|
}
|
|
3330
|
-
const normalized = normalizePath(
|
|
3332
|
+
const normalized = normalizePath(path2);
|
|
3331
3333
|
const parent = dirname(normalized);
|
|
3332
3334
|
return parent === "/" ? `/${newName}` : `${parent}/${newName}`;
|
|
3333
3335
|
}
|
|
@@ -3451,8 +3453,8 @@ var init_files = __esm({
|
|
|
3451
3453
|
* Write a file to storage.
|
|
3452
3454
|
* Files > CHUNK_SIZE are automatically chunked into file_chunks table.
|
|
3453
3455
|
*/
|
|
3454
|
-
async writeFile(
|
|
3455
|
-
const normalizedPath = normalizePath(
|
|
3456
|
+
async writeFile(path2, data, mimeType, options) {
|
|
3457
|
+
const normalizedPath = normalizePath(path2);
|
|
3456
3458
|
const name = basename(normalizedPath);
|
|
3457
3459
|
const isText = isTextMimeType(mimeType);
|
|
3458
3460
|
const now = Date.now();
|
|
@@ -3564,8 +3566,8 @@ var init_files = __esm({
|
|
|
3564
3566
|
/**
|
|
3565
3567
|
* Link to an external file (URL, S3, R2)
|
|
3566
3568
|
*/
|
|
3567
|
-
async linkFile(
|
|
3568
|
-
const normalizedPath = normalizePath(
|
|
3569
|
+
async linkFile(path2, location, options) {
|
|
3570
|
+
const normalizedPath = normalizePath(path2);
|
|
3569
3571
|
const name = basename(normalizedPath);
|
|
3570
3572
|
const storage = detectStorageBackend(location);
|
|
3571
3573
|
const now = Date.now();
|
|
@@ -3604,8 +3606,8 @@ var init_files = __esm({
|
|
|
3604
3606
|
* WARNING: For large chunked files, this loads the entire file into memory.
|
|
3605
3607
|
* Use streamFile() for memory-efficient access to large files.
|
|
3606
3608
|
*/
|
|
3607
|
-
async readFile(
|
|
3608
|
-
const normalizedPath = normalizePath(
|
|
3609
|
+
async readFile(path2) {
|
|
3610
|
+
const normalizedPath = normalizePath(path2);
|
|
3609
3611
|
const cursor = await this.sql.exec(
|
|
3610
3612
|
`SELECT data, content, storage, is_chunked, chunk_count FROM files WHERE path = ? AND is_directory = 0`,
|
|
3611
3613
|
normalizedPath
|
|
@@ -3657,8 +3659,8 @@ var init_files = __esm({
|
|
|
3657
3659
|
* Memory-efficient way to read large chunked files.
|
|
3658
3660
|
* Yields one chunk at a time for streaming HTTP responses.
|
|
3659
3661
|
*/
|
|
3660
|
-
async *streamFile(
|
|
3661
|
-
const normalizedPath = normalizePath(
|
|
3662
|
+
async *streamFile(path2) {
|
|
3663
|
+
const normalizedPath = normalizePath(path2);
|
|
3662
3664
|
const cursor = await this.sql.exec(
|
|
3663
3665
|
`SELECT data, content, storage, is_chunked, chunk_count FROM files WHERE path = ? AND is_directory = 0`,
|
|
3664
3666
|
normalizedPath
|
|
@@ -3692,8 +3694,8 @@ var init_files = __esm({
|
|
|
3692
3694
|
/**
|
|
3693
3695
|
* Read text file content
|
|
3694
3696
|
*/
|
|
3695
|
-
async readTextFile(
|
|
3696
|
-
const normalizedPath = normalizePath(
|
|
3697
|
+
async readTextFile(path2) {
|
|
3698
|
+
const normalizedPath = normalizePath(path2);
|
|
3697
3699
|
const cursor = await this.sql.exec(
|
|
3698
3700
|
`SELECT content, data, storage FROM files WHERE path = ? AND is_directory = 0`,
|
|
3699
3701
|
normalizedPath
|
|
@@ -3711,8 +3713,8 @@ var init_files = __esm({
|
|
|
3711
3713
|
/**
|
|
3712
3714
|
* Get file metadata (stat)
|
|
3713
3715
|
*/
|
|
3714
|
-
async stat(
|
|
3715
|
-
const normalizedPath = normalizePath(
|
|
3716
|
+
async stat(path2) {
|
|
3717
|
+
const normalizedPath = normalizePath(path2);
|
|
3716
3718
|
const cursor = await this.sql.exec(
|
|
3717
3719
|
`SELECT path, name, mime_type, storage, location, size, metadata, is_directory, created_at, width, height, is_chunked, chunk_count
|
|
3718
3720
|
FROM files WHERE path = ?`,
|
|
@@ -3725,8 +3727,8 @@ var init_files = __esm({
|
|
|
3725
3727
|
/**
|
|
3726
3728
|
* Check if file or directory exists
|
|
3727
3729
|
*/
|
|
3728
|
-
async exists(
|
|
3729
|
-
const normalizedPath = normalizePath(
|
|
3730
|
+
async exists(path2) {
|
|
3731
|
+
const normalizedPath = normalizePath(path2);
|
|
3730
3732
|
const cursor = await this.sql.exec(
|
|
3731
3733
|
`SELECT COUNT(*) as count FROM files WHERE path = ?`,
|
|
3732
3734
|
normalizedPath
|
|
@@ -3736,8 +3738,8 @@ var init_files = __esm({
|
|
|
3736
3738
|
/**
|
|
3737
3739
|
* Delete a file
|
|
3738
3740
|
*/
|
|
3739
|
-
async unlink(
|
|
3740
|
-
const normalizedPath = normalizePath(
|
|
3741
|
+
async unlink(path2) {
|
|
3742
|
+
const normalizedPath = normalizePath(path2);
|
|
3741
3743
|
await this.sql.exec(
|
|
3742
3744
|
`DELETE FROM files WHERE path = ? AND is_directory = 0`,
|
|
3743
3745
|
normalizedPath
|
|
@@ -3747,8 +3749,8 @@ var init_files = __esm({
|
|
|
3747
3749
|
/**
|
|
3748
3750
|
* Create a directory marker
|
|
3749
3751
|
*/
|
|
3750
|
-
async mkdir(
|
|
3751
|
-
const normalizedPath = normalizePath(
|
|
3752
|
+
async mkdir(path2) {
|
|
3753
|
+
const normalizedPath = normalizePath(path2);
|
|
3752
3754
|
const name = basename(normalizedPath);
|
|
3753
3755
|
const now = Date.now();
|
|
3754
3756
|
await this.sql.exec(
|
|
@@ -3773,8 +3775,8 @@ var init_files = __esm({
|
|
|
3773
3775
|
/**
|
|
3774
3776
|
* List directory contents
|
|
3775
3777
|
*/
|
|
3776
|
-
async readdir(
|
|
3777
|
-
const normalizedPath = normalizePath(
|
|
3778
|
+
async readdir(path2) {
|
|
3779
|
+
const normalizedPath = normalizePath(path2);
|
|
3778
3780
|
const prefix = normalizedPath === "/" ? "/" : normalizedPath + "/";
|
|
3779
3781
|
const cursor = await this.sql.exec(
|
|
3780
3782
|
`SELECT path, name, mime_type, storage, location, size, metadata, is_directory, created_at
|
|
@@ -3792,8 +3794,8 @@ var init_files = __esm({
|
|
|
3792
3794
|
/**
|
|
3793
3795
|
* Remove empty directory
|
|
3794
3796
|
*/
|
|
3795
|
-
async rmdir(
|
|
3796
|
-
const normalizedPath = normalizePath(
|
|
3797
|
+
async rmdir(path2) {
|
|
3798
|
+
const normalizedPath = normalizePath(path2);
|
|
3797
3799
|
const prefix = normalizedPath + "/";
|
|
3798
3800
|
const cursor = await this.sql.exec(
|
|
3799
3801
|
`SELECT COUNT(*) as count FROM files WHERE path LIKE ? || '%'`,
|
|
@@ -3891,9 +3893,9 @@ var init_files = __esm({
|
|
|
3891
3893
|
* Rename a file or directory in place, keeping it in the same parent
|
|
3892
3894
|
* directory. `newName` must be a bare file name with no path separators.
|
|
3893
3895
|
*/
|
|
3894
|
-
async rename(
|
|
3895
|
-
const destination = resolveRenameDestination(
|
|
3896
|
-
return this.move(normalizePath(
|
|
3896
|
+
async rename(path2, newName) {
|
|
3897
|
+
const destination = resolveRenameDestination(path2, newName);
|
|
3898
|
+
return this.move(normalizePath(path2), destination);
|
|
3897
3899
|
}
|
|
3898
3900
|
/**
|
|
3899
3901
|
* Get storage statistics
|
|
@@ -3923,8 +3925,8 @@ var init_files = __esm({
|
|
|
3923
3925
|
/**
|
|
3924
3926
|
* Get thumbnail for an image
|
|
3925
3927
|
*/
|
|
3926
|
-
async getThumbnail(
|
|
3927
|
-
const normalizedPath = normalizePath(
|
|
3928
|
+
async getThumbnail(path2) {
|
|
3929
|
+
const normalizedPath = normalizePath(path2);
|
|
3928
3930
|
const cursor = await this.sql.exec(
|
|
3929
3931
|
`SELECT thumbnail FROM files WHERE path = ? AND is_directory = 0`,
|
|
3930
3932
|
normalizedPath
|
|
@@ -4375,8 +4377,8 @@ var init_ToolExecutor = __esm({
|
|
|
4375
4377
|
const validation = argsSchema.safeParse(args);
|
|
4376
4378
|
if (!validation.success) {
|
|
4377
4379
|
const errorMessage = validation.error.issues.map((issue) => {
|
|
4378
|
-
const
|
|
4379
|
-
return `[${
|
|
4380
|
+
const path2 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
4381
|
+
return `[${path2}] ${issue.message}`;
|
|
4380
4382
|
}).join("; ");
|
|
4381
4383
|
return {
|
|
4382
4384
|
status: "error",
|
|
@@ -5074,9 +5076,7 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5074
5076
|
if (resumable) {
|
|
5075
5077
|
await this.settleResumableChildAfterRun(
|
|
5076
5078
|
state,
|
|
5077
|
-
|
|
5078
|
-
childThreadId,
|
|
5079
|
-
childResult
|
|
5079
|
+
childThreadId
|
|
5080
5080
|
);
|
|
5081
5081
|
} else if (stub.terminateThread) {
|
|
5082
5082
|
await stub.terminateThread(childThreadId);
|
|
@@ -5088,7 +5088,7 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5088
5088
|
attachments: copiedAttachments,
|
|
5089
5089
|
subagent_id: childThreadId
|
|
5090
5090
|
};
|
|
5091
|
-
return resumable
|
|
5091
|
+
return resumable ? this.withReferenceInToolResult(toolResult, childThreadId) : toolResult;
|
|
5092
5092
|
}
|
|
5093
5093
|
const backgroundRun = (async () => {
|
|
5094
5094
|
try {
|
|
@@ -5123,9 +5123,7 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5123
5123
|
if (resumable) {
|
|
5124
5124
|
await this.settleResumableChildAfterRun(
|
|
5125
5125
|
state,
|
|
5126
|
-
|
|
5127
|
-
childThreadId,
|
|
5128
|
-
childResult
|
|
5126
|
+
childThreadId
|
|
5129
5127
|
);
|
|
5130
5128
|
} else if (stub.terminateThread) {
|
|
5131
5129
|
await stub.terminateThread(childThreadId);
|
|
@@ -5374,13 +5372,13 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5374
5372
|
new Set(
|
|
5375
5373
|
issues.map(
|
|
5376
5374
|
(issue) => Array.isArray(issue.path) ? issue.path.map(String).join(".") : String(issue.path ?? "")
|
|
5377
|
-
).filter((
|
|
5375
|
+
).filter((path2) => path2.length > 0)
|
|
5378
5376
|
)
|
|
5379
5377
|
);
|
|
5380
5378
|
const detail = issues.map((issue) => {
|
|
5381
|
-
const
|
|
5379
|
+
const path2 = Array.isArray(issue.path) ? issue.path.map(String).join(".") : "";
|
|
5382
5380
|
const message = typeof issue.message === "string" ? issue.message : "invalid value";
|
|
5383
|
-
return
|
|
5381
|
+
return path2 ? `${path2}: ${message}` : message;
|
|
5384
5382
|
}).join("; ") || parsed.error.message || "invalid arguments";
|
|
5385
5383
|
const agentLabel = agentDef.title || agentDef.name || options.agentName || qualifiedPromptName;
|
|
5386
5384
|
return {
|
|
@@ -5520,18 +5518,8 @@ Message one with subagent_message(referenceId, message).`
|
|
|
5520
5518
|
JSON.stringify(next)
|
|
5521
5519
|
);
|
|
5522
5520
|
}
|
|
5523
|
-
static
|
|
5524
|
-
|
|
5525
|
-
}
|
|
5526
|
-
static async settleResumableChildAfterRun(state, childThread, reference, result) {
|
|
5527
|
-
if (!this.isTerminalSubagentResult(result)) {
|
|
5528
|
-
await this.updateChildStatus(state, reference, "idle");
|
|
5529
|
-
return;
|
|
5530
|
-
}
|
|
5531
|
-
await this.updateChildStatus(state, reference, "terminated");
|
|
5532
|
-
if (typeof childThread.terminateThread === "function") {
|
|
5533
|
-
await childThread.terminateThread(reference);
|
|
5534
|
-
}
|
|
5521
|
+
static async settleResumableChildAfterRun(state, reference) {
|
|
5522
|
+
await this.updateChildStatus(state, reference, "idle");
|
|
5535
5523
|
}
|
|
5536
5524
|
static async buildChildInvocationMessages(state, childThread, content, receivesMessages, parentAttachments, initialArguments) {
|
|
5537
5525
|
const copiedAttachments = await this.copyAttachmentsBetweenThreads(
|
|
@@ -5739,8 +5727,8 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5739
5727
|
}
|
|
5740
5728
|
return [];
|
|
5741
5729
|
}
|
|
5742
|
-
static inferMimeTypeFromPath(
|
|
5743
|
-
const normalized =
|
|
5730
|
+
static inferMimeTypeFromPath(path2) {
|
|
5731
|
+
const normalized = path2.toLowerCase();
|
|
5744
5732
|
if (normalized.endsWith(".png")) return "image/png";
|
|
5745
5733
|
if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
|
|
5746
5734
|
if (normalized.endsWith(".webp")) return "image/webp";
|
|
@@ -5779,7 +5767,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5779
5767
|
ext: value.slice(lastDot + 1).toLowerCase()
|
|
5780
5768
|
};
|
|
5781
5769
|
}
|
|
5782
|
-
static resolveAttachmentMimeType(sourceMimeType, fallbackMimeType,
|
|
5770
|
+
static resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path2) {
|
|
5783
5771
|
const source = sourceMimeType?.trim();
|
|
5784
5772
|
if (source && source !== "application/octet-stream") {
|
|
5785
5773
|
return source;
|
|
@@ -5788,7 +5776,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5788
5776
|
if (fallback && fallback !== "application/octet-stream") {
|
|
5789
5777
|
return fallback;
|
|
5790
5778
|
}
|
|
5791
|
-
return this.inferMimeTypeFromPath(
|
|
5779
|
+
return this.inferMimeTypeFromPath(path2) ?? source ?? fallback ?? "application/octet-stream";
|
|
5792
5780
|
}
|
|
5793
5781
|
static buildAttachmentTargetPath(preferredName, mimeType, sourcePath) {
|
|
5794
5782
|
const safeName = this.sanitizeFilename(preferredName);
|
|
@@ -5885,8 +5873,8 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5885
5873
|
}
|
|
5886
5874
|
return copied;
|
|
5887
5875
|
}
|
|
5888
|
-
static async readAttachmentDataFromSource(sourceThread,
|
|
5889
|
-
const sourceData = await sourceThread.readFile(
|
|
5876
|
+
static async readAttachmentDataFromSource(sourceThread, path2, sourceFile, allowedAttachmentFetchHosts) {
|
|
5877
|
+
const sourceData = await sourceThread.readFile(path2);
|
|
5890
5878
|
if (sourceData.success && sourceData.data) {
|
|
5891
5879
|
return sourceData.data;
|
|
5892
5880
|
}
|
|
@@ -5923,7 +5911,7 @@ Reference: ${referenceId}` : `Reference: ${referenceId}`;
|
|
|
5923
5911
|
if (!attachments || attachments.length === 0) {
|
|
5924
5912
|
return "";
|
|
5925
5913
|
}
|
|
5926
|
-
const paths = attachments.map((attachment) => attachment.path).filter((
|
|
5914
|
+
const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
|
|
5927
5915
|
if (paths.length === 0) {
|
|
5928
5916
|
return "";
|
|
5929
5917
|
}
|
|
@@ -6220,7 +6208,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
6220
6208
|
mappedAttachmentValue
|
|
6221
6209
|
);
|
|
6222
6210
|
const resolvedPaths = new Set(mappedRefs.map((ref) => ref.path));
|
|
6223
|
-
const missingPaths = candidatePaths.filter((
|
|
6211
|
+
const missingPaths = candidatePaths.filter((path2) => !resolvedPaths.has(path2));
|
|
6224
6212
|
if (candidatePaths.length === 0 || missingPaths.length > 0) {
|
|
6225
6213
|
processedResult = {
|
|
6226
6214
|
status: "error",
|
|
@@ -6402,8 +6390,8 @@ ${attachmentPaths}`;
|
|
|
6402
6390
|
if (mimeType.startsWith("image/")) {
|
|
6403
6391
|
return true;
|
|
6404
6392
|
}
|
|
6405
|
-
const
|
|
6406
|
-
return
|
|
6393
|
+
const path2 = ref.path.toLowerCase();
|
|
6394
|
+
return path2.endsWith(".png") || path2.endsWith(".jpg") || path2.endsWith(".jpeg") || path2.endsWith(".webp") || path2.endsWith(".gif") || path2.endsWith(".bmp") || path2.endsWith(".svg");
|
|
6407
6395
|
});
|
|
6408
6396
|
if (imageRefs.length === 0) {
|
|
6409
6397
|
return;
|
|
@@ -6469,27 +6457,27 @@ ${attachmentPaths}`;
|
|
|
6469
6457
|
*/
|
|
6470
6458
|
static async processToolAttachments(attachments, state) {
|
|
6471
6459
|
const { FileStorage: FileStorage2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
6472
|
-
const
|
|
6460
|
+
const fs2 = new FileStorage2(state.storage.sql);
|
|
6473
6461
|
const refs = [];
|
|
6474
6462
|
for (const attachment of attachments) {
|
|
6475
6463
|
try {
|
|
6476
6464
|
const attachmentId = crypto.randomUUID();
|
|
6477
6465
|
const timestamp = Date.now();
|
|
6478
6466
|
const ext = attachment.mimeType === "image/png" ? "png" : attachment.mimeType === "image/jpeg" ? "jpg" : attachment.mimeType === "image/gif" ? "gif" : attachment.mimeType === "image/webp" ? "webp" : attachment.name.split(".").pop() || "bin";
|
|
6479
|
-
const
|
|
6467
|
+
const path2 = `/attachments/${timestamp}-${attachmentId.slice(0, 8)}.${ext}`;
|
|
6480
6468
|
const binaryString = atob(attachment.data);
|
|
6481
6469
|
const dataBuffer = new Uint8Array(binaryString.length);
|
|
6482
6470
|
for (let i = 0; i < binaryString.length; i++) {
|
|
6483
6471
|
dataBuffer[i] = binaryString.charCodeAt(i);
|
|
6484
6472
|
}
|
|
6485
|
-
await
|
|
6473
|
+
await fs2.writeFile(path2, dataBuffer.buffer, attachment.mimeType, {
|
|
6486
6474
|
width: attachment.width,
|
|
6487
6475
|
height: attachment.height
|
|
6488
6476
|
});
|
|
6489
6477
|
const ref = {
|
|
6490
6478
|
id: attachmentId,
|
|
6491
6479
|
type: "file",
|
|
6492
|
-
path,
|
|
6480
|
+
path: path2,
|
|
6493
6481
|
name: attachment.name,
|
|
6494
6482
|
mimeType: attachment.mimeType,
|
|
6495
6483
|
size: dataBuffer.byteLength
|
|
@@ -10852,20 +10840,20 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10852
10840
|
continue;
|
|
10853
10841
|
}
|
|
10854
10842
|
const attachmentId = crypto.randomUUID();
|
|
10855
|
-
const
|
|
10843
|
+
const path2 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
|
|
10856
10844
|
try {
|
|
10857
|
-
const written = await state.thread.instance.writeFile(
|
|
10845
|
+
const written = await state.thread.instance.writeFile(path2, base64Data, mimeType);
|
|
10858
10846
|
if (written && written.success === false) {
|
|
10859
10847
|
console.error("[FlowEngine] Generated image write failed:", written.error);
|
|
10860
10848
|
continue;
|
|
10861
10849
|
}
|
|
10862
10850
|
if (image.id) {
|
|
10863
|
-
imagePathMap.set(image.id,
|
|
10851
|
+
imagePathMap.set(image.id, path2);
|
|
10864
10852
|
}
|
|
10865
10853
|
refs.push({
|
|
10866
10854
|
id: attachmentId,
|
|
10867
10855
|
type: "file",
|
|
10868
|
-
path,
|
|
10856
|
+
path: path2,
|
|
10869
10857
|
name: `generated-${attachmentId}.${ext}`,
|
|
10870
10858
|
mimeType,
|
|
10871
10859
|
size: Math.ceil(base64Data.length * 3 / 4)
|
|
@@ -10930,9 +10918,9 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10930
10918
|
continue;
|
|
10931
10919
|
}
|
|
10932
10920
|
const attachmentId = crypto.randomUUID();
|
|
10933
|
-
const
|
|
10921
|
+
const path2 = `/attachments/${Date.now()}-${attachmentId.slice(0, 8)}.${ext}`;
|
|
10934
10922
|
try {
|
|
10935
|
-
const written = await state.thread.instance.writeFile(
|
|
10923
|
+
const written = await state.thread.instance.writeFile(path2, base64Data, mimeType);
|
|
10936
10924
|
if (written && written.success === false) {
|
|
10937
10925
|
console.error(`[FlowEngine] ${toolName} image write failed:`, written.error);
|
|
10938
10926
|
continue;
|
|
@@ -10940,7 +10928,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
10940
10928
|
const attachmentRef = {
|
|
10941
10929
|
id: attachmentId,
|
|
10942
10930
|
type: "file",
|
|
10943
|
-
path,
|
|
10931
|
+
path: path2,
|
|
10944
10932
|
name: `generated-${attachmentId}.${ext}`,
|
|
10945
10933
|
mimeType,
|
|
10946
10934
|
size: Math.ceil(base64Data.length * 3 / 4)
|
|
@@ -11003,7 +10991,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
11003
10991
|
content: "Image generated successfully",
|
|
11004
10992
|
status: "success",
|
|
11005
10993
|
timestamp: Date.now(),
|
|
11006
|
-
attachment_path:
|
|
10994
|
+
attachment_path: path2
|
|
11007
10995
|
});
|
|
11008
10996
|
await state.storage.sql.exec(
|
|
11009
10997
|
`UPDATE logs SET tool_results = ?1 WHERE id = ?2`,
|
|
@@ -11025,7 +11013,7 @@ ${msg.content}` : `${imageDescriptions}${nonImageList}`;
|
|
|
11025
11013
|
}
|
|
11026
11014
|
}
|
|
11027
11015
|
if (image.id) {
|
|
11028
|
-
imagePathMap.set(image.id,
|
|
11016
|
+
imagePathMap.set(image.id, path2);
|
|
11029
11017
|
}
|
|
11030
11018
|
} catch (error) {
|
|
11031
11019
|
console.error(`[FlowEngine] Failed to store provider tool result for ${toolName}:`, error);
|
|
@@ -11890,7 +11878,7 @@ async function updateThread(thread, params) {
|
|
|
11890
11878
|
}
|
|
11891
11879
|
return result.thread;
|
|
11892
11880
|
}
|
|
11893
|
-
async function writeFile(flow,
|
|
11881
|
+
async function writeFile(flow, path2, data, mimeType, options) {
|
|
11894
11882
|
const instance = flow.thread.instance;
|
|
11895
11883
|
let base64Data;
|
|
11896
11884
|
if (typeof data === "string") {
|
|
@@ -11912,7 +11900,7 @@ async function writeFile(flow, path, data, mimeType, options) {
|
|
|
11912
11900
|
}
|
|
11913
11901
|
base64Thumbnail = btoa(binary);
|
|
11914
11902
|
}
|
|
11915
|
-
const result = await instance.writeFile(
|
|
11903
|
+
const result = await instance.writeFile(path2, base64Data, mimeType, {
|
|
11916
11904
|
metadata: options?.metadata,
|
|
11917
11905
|
thumbnail: base64Thumbnail
|
|
11918
11906
|
});
|
|
@@ -11921,20 +11909,20 @@ async function writeFile(flow, path, data, mimeType, options) {
|
|
|
11921
11909
|
}
|
|
11922
11910
|
return result.file;
|
|
11923
11911
|
}
|
|
11924
|
-
async function writeImage(flow,
|
|
11925
|
-
return writeFile(flow,
|
|
11912
|
+
async function writeImage(flow, path2, data, mimeType, options) {
|
|
11913
|
+
return writeFile(flow, path2, data, mimeType, options);
|
|
11926
11914
|
}
|
|
11927
|
-
async function linkFile(flow,
|
|
11915
|
+
async function linkFile(flow, path2, location, options) {
|
|
11928
11916
|
const instance = flow.thread.instance;
|
|
11929
|
-
const result = await instance.linkFile(
|
|
11917
|
+
const result = await instance.linkFile(path2, location, options);
|
|
11930
11918
|
if (!result.success) {
|
|
11931
11919
|
throw new Error(result.error || "Failed to link file");
|
|
11932
11920
|
}
|
|
11933
11921
|
return result.file;
|
|
11934
11922
|
}
|
|
11935
|
-
async function readFile(flow,
|
|
11923
|
+
async function readFile(flow, path2) {
|
|
11936
11924
|
const instance = flow.thread.instance;
|
|
11937
|
-
const result = await instance.readFile(
|
|
11925
|
+
const result = await instance.readFile(path2);
|
|
11938
11926
|
if (!result.success) {
|
|
11939
11927
|
return null;
|
|
11940
11928
|
}
|
|
@@ -11945,45 +11933,45 @@ async function readFile(flow, path) {
|
|
|
11945
11933
|
}
|
|
11946
11934
|
return bytes.buffer;
|
|
11947
11935
|
}
|
|
11948
|
-
async function stat(flow,
|
|
11936
|
+
async function stat(flow, path2) {
|
|
11949
11937
|
const instance = flow.thread.instance;
|
|
11950
|
-
const result = await instance.statFile(
|
|
11938
|
+
const result = await instance.statFile(path2);
|
|
11951
11939
|
if (!result.success) {
|
|
11952
11940
|
return null;
|
|
11953
11941
|
}
|
|
11954
11942
|
return result.file;
|
|
11955
11943
|
}
|
|
11956
|
-
async function exists(flow,
|
|
11944
|
+
async function exists(flow, path2) {
|
|
11957
11945
|
const instance = flow.thread.instance;
|
|
11958
|
-
const result = await instance.fileExists(
|
|
11946
|
+
const result = await instance.fileExists(path2);
|
|
11959
11947
|
return result.success && result.exists;
|
|
11960
11948
|
}
|
|
11961
|
-
async function unlink(flow,
|
|
11949
|
+
async function unlink(flow, path2) {
|
|
11962
11950
|
const instance = flow.thread.instance;
|
|
11963
|
-
const result = await instance.unlinkFile(
|
|
11951
|
+
const result = await instance.unlinkFile(path2);
|
|
11964
11952
|
if (!result.success) {
|
|
11965
11953
|
throw new Error(result.error || "Failed to delete file");
|
|
11966
11954
|
}
|
|
11967
11955
|
}
|
|
11968
|
-
async function mkdir(flow,
|
|
11956
|
+
async function mkdir(flow, path2) {
|
|
11969
11957
|
const instance = flow.thread.instance;
|
|
11970
|
-
const result = await instance.mkdirFile(
|
|
11958
|
+
const result = await instance.mkdirFile(path2);
|
|
11971
11959
|
if (!result.success) {
|
|
11972
11960
|
throw new Error(result.error || "Failed to create directory");
|
|
11973
11961
|
}
|
|
11974
11962
|
return result.directory;
|
|
11975
11963
|
}
|
|
11976
|
-
async function readdir(flow,
|
|
11964
|
+
async function readdir(flow, path2) {
|
|
11977
11965
|
const instance = flow.thread.instance;
|
|
11978
|
-
const result = await instance.readdirFile(
|
|
11966
|
+
const result = await instance.readdirFile(path2);
|
|
11979
11967
|
if (!result.success) {
|
|
11980
11968
|
throw new Error(result.error || "Failed to read directory");
|
|
11981
11969
|
}
|
|
11982
11970
|
return result.files;
|
|
11983
11971
|
}
|
|
11984
|
-
async function rmdir(flow,
|
|
11972
|
+
async function rmdir(flow, path2) {
|
|
11985
11973
|
const instance = flow.thread.instance;
|
|
11986
|
-
const result = await instance.rmdirFile(
|
|
11974
|
+
const result = await instance.rmdirFile(path2);
|
|
11987
11975
|
if (!result.success) {
|
|
11988
11976
|
throw new Error(result.error || "Failed to remove directory");
|
|
11989
11977
|
}
|
|
@@ -11996,9 +11984,9 @@ async function move(flow, sourcePath, destinationPath) {
|
|
|
11996
11984
|
}
|
|
11997
11985
|
return result.file;
|
|
11998
11986
|
}
|
|
11999
|
-
async function rename(flow,
|
|
11987
|
+
async function rename(flow, path2, newName) {
|
|
12000
11988
|
const instance = flow.thread.instance;
|
|
12001
|
-
const result = await instance.renameFile(
|
|
11989
|
+
const result = await instance.renameFile(path2, newName);
|
|
12002
11990
|
if (!result.success) {
|
|
12003
11991
|
throw new Error(result.error || "Failed to rename file");
|
|
12004
11992
|
}
|
|
@@ -12012,9 +12000,9 @@ async function getFileStats(flow) {
|
|
|
12012
12000
|
}
|
|
12013
12001
|
return result.stats;
|
|
12014
12002
|
}
|
|
12015
|
-
async function getThumbnail(flow,
|
|
12003
|
+
async function getThumbnail(flow, path2) {
|
|
12016
12004
|
const instance = flow.thread.instance;
|
|
12017
|
-
const result = await instance.getFileThumbnail(
|
|
12005
|
+
const result = await instance.getFileThumbnail(path2);
|
|
12018
12006
|
if (!result.success) {
|
|
12019
12007
|
return null;
|
|
12020
12008
|
}
|
|
@@ -12025,22 +12013,22 @@ async function getThumbnail(flow, path) {
|
|
|
12025
12013
|
}
|
|
12026
12014
|
return bytes.buffer;
|
|
12027
12015
|
}
|
|
12028
|
-
async function cat(flow,
|
|
12016
|
+
async function cat(flow, path2) {
|
|
12029
12017
|
const instance = flow.thread.instance;
|
|
12030
|
-
const result = await instance.readTextFile(
|
|
12018
|
+
const result = await instance.readTextFile(path2);
|
|
12031
12019
|
if (!result.success) {
|
|
12032
12020
|
return null;
|
|
12033
12021
|
}
|
|
12034
12022
|
return result.content;
|
|
12035
12023
|
}
|
|
12036
|
-
async function head(flow,
|
|
12037
|
-
const content = await cat(flow,
|
|
12024
|
+
async function head(flow, path2, lines = 10) {
|
|
12025
|
+
const content = await cat(flow, path2);
|
|
12038
12026
|
if (content === null) return null;
|
|
12039
12027
|
const allLines = content.split("\n");
|
|
12040
12028
|
return allLines.slice(0, lines).join("\n");
|
|
12041
12029
|
}
|
|
12042
|
-
async function tail(flow,
|
|
12043
|
-
const content = await cat(flow,
|
|
12030
|
+
async function tail(flow, path2, lines = 10) {
|
|
12031
|
+
const content = await cat(flow, path2);
|
|
12044
12032
|
if (content === null) return null;
|
|
12045
12033
|
const allLines = content.split("\n");
|
|
12046
12034
|
return allLines.slice(-lines).join("\n");
|
|
@@ -12579,32 +12567,32 @@ function prepareBridge(options, reports, logs) {
|
|
|
12579
12567
|
logs
|
|
12580
12568
|
};
|
|
12581
12569
|
}
|
|
12582
|
-
function prepareNamespaceRecord(value,
|
|
12570
|
+
function prepareNamespaceRecord(value, path2, functions) {
|
|
12583
12571
|
const out = {};
|
|
12584
12572
|
for (const [key, namespace] of Object.entries(value)) {
|
|
12585
|
-
out[key] = prepareValueRecord(namespace, `${
|
|
12573
|
+
out[key] = prepareValueRecord(namespace, `${path2}.${key}`, functions);
|
|
12586
12574
|
}
|
|
12587
12575
|
return out;
|
|
12588
12576
|
}
|
|
12589
|
-
function prepareValueRecord(value,
|
|
12577
|
+
function prepareValueRecord(value, path2, functions) {
|
|
12590
12578
|
const out = {};
|
|
12591
12579
|
for (const [key, item] of Object.entries(value)) {
|
|
12592
|
-
out[key] = prepareBridgeValue(item, `${
|
|
12580
|
+
out[key] = prepareBridgeValue(item, `${path2}.${key}`, functions);
|
|
12593
12581
|
}
|
|
12594
12582
|
return out;
|
|
12595
12583
|
}
|
|
12596
|
-
function prepareBridgeValue(value,
|
|
12584
|
+
function prepareBridgeValue(value, path2, functions) {
|
|
12597
12585
|
if (typeof value === "function") {
|
|
12598
|
-
functions.set(
|
|
12599
|
-
return { __agentbuilderType: "function", id:
|
|
12586
|
+
functions.set(path2, value);
|
|
12587
|
+
return { __agentbuilderType: "function", id: path2 };
|
|
12600
12588
|
}
|
|
12601
12589
|
if (isThenable(value)) {
|
|
12602
|
-
const promiseId = `${
|
|
12590
|
+
const promiseId = `${path2}.__promise`;
|
|
12603
12591
|
functions.set(promiseId, async () => value);
|
|
12604
12592
|
return { __agentbuilderType: "promise", id: promiseId };
|
|
12605
12593
|
}
|
|
12606
12594
|
if (Array.isArray(value)) {
|
|
12607
|
-
return value.map((item, index) => prepareBridgeValue(item, `${
|
|
12595
|
+
return value.map((item, index) => prepareBridgeValue(item, `${path2}.${index}`, functions));
|
|
12608
12596
|
}
|
|
12609
12597
|
if (value && typeof value === "object") {
|
|
12610
12598
|
if (value instanceof Date || value instanceof Map || value instanceof Set || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) {
|
|
@@ -12615,7 +12603,7 @@ function prepareBridgeValue(value, path, functions) {
|
|
|
12615
12603
|
}
|
|
12616
12604
|
const out = {};
|
|
12617
12605
|
for (const [key, item] of Object.entries(value)) {
|
|
12618
|
-
out[key] = prepareBridgeValue(item, `${
|
|
12606
|
+
out[key] = prepareBridgeValue(item, `${path2}.${key}`, functions);
|
|
12619
12607
|
}
|
|
12620
12608
|
return out;
|
|
12621
12609
|
}
|
|
@@ -13490,12 +13478,12 @@ function normalizeVirtualModulePath(basePath, specifier) {
|
|
|
13490
13478
|
}
|
|
13491
13479
|
return normalized;
|
|
13492
13480
|
}
|
|
13493
|
-
function dirnameModulePath(
|
|
13494
|
-
const index =
|
|
13495
|
-
return index <= 0 ? "" :
|
|
13481
|
+
function dirnameModulePath(path2) {
|
|
13482
|
+
const index = path2.lastIndexOf("/");
|
|
13483
|
+
return index <= 0 ? "" : path2.slice(0, index);
|
|
13496
13484
|
}
|
|
13497
|
-
function hasModuleExtension(
|
|
13498
|
-
return /\.[A-Za-z0-9]+$/.test(
|
|
13485
|
+
function hasModuleExtension(path2) {
|
|
13486
|
+
return /\.[A-Za-z0-9]+$/.test(path2);
|
|
13499
13487
|
}
|
|
13500
13488
|
function resolveGraphModuleSpecifier(fromPath, specifier, modulePaths) {
|
|
13501
13489
|
const base = normalizeVirtualModulePath(dirnameModulePath(fromPath), specifier);
|
|
@@ -13852,9 +13840,9 @@ function isPlainObject2(value) {
|
|
|
13852
13840
|
const prototype = Object.getPrototypeOf(value);
|
|
13853
13841
|
return prototype === Object.prototype || prototype === null;
|
|
13854
13842
|
}
|
|
13855
|
-
function findUntransferableOption(value,
|
|
13843
|
+
function findUntransferableOption(value, path2, seen = /* @__PURE__ */ new WeakSet()) {
|
|
13856
13844
|
if (typeof value === "function" || typeof value === "symbol") {
|
|
13857
|
-
return
|
|
13845
|
+
return path2;
|
|
13858
13846
|
}
|
|
13859
13847
|
if (!value || typeof value !== "object") {
|
|
13860
13848
|
return null;
|
|
@@ -13868,7 +13856,7 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
|
|
|
13868
13856
|
seen.add(value);
|
|
13869
13857
|
if (Array.isArray(value)) {
|
|
13870
13858
|
for (const [index, item] of value.entries()) {
|
|
13871
|
-
const found = findUntransferableOption(item, `${
|
|
13859
|
+
const found = findUntransferableOption(item, `${path2}.${index}`, seen);
|
|
13872
13860
|
if (found) return found;
|
|
13873
13861
|
}
|
|
13874
13862
|
return null;
|
|
@@ -13876,9 +13864,9 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
|
|
|
13876
13864
|
if (value instanceof Map) {
|
|
13877
13865
|
let index = 0;
|
|
13878
13866
|
for (const [key, item] of value.entries()) {
|
|
13879
|
-
const foundKey = findUntransferableOption(key, `${
|
|
13867
|
+
const foundKey = findUntransferableOption(key, `${path2}.mapKey${index}`, seen);
|
|
13880
13868
|
if (foundKey) return foundKey;
|
|
13881
|
-
const foundValue = findUntransferableOption(item, `${
|
|
13869
|
+
const foundValue = findUntransferableOption(item, `${path2}.mapValue${index}`, seen);
|
|
13882
13870
|
if (foundValue) return foundValue;
|
|
13883
13871
|
index += 1;
|
|
13884
13872
|
}
|
|
@@ -13887,17 +13875,17 @@ function findUntransferableOption(value, path, seen = /* @__PURE__ */ new WeakSe
|
|
|
13887
13875
|
if (value instanceof Set) {
|
|
13888
13876
|
let index = 0;
|
|
13889
13877
|
for (const item of value.values()) {
|
|
13890
|
-
const found = findUntransferableOption(item, `${
|
|
13878
|
+
const found = findUntransferableOption(item, `${path2}.setValue${index}`, seen);
|
|
13891
13879
|
if (found) return found;
|
|
13892
13880
|
index += 1;
|
|
13893
13881
|
}
|
|
13894
13882
|
return null;
|
|
13895
13883
|
}
|
|
13896
13884
|
if (!isPlainObject2(value)) {
|
|
13897
|
-
return
|
|
13885
|
+
return path2;
|
|
13898
13886
|
}
|
|
13899
13887
|
for (const [key, item] of Object.entries(value)) {
|
|
13900
|
-
const found = findUntransferableOption(item, `${
|
|
13888
|
+
const found = findUntransferableOption(item, `${path2}.${key}`, seen);
|
|
13901
13889
|
if (found) return found;
|
|
13902
13890
|
}
|
|
13903
13891
|
return null;
|
|
@@ -14727,27 +14715,51 @@ var init_ThreadStateImpl = __esm({
|
|
|
14727
14715
|
const withWake = (threadId) => wakeUserId ? { ...request, wake: { threadId, userId: wakeUserId } } : request;
|
|
14728
14716
|
const local = await instance.openClientStream(withWake(this._metadata.id));
|
|
14729
14717
|
if (local.ok || !this.isNoClient(local)) return local;
|
|
14730
|
-
|
|
14731
|
-
|
|
14718
|
+
if (typeof instance.createProxyStreamReceiver !== "function" || typeof instance.proxyStreamReceive !== "function") {
|
|
14719
|
+
return local;
|
|
14720
|
+
}
|
|
14721
|
+
let abortRemote = null;
|
|
14722
|
+
const receiver = instance.createProxyStreamReceiver((error) => abortRemote?.(error));
|
|
14723
|
+
const discardReceiver = async (error) => {
|
|
14724
|
+
await instance.proxyStreamReceive(receiver.id, { type: "abort", error });
|
|
14725
|
+
};
|
|
14726
|
+
const namespace = instance.env.AGENT_BUILDER_THREAD;
|
|
14732
14727
|
const seen = /* @__PURE__ */ new Set([this._metadata.id]);
|
|
14733
14728
|
let parentId = await this.resolveParentThreadId(this._metadata.id);
|
|
14734
14729
|
while (parentId && !seen.has(parentId)) {
|
|
14735
14730
|
seen.add(parentId);
|
|
14736
14731
|
try {
|
|
14737
|
-
const stub =
|
|
14732
|
+
const stub = namespace.get(namespace.idFromName(parentId));
|
|
14738
14733
|
if (typeof stub.proxyStreamOpen === "function") {
|
|
14739
|
-
const opened = await stub.proxyStreamOpen(withWake(parentId)
|
|
14734
|
+
const opened = await stub.proxyStreamOpen(withWake(parentId), {
|
|
14735
|
+
threadId: this._metadata.id,
|
|
14736
|
+
receiverId: receiver.id
|
|
14737
|
+
});
|
|
14740
14738
|
if (opened.ok && opened.id) {
|
|
14739
|
+
if (opened.eventDriven !== true) {
|
|
14740
|
+
await stub.proxyStreamAbort(opened.id).catch(() => {
|
|
14741
|
+
});
|
|
14742
|
+
await discardReceiver("The ancestor runtime does not support event-driven streams.");
|
|
14743
|
+
return {
|
|
14744
|
+
ok: false,
|
|
14745
|
+
error: "The ancestor runtime does not support event-driven streams.",
|
|
14746
|
+
data: { code: "unsupported" }
|
|
14747
|
+
};
|
|
14748
|
+
}
|
|
14749
|
+
abortRemote = (error) => {
|
|
14750
|
+
void stub.proxyStreamAbort(opened.id).catch(() => {
|
|
14751
|
+
});
|
|
14752
|
+
if (error) {
|
|
14753
|
+
void instance.proxyStreamReceive(receiver.id, { type: "abort", error });
|
|
14754
|
+
}
|
|
14755
|
+
};
|
|
14741
14756
|
return {
|
|
14742
14757
|
ok: true,
|
|
14743
|
-
duplex: this.
|
|
14744
|
-
stub,
|
|
14745
|
-
opened.id,
|
|
14746
|
-
opened.parkedPull === true
|
|
14747
|
-
)
|
|
14758
|
+
duplex: this.buildEventProxyDuplex(stub, opened.id, receiver, instance)
|
|
14748
14759
|
};
|
|
14749
14760
|
}
|
|
14750
14761
|
if (opened.error && !opened.noClient) {
|
|
14762
|
+
await discardReceiver(opened.error);
|
|
14751
14763
|
return {
|
|
14752
14764
|
ok: false,
|
|
14753
14765
|
error: opened.error,
|
|
@@ -14759,69 +14771,21 @@ var init_ThreadStateImpl = __esm({
|
|
|
14759
14771
|
}
|
|
14760
14772
|
parentId = await this.resolveParentThreadId(parentId);
|
|
14761
14773
|
}
|
|
14774
|
+
await discardReceiver(local.error ?? "No execution-owner bridge is available.");
|
|
14762
14775
|
return local;
|
|
14763
14776
|
}
|
|
14764
14777
|
/**
|
|
14765
14778
|
* Build a client duplex that bridges to a stream opened on an ancestor DO
|
|
14766
|
-
* (the bridge holder)
|
|
14767
|
-
*
|
|
14768
|
-
* error, or abort, so an idle open stream performs zero repeated pulls.
|
|
14769
|
-
* Older ancestors use the bounded long-pull compatibility path. `writable`
|
|
14770
|
-
* forwards each chunk with `proxyStreamWrite`; teardown calls
|
|
14771
|
-
* `proxyStreamAbort`.
|
|
14779
|
+
* (the bridge holder). The readable is the receiver registered on this DO;
|
|
14780
|
+
* writes and terminal actions are the only child-to-ancestor RPCs.
|
|
14772
14781
|
*/
|
|
14773
|
-
|
|
14774
|
-
buildProxyDuplex(stub, id, supportsParkedPull = false) {
|
|
14775
|
-
let settleDone;
|
|
14776
|
-
const done = new Promise((r) => settleDone = r);
|
|
14782
|
+
buildEventProxyDuplex(stub, id, receiver, instance) {
|
|
14777
14783
|
let closed = false;
|
|
14778
|
-
|
|
14779
|
-
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
settleDone(result);
|
|
14784
|
+
const settleLocal = (error) => {
|
|
14785
|
+
if (typeof instance.proxyStreamReceive !== "function") return;
|
|
14786
|
+
const frame = error ? { type: "abort", error } : { type: "end" };
|
|
14787
|
+
void instance.proxyStreamReceive(receiver.id, frame);
|
|
14783
14788
|
};
|
|
14784
|
-
const readable = new ReadableStream({
|
|
14785
|
-
async pull(controller) {
|
|
14786
|
-
while (!closed) {
|
|
14787
|
-
const pullStartedAt = Date.now();
|
|
14788
|
-
let res;
|
|
14789
|
-
try {
|
|
14790
|
-
res = await stub.proxyStreamPull(
|
|
14791
|
-
id,
|
|
14792
|
-
supportsParkedPull ? void 0 : _ThreadStateImpl.PROXY_PULL_MAX_WAIT_MS
|
|
14793
|
-
);
|
|
14794
|
-
} catch (error) {
|
|
14795
|
-
controller.error(error instanceof Error ? error : new Error(String(error)));
|
|
14796
|
-
settle({ ok: false, error: "proxy stream pull failed" });
|
|
14797
|
-
return;
|
|
14798
|
-
}
|
|
14799
|
-
for (const chunk of res.chunks) {
|
|
14800
|
-
controller.enqueue(decodeStreamChunk(chunk));
|
|
14801
|
-
}
|
|
14802
|
-
if (res.done) {
|
|
14803
|
-
controller.close();
|
|
14804
|
-
settle(res.error ? { ok: false, error: res.error } : { ok: true });
|
|
14805
|
-
return;
|
|
14806
|
-
}
|
|
14807
|
-
if (res.chunks.length > 0) return;
|
|
14808
|
-
if (supportsParkedPull) {
|
|
14809
|
-
controller.error(new Error("parked proxy pull returned without data"));
|
|
14810
|
-
settle({ ok: false, error: "parked proxy pull returned without data" });
|
|
14811
|
-
return;
|
|
14812
|
-
}
|
|
14813
|
-
if (Date.now() - pullStartedAt < 250) {
|
|
14814
|
-
await new Promise((r) => setTimeout(r, 250));
|
|
14815
|
-
}
|
|
14816
|
-
}
|
|
14817
|
-
},
|
|
14818
|
-
cancel() {
|
|
14819
|
-
closed = true;
|
|
14820
|
-
void stub.proxyStreamAbort(id).catch(() => {
|
|
14821
|
-
});
|
|
14822
|
-
settle({ ok: false, error: "proxy stream reader canceled" });
|
|
14823
|
-
}
|
|
14824
|
-
});
|
|
14825
14789
|
const writable = new WritableStream({
|
|
14826
14790
|
async write(chunk) {
|
|
14827
14791
|
await stub.proxyStreamWrite(id, encodeStreamChunk(chunk));
|
|
@@ -14834,20 +14798,20 @@ var init_ThreadStateImpl = __esm({
|
|
|
14834
14798
|
closed = true;
|
|
14835
14799
|
void stub.proxyStreamAbort(id).catch(() => {
|
|
14836
14800
|
});
|
|
14837
|
-
|
|
14801
|
+
settleLocal("The proxy stream writer was aborted.");
|
|
14838
14802
|
}
|
|
14839
14803
|
});
|
|
14840
14804
|
return {
|
|
14841
|
-
readable,
|
|
14805
|
+
readable: receiver.readable,
|
|
14842
14806
|
writable,
|
|
14843
14807
|
close: (error) => {
|
|
14844
14808
|
if (closed) return;
|
|
14845
14809
|
closed = true;
|
|
14846
14810
|
void stub.proxyStreamAbort(id).catch(() => {
|
|
14847
14811
|
});
|
|
14848
|
-
|
|
14812
|
+
settleLocal(error);
|
|
14849
14813
|
},
|
|
14850
|
-
done
|
|
14814
|
+
done: receiver.done
|
|
14851
14815
|
};
|
|
14852
14816
|
}
|
|
14853
14817
|
isNoClient(res) {
|
|
@@ -14873,7 +14837,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
14873
14837
|
// ─────────────────────────────────────────────────────────────────────────
|
|
14874
14838
|
// File System
|
|
14875
14839
|
// ─────────────────────────────────────────────────────────────────────────
|
|
14876
|
-
async writeFile(
|
|
14840
|
+
async writeFile(path2, data, mimeType, options) {
|
|
14877
14841
|
const isText = this._isTextMimeType(mimeType);
|
|
14878
14842
|
if (isText) {
|
|
14879
14843
|
let textContent;
|
|
@@ -14882,7 +14846,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
14882
14846
|
} else {
|
|
14883
14847
|
textContent = new TextDecoder().decode(data);
|
|
14884
14848
|
}
|
|
14885
|
-
const result = await this._threadInstance.writeTextFile(
|
|
14849
|
+
const result = await this._threadInstance.writeTextFile(path2, textContent, mimeType, options);
|
|
14886
14850
|
return this._mapFileRecord(result.file);
|
|
14887
14851
|
} else {
|
|
14888
14852
|
let base64Data;
|
|
@@ -14902,7 +14866,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
14902
14866
|
}
|
|
14903
14867
|
base64Data = btoa(binary);
|
|
14904
14868
|
}
|
|
14905
|
-
const result = await this._threadInstance.writeFile(
|
|
14869
|
+
const result = await this._threadInstance.writeFile(path2, base64Data, mimeType, options);
|
|
14906
14870
|
return this._mapFileRecord(result.file);
|
|
14907
14871
|
}
|
|
14908
14872
|
}
|
|
@@ -14974,8 +14938,8 @@ var init_ThreadStateImpl = __esm({
|
|
|
14974
14938
|
(type) => mimeType === type || mimeType.startsWith(type + ";")
|
|
14975
14939
|
);
|
|
14976
14940
|
}
|
|
14977
|
-
async readFile(
|
|
14978
|
-
const result = await this._threadInstance.readFile(
|
|
14941
|
+
async readFile(path2) {
|
|
14942
|
+
const result = await this._threadInstance.readFile(path2);
|
|
14979
14943
|
if (!result.success || !result.data) {
|
|
14980
14944
|
return null;
|
|
14981
14945
|
}
|
|
@@ -14986,8 +14950,8 @@ var init_ThreadStateImpl = __esm({
|
|
|
14986
14950
|
}
|
|
14987
14951
|
return bytes.buffer;
|
|
14988
14952
|
}
|
|
14989
|
-
async readFileStream(
|
|
14990
|
-
const fileInfo = this._unwrapStatRecord(await this._threadInstance.statFile(
|
|
14953
|
+
async readFileStream(path2, options) {
|
|
14954
|
+
const fileInfo = this._unwrapStatRecord(await this._threadInstance.statFile(path2));
|
|
14991
14955
|
if (!fileInfo) {
|
|
14992
14956
|
return null;
|
|
14993
14957
|
}
|
|
@@ -15002,7 +14966,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
15002
14966
|
return {
|
|
15003
14967
|
[Symbol.asyncIterator]: async function* () {
|
|
15004
14968
|
if (!isChunked) {
|
|
15005
|
-
const result = await threadInstance.readFile(
|
|
14969
|
+
const result = await threadInstance.readFile(path2);
|
|
15006
14970
|
if (!result.success || !result.data) {
|
|
15007
14971
|
return;
|
|
15008
14972
|
}
|
|
@@ -15023,7 +14987,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
15023
14987
|
if (signal?.aborted) {
|
|
15024
14988
|
return;
|
|
15025
14989
|
}
|
|
15026
|
-
const result = await threadInstance.readFileChunk(
|
|
14990
|
+
const result = await threadInstance.readFileChunk(path2, i);
|
|
15027
14991
|
if (!result.success || !result.data) {
|
|
15028
14992
|
throw new Error(result.error || `Failed to read chunk ${i}`);
|
|
15029
14993
|
}
|
|
@@ -15056,31 +15020,31 @@ var init_ThreadStateImpl = __esm({
|
|
|
15056
15020
|
if (!("path" in record) && !("name" in record)) return null;
|
|
15057
15021
|
return record;
|
|
15058
15022
|
}
|
|
15059
|
-
async statFile(
|
|
15060
|
-
const record = this._unwrapStatRecord(await this._threadInstance.statFile(
|
|
15023
|
+
async statFile(path2) {
|
|
15024
|
+
const record = this._unwrapStatRecord(await this._threadInstance.statFile(path2));
|
|
15061
15025
|
return record ? this._mapFileRecord(record) : null;
|
|
15062
15026
|
}
|
|
15063
|
-
async readdirFile(
|
|
15064
|
-
const result = await this._threadInstance.readdirFile(
|
|
15027
|
+
async readdirFile(path2) {
|
|
15028
|
+
const result = await this._threadInstance.readdirFile(path2);
|
|
15065
15029
|
const entries = Array.isArray(result) ? result : result?.files;
|
|
15066
15030
|
if (!Array.isArray(entries)) {
|
|
15067
15031
|
throw new Error(
|
|
15068
|
-
result?.error || `Could not list directory: ${
|
|
15032
|
+
result?.error || `Could not list directory: ${path2}`
|
|
15069
15033
|
);
|
|
15070
15034
|
}
|
|
15071
15035
|
return {
|
|
15072
15036
|
entries: entries.map((e) => this._mapFileRecord(e))
|
|
15073
15037
|
};
|
|
15074
15038
|
}
|
|
15075
|
-
async unlinkFile(
|
|
15076
|
-
await this._threadInstance.unlinkFile(
|
|
15039
|
+
async unlinkFile(path2) {
|
|
15040
|
+
await this._threadInstance.unlinkFile(path2);
|
|
15077
15041
|
}
|
|
15078
|
-
async mkdirFile(
|
|
15079
|
-
const result = await this._threadInstance.mkdirFile(
|
|
15042
|
+
async mkdirFile(path2) {
|
|
15043
|
+
const result = await this._threadInstance.mkdirFile(path2);
|
|
15080
15044
|
return this._mapFileRecord(result);
|
|
15081
15045
|
}
|
|
15082
|
-
async rmdirFile(
|
|
15083
|
-
await this._threadInstance.rmdirFile(
|
|
15046
|
+
async rmdirFile(path2) {
|
|
15047
|
+
await this._threadInstance.rmdirFile(path2);
|
|
15084
15048
|
}
|
|
15085
15049
|
async moveFile(sourcePath, destinationPath) {
|
|
15086
15050
|
const result = await this._threadInstance.moveFile(sourcePath, destinationPath);
|
|
@@ -15089,8 +15053,8 @@ var init_ThreadStateImpl = __esm({
|
|
|
15089
15053
|
}
|
|
15090
15054
|
return this._mapFileRecord(result.file);
|
|
15091
15055
|
}
|
|
15092
|
-
async renameFile(
|
|
15093
|
-
const result = await this._threadInstance.renameFile(
|
|
15056
|
+
async renameFile(path2, newName) {
|
|
15057
|
+
const result = await this._threadInstance.renameFile(path2, newName);
|
|
15094
15058
|
if (!result.success || !result.file) {
|
|
15095
15059
|
throw new Error(result.error || "Failed to rename file");
|
|
15096
15060
|
}
|
|
@@ -15117,8 +15081,8 @@ var init_ThreadStateImpl = __esm({
|
|
|
15117
15081
|
paths: Array.isArray(results) ? results : results.paths || []
|
|
15118
15082
|
};
|
|
15119
15083
|
}
|
|
15120
|
-
async getFileThumbnail(
|
|
15121
|
-
return this._threadInstance.getFileThumbnail(
|
|
15084
|
+
async getFileThumbnail(path2) {
|
|
15085
|
+
return this._threadInstance.getFileThumbnail(path2);
|
|
15122
15086
|
}
|
|
15123
15087
|
// ─────────────────────────────────────────────────────────────────────────
|
|
15124
15088
|
// Execution State
|
|
@@ -15423,7 +15387,7 @@ var init_ThreadStateImpl = __esm({
|
|
|
15423
15387
|
const skillMd = await stub.getSkillFile(scope, name, "SKILL.md") ?? "";
|
|
15424
15388
|
return { metadata, skillMd };
|
|
15425
15389
|
},
|
|
15426
|
-
readFile: (name,
|
|
15390
|
+
readFile: (name, path2) => stub.getSkillFile(scope, name, path2),
|
|
15427
15391
|
install: async (files) => {
|
|
15428
15392
|
await requireMutationAdmin();
|
|
15429
15393
|
return stub.upsertSkill(scope, files);
|
|
@@ -15710,7 +15674,14 @@ function isHostedInstance(env) {
|
|
|
15710
15674
|
}
|
|
15711
15675
|
return Boolean(value);
|
|
15712
15676
|
}
|
|
15713
|
-
function
|
|
15677
|
+
function compiledTrustedDevHosts() {
|
|
15678
|
+
try {
|
|
15679
|
+
return typeof __STANDARD_AGENTS_TRUSTED_DEV_HOSTS__ !== "undefined" && Array.isArray(__STANDARD_AGENTS_TRUSTED_DEV_HOSTS__) ? __STANDARD_AGENTS_TRUSTED_DEV_HOSTS__ : [];
|
|
15680
|
+
} catch {
|
|
15681
|
+
return [];
|
|
15682
|
+
}
|
|
15683
|
+
}
|
|
15684
|
+
function isTrustedLocalDevelopmentRequest(request, env, trustedDevHosts = compiledTrustedDevHosts()) {
|
|
15714
15685
|
if (isHostedInstance(env)) return false;
|
|
15715
15686
|
let hostname;
|
|
15716
15687
|
try {
|
|
@@ -15718,7 +15689,7 @@ function isTrustedLocalDevelopmentRequest(request, env) {
|
|
|
15718
15689
|
} catch {
|
|
15719
15690
|
return false;
|
|
15720
15691
|
}
|
|
15721
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local");
|
|
15692
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname.endsWith(".localhost") || hostname.endsWith(".orb.local") || trustedDevHosts.some((trusted) => trusted.trim().toLowerCase() === hostname);
|
|
15722
15693
|
}
|
|
15723
15694
|
function isPublicApiRoute(routePath, request, env) {
|
|
15724
15695
|
if (PUBLIC_ROUTES.has(routePath)) return true;
|
|
@@ -19013,10 +18984,10 @@ var DurableAgentBuilder = class extends DurableObject {
|
|
|
19013
18984
|
for (const entry of value) {
|
|
19014
18985
|
if (!entry || typeof entry !== "object") continue;
|
|
19015
18986
|
const attachment = entry;
|
|
19016
|
-
const
|
|
19017
|
-
if (!
|
|
18987
|
+
const path2 = typeof attachment.path === "string" ? attachment.path.trim() : "";
|
|
18988
|
+
if (!path2) continue;
|
|
19018
18989
|
output.push({
|
|
19019
|
-
path,
|
|
18990
|
+
path: path2,
|
|
19020
18991
|
name: typeof attachment.name === "string" ? attachment.name : void 0,
|
|
19021
18992
|
mimeType: typeof attachment.mimeType === "string" ? attachment.mimeType : void 0,
|
|
19022
18993
|
size: typeof attachment.size === "number" ? attachment.size : void 0,
|
|
@@ -19033,8 +19004,8 @@ var DurableAgentBuilder = class extends DurableObject {
|
|
|
19033
19004
|
const trimmed = sanitized.replace(/^[-.]+|[-.]+$/g, "");
|
|
19034
19005
|
return trimmed || "attachment";
|
|
19035
19006
|
}
|
|
19036
|
-
inferMimeTypeFromPath(
|
|
19037
|
-
const normalized =
|
|
19007
|
+
inferMimeTypeFromPath(path2) {
|
|
19008
|
+
const normalized = path2.toLowerCase();
|
|
19038
19009
|
if (normalized.endsWith(".png")) return "image/png";
|
|
19039
19010
|
if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
|
|
19040
19011
|
if (normalized.endsWith(".webp")) return "image/webp";
|
|
@@ -19072,7 +19043,7 @@ var DurableAgentBuilder = class extends DurableObject {
|
|
|
19072
19043
|
if (!attachments || attachments.length === 0) {
|
|
19073
19044
|
return "";
|
|
19074
19045
|
}
|
|
19075
|
-
const paths = attachments.map((attachment) => attachment.path).filter((
|
|
19046
|
+
const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
|
|
19076
19047
|
if (paths.length === 0) {
|
|
19077
19048
|
return "";
|
|
19078
19049
|
}
|
|
@@ -20474,12 +20445,9 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
20474
20445
|
await parentThread.updateChildRegistryStatus(
|
|
20475
20446
|
params.parent_thread_id,
|
|
20476
20447
|
childThread.id,
|
|
20477
|
-
|
|
20448
|
+
"idle"
|
|
20478
20449
|
);
|
|
20479
20450
|
}
|
|
20480
|
-
if (childResult.terminal && typeof childThreadStub.terminateThread === "function") {
|
|
20481
|
-
await childThreadStub.terminateThread(childThread.id);
|
|
20482
|
-
}
|
|
20483
20451
|
} else if (typeof childThreadStub.terminateThread === "function") {
|
|
20484
20452
|
await childThreadStub.terminateThread(childThread.id);
|
|
20485
20453
|
}
|
|
@@ -21752,7 +21720,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
21752
21720
|
for (const row of cursor.toArray()) {
|
|
21753
21721
|
if (skills.has(row.name)) continue;
|
|
21754
21722
|
const parsedFiles = row.files ? JSON.parse(row.files) : [];
|
|
21755
|
-
const files = Array.isArray(parsedFiles) ? parsedFiles.filter((
|
|
21723
|
+
const files = Array.isArray(parsedFiles) ? parsedFiles.filter((path2) => typeof path2 === "string").sort() : [];
|
|
21756
21724
|
skills.set(row.name, {
|
|
21757
21725
|
name: row.name,
|
|
21758
21726
|
description: row.description,
|
|
@@ -21770,7 +21738,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
21770
21738
|
return all.find((s) => s.name === name) ?? null;
|
|
21771
21739
|
}
|
|
21772
21740
|
/** One bundled file's text (null when the skill or file is missing). */
|
|
21773
|
-
async getSkillFile(scope, name,
|
|
21741
|
+
async getSkillFile(scope, name, path2) {
|
|
21774
21742
|
await this.ensureMigrated();
|
|
21775
21743
|
const cursor = await this.ctx.storage.sql.exec(
|
|
21776
21744
|
`SELECT f.content FROM skill_files f
|
|
@@ -21780,7 +21748,7 @@ ${result ?? error ?? "No result content."}${attachmentSummary}`;
|
|
|
21780
21748
|
ORDER BY CASE WHEN f.owner_id = ? THEN 0 ELSE 1 END
|
|
21781
21749
|
LIMIT 1`,
|
|
21782
21750
|
name,
|
|
21783
|
-
|
|
21751
|
+
path2.replace(/^\.\//, ""),
|
|
21784
21752
|
scope.ownerId,
|
|
21785
21753
|
scope.includeShared ? 1 : 0,
|
|
21786
21754
|
scope.ownerId
|
|
@@ -22075,12 +22043,12 @@ async function authorizesToolDelivery(pending, proof) {
|
|
|
22075
22043
|
return matchesToolDeliveryOwner(pending, proof) && await matchesToolDeliveryToken(pending.delivery_token_hash, proof.token);
|
|
22076
22044
|
}
|
|
22077
22045
|
var RUNTIME_STORAGE_PREFIX = "__agentbuilder_runtime_storage__:";
|
|
22078
|
-
function normalizeEndpointThreadPath(
|
|
22079
|
-
if (!
|
|
22046
|
+
function normalizeEndpointThreadPath(path2) {
|
|
22047
|
+
if (!path2 || /^[A-Za-z][A-Za-z\d+\-.]*:/.test(path2)) {
|
|
22080
22048
|
throw new Error("Use a relative thread filesystem path");
|
|
22081
22049
|
}
|
|
22082
22050
|
const parts = [];
|
|
22083
|
-
for (const part of
|
|
22051
|
+
for (const part of path2.replace(/\\/g, "/").split("/")) {
|
|
22084
22052
|
if (!part || part === ".") continue;
|
|
22085
22053
|
if (part === "..") {
|
|
22086
22054
|
if (parts.length === 0) throw new Error("Path cannot escape the thread filesystem root");
|
|
@@ -22130,12 +22098,12 @@ function createEndpointFetchBridge() {
|
|
|
22130
22098
|
function createEndpointFsBridge(state) {
|
|
22131
22099
|
const decoder = new TextDecoder();
|
|
22132
22100
|
return {
|
|
22133
|
-
readFile: async (
|
|
22134
|
-
const data = await state.readFile(normalizeEndpointThreadPath(
|
|
22101
|
+
readFile: async (path2) => {
|
|
22102
|
+
const data = await state.readFile(normalizeEndpointThreadPath(path2));
|
|
22135
22103
|
return data ? decoder.decode(data) : null;
|
|
22136
22104
|
},
|
|
22137
|
-
writeFile: async (
|
|
22138
|
-
return state.writeFile(normalizeEndpointThreadPath(
|
|
22105
|
+
writeFile: async (path2, content, mimeType = "text/plain") => {
|
|
22106
|
+
return state.writeFile(normalizeEndpointThreadPath(path2), content, mimeType);
|
|
22139
22107
|
}
|
|
22140
22108
|
};
|
|
22141
22109
|
}
|
|
@@ -22204,24 +22172,24 @@ function createEndpointThreadStateBridge(state) {
|
|
|
22204
22172
|
emit: (event, data) => state.emit(event, data),
|
|
22205
22173
|
getValue: (key) => state.getValue(key),
|
|
22206
22174
|
setValue: (key, value) => state.setValue(key, value),
|
|
22207
|
-
readFile: (
|
|
22208
|
-
writeFile: (
|
|
22209
|
-
return state.writeFile(normalizeEndpointThreadPath(
|
|
22175
|
+
readFile: (path2) => state.readFile(normalizeEndpointThreadPath(path2)),
|
|
22176
|
+
writeFile: (path2, data, mimeType = "application/octet-stream", options) => {
|
|
22177
|
+
return state.writeFile(normalizeEndpointThreadPath(path2), data, mimeType, options);
|
|
22210
22178
|
},
|
|
22211
|
-
statFile: (
|
|
22212
|
-
readdirFile: (
|
|
22213
|
-
unlinkFile: (
|
|
22214
|
-
mkdirFile: (
|
|
22215
|
-
rmdirFile: (
|
|
22179
|
+
statFile: (path2) => state.statFile(normalizeEndpointThreadPath(path2)),
|
|
22180
|
+
readdirFile: (path2) => state.readdirFile(normalizeEndpointThreadPath(path2)),
|
|
22181
|
+
unlinkFile: (path2) => state.unlinkFile(normalizeEndpointThreadPath(path2)),
|
|
22182
|
+
mkdirFile: (path2) => state.mkdirFile(normalizeEndpointThreadPath(path2)),
|
|
22183
|
+
rmdirFile: (path2) => state.rmdirFile(normalizeEndpointThreadPath(path2)),
|
|
22216
22184
|
moveFile: (sourcePath, destinationPath) => state.moveFile(
|
|
22217
22185
|
normalizeEndpointThreadPath(sourcePath),
|
|
22218
22186
|
normalizeEndpointThreadPath(destinationPath)
|
|
22219
22187
|
),
|
|
22220
|
-
renameFile: (
|
|
22188
|
+
renameFile: (path2, newName) => state.renameFile(normalizeEndpointThreadPath(path2), newName),
|
|
22221
22189
|
getFileStats: () => state.getFileStats(),
|
|
22222
22190
|
grepFiles: (pattern) => state.grepFiles(pattern),
|
|
22223
22191
|
findFiles: (pattern) => state.findFiles(pattern),
|
|
22224
|
-
getFileThumbnail: (
|
|
22192
|
+
getFileThumbnail: (path2) => state.getFileThumbnail(normalizeEndpointThreadPath(path2))
|
|
22225
22193
|
};
|
|
22226
22194
|
}
|
|
22227
22195
|
function routeBridgeClientFrame(socket, message, handlers) {
|
|
@@ -22274,6 +22242,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22274
22242
|
// opened on and dies with it. Streams are in-memory only — they exist solely
|
|
22275
22243
|
// while the client is attached and never park durably.
|
|
22276
22244
|
clientStreams = /* @__PURE__ */ new Map();
|
|
22245
|
+
proxyStreamReceivers = /* @__PURE__ */ new Map();
|
|
22246
|
+
eventProxyStreams = /* @__PURE__ */ new Map();
|
|
22277
22247
|
alarmQueue;
|
|
22278
22248
|
runtimeSafety;
|
|
22279
22249
|
alarmQueueRearmed = false;
|
|
@@ -22385,6 +22355,10 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22385
22355
|
clientName: typeof attachment.clientName === "string" ? attachment.clientName : null,
|
|
22386
22356
|
clientKind: typeof attachment.clientKind === "string" ? attachment.clientKind : null
|
|
22387
22357
|
});
|
|
22358
|
+
const interrupted = this.parseProxyStreamAttachments(attachment.proxyStreams);
|
|
22359
|
+
if (interrupted.length > 0) {
|
|
22360
|
+
this.recoverInterruptedProxyStreams(ws, interrupted);
|
|
22361
|
+
}
|
|
22388
22362
|
}
|
|
22389
22363
|
}
|
|
22390
22364
|
}
|
|
@@ -22973,7 +22947,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22973
22947
|
this.assertJsonSerializableThreadValue(value, "$", /* @__PURE__ */ new WeakSet());
|
|
22974
22948
|
return JSON.stringify(value);
|
|
22975
22949
|
}
|
|
22976
|
-
assertJsonSerializableThreadValue(value,
|
|
22950
|
+
assertJsonSerializableThreadValue(value, path2, seen) {
|
|
22977
22951
|
if (value === null) {
|
|
22978
22952
|
return;
|
|
22979
22953
|
}
|
|
@@ -22983,36 +22957,36 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
22983
22957
|
return;
|
|
22984
22958
|
case "number":
|
|
22985
22959
|
if (!Number.isFinite(value)) {
|
|
22986
|
-
throw new Error(`Thread value at ${
|
|
22960
|
+
throw new Error(`Thread value at ${path2} must be a finite number`);
|
|
22987
22961
|
}
|
|
22988
22962
|
return;
|
|
22989
22963
|
case "object": {
|
|
22990
22964
|
if (seen.has(value)) {
|
|
22991
|
-
throw new Error(`Thread value at ${
|
|
22965
|
+
throw new Error(`Thread value at ${path2} cannot contain circular references`);
|
|
22992
22966
|
}
|
|
22993
22967
|
seen.add(value);
|
|
22994
22968
|
if (Array.isArray(value)) {
|
|
22995
22969
|
for (let i = 0; i < value.length; i += 1) {
|
|
22996
|
-
this.assertJsonSerializableThreadValue(value[i], `${
|
|
22970
|
+
this.assertJsonSerializableThreadValue(value[i], `${path2}[${i}]`, seen);
|
|
22997
22971
|
}
|
|
22998
22972
|
seen.delete(value);
|
|
22999
22973
|
return;
|
|
23000
22974
|
}
|
|
23001
22975
|
const prototype = Object.getPrototypeOf(value);
|
|
23002
22976
|
if (prototype !== Object.prototype && prototype !== null) {
|
|
23003
|
-
throw new Error(`Thread value at ${
|
|
22977
|
+
throw new Error(`Thread value at ${path2} must be a JSON object, array, or primitive`);
|
|
23004
22978
|
}
|
|
23005
22979
|
if (Object.getOwnPropertySymbols(value).length > 0) {
|
|
23006
|
-
throw new Error(`Thread value at ${
|
|
22980
|
+
throw new Error(`Thread value at ${path2} cannot contain symbol keys`);
|
|
23007
22981
|
}
|
|
23008
22982
|
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
23009
|
-
this.assertJsonSerializableThreadValue(entryValue, `${
|
|
22983
|
+
this.assertJsonSerializableThreadValue(entryValue, `${path2}.${entryKey}`, seen);
|
|
23010
22984
|
}
|
|
23011
22985
|
seen.delete(value);
|
|
23012
22986
|
return;
|
|
23013
22987
|
}
|
|
23014
22988
|
default:
|
|
23015
|
-
throw new Error(`Thread value at ${
|
|
22989
|
+
throw new Error(`Thread value at ${path2} must be JSON-serializable`);
|
|
23016
22990
|
}
|
|
23017
22991
|
}
|
|
23018
22992
|
// ============================================================
|
|
@@ -24213,8 +24187,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
24213
24187
|
);
|
|
24214
24188
|
return terminalCursor.toArray()[0] ?? null;
|
|
24215
24189
|
}
|
|
24216
|
-
inferMimeTypeFromPath(
|
|
24217
|
-
const normalized =
|
|
24190
|
+
inferMimeTypeFromPath(path2) {
|
|
24191
|
+
const normalized = path2.toLowerCase();
|
|
24218
24192
|
if (normalized.endsWith(".png")) return "image/png";
|
|
24219
24193
|
if (normalized.endsWith(".jpg") || normalized.endsWith(".jpeg")) return "image/jpeg";
|
|
24220
24194
|
if (normalized.endsWith(".webp")) return "image/webp";
|
|
@@ -24253,7 +24227,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
24253
24227
|
ext: value.slice(lastDot + 1).toLowerCase()
|
|
24254
24228
|
};
|
|
24255
24229
|
}
|
|
24256
|
-
resolveAttachmentMimeType(sourceMimeType, fallbackMimeType,
|
|
24230
|
+
resolveAttachmentMimeType(sourceMimeType, fallbackMimeType, path2) {
|
|
24257
24231
|
const source = sourceMimeType?.trim();
|
|
24258
24232
|
if (source && source !== "application/octet-stream") {
|
|
24259
24233
|
return source;
|
|
@@ -24262,7 +24236,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
24262
24236
|
if (fallback && fallback !== "application/octet-stream") {
|
|
24263
24237
|
return fallback;
|
|
24264
24238
|
}
|
|
24265
|
-
return this.inferMimeTypeFromPath(
|
|
24239
|
+
return this.inferMimeTypeFromPath(path2) ?? source ?? fallback ?? "application/octet-stream";
|
|
24266
24240
|
}
|
|
24267
24241
|
buildAttachmentTargetPath(preferredName, mimeType, sourcePath) {
|
|
24268
24242
|
const safeName = this.sanitizeFilename(preferredName);
|
|
@@ -24357,8 +24331,8 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
24357
24331
|
}
|
|
24358
24332
|
return copied;
|
|
24359
24333
|
}
|
|
24360
|
-
async readAttachmentDataFromSource(
|
|
24361
|
-
const sourceData = await this.readFile(
|
|
24334
|
+
async readAttachmentDataFromSource(path2, sourceFile) {
|
|
24335
|
+
const sourceData = await this.readFile(path2);
|
|
24362
24336
|
if (sourceData.success && sourceData.data) {
|
|
24363
24337
|
return sourceData.data;
|
|
24364
24338
|
}
|
|
@@ -24395,7 +24369,7 @@ var DurableThread = class _DurableThread extends DurableObject {
|
|
|
24395
24369
|
if (!attachments || attachments.length === 0) {
|
|
24396
24370
|
return "";
|
|
24397
24371
|
}
|
|
24398
|
-
const paths = attachments.map((attachment) => attachment.path).filter((
|
|
24372
|
+
const paths = attachments.map((attachment) => attachment.path).filter((path2) => typeof path2 === "string" && path2.length > 0);
|
|
24399
24373
|
if (paths.length === 0) {
|
|
24400
24374
|
return "";
|
|
24401
24375
|
}
|
|
@@ -24475,11 +24449,13 @@ ${paths.join("\n")}`;
|
|
|
24475
24449
|
try {
|
|
24476
24450
|
const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
|
|
24477
24451
|
const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
|
|
24478
|
-
const
|
|
24452
|
+
const childRegistryEntry = await this.getParentRegistryEntryForChild(
|
|
24479
24453
|
parentStub,
|
|
24480
24454
|
parentThreadId,
|
|
24481
24455
|
threadId
|
|
24482
24456
|
);
|
|
24457
|
+
const parentCommunication = childRegistryEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
|
|
24458
|
+
const resumableChild = childRegistryEntry?.resumable === true;
|
|
24483
24459
|
const copiedRefs = await this.copyAttachmentRefsToThread(
|
|
24484
24460
|
refs,
|
|
24485
24461
|
parentStub,
|
|
@@ -24502,10 +24478,11 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24502
24478
|
});
|
|
24503
24479
|
}
|
|
24504
24480
|
const terminalChildRun = sessionStopped || hasTerminalSessionTools;
|
|
24481
|
+
const terminateChildThread = terminalChildRun && !resumableChild;
|
|
24505
24482
|
await parentStub.updateChildRegistryStatus(
|
|
24506
24483
|
parentThreadId,
|
|
24507
24484
|
threadId,
|
|
24508
|
-
|
|
24485
|
+
terminateChildThread ? "terminated" : "idle"
|
|
24509
24486
|
);
|
|
24510
24487
|
if (parentCommunication !== "explicit") {
|
|
24511
24488
|
await this.persistParentHandoffStatusMessage(
|
|
@@ -24513,23 +24490,22 @@ ${resultContent}${attachmentSummary}`;
|
|
|
24513
24490
|
isErrorTerminal ? "failure" : "result"
|
|
24514
24491
|
);
|
|
24515
24492
|
}
|
|
24516
|
-
if (
|
|
24493
|
+
if (terminateChildThread) {
|
|
24517
24494
|
await this.terminateThread(threadId);
|
|
24518
24495
|
}
|
|
24519
24496
|
} catch (error) {
|
|
24520
24497
|
console.error("[DurableThread] Failed to deliver subagent completion to parent:", error);
|
|
24521
24498
|
}
|
|
24522
24499
|
}
|
|
24523
|
-
async
|
|
24500
|
+
async getParentRegistryEntryForChild(parentStub, parentThreadId, childThreadId) {
|
|
24524
24501
|
if (typeof parentStub.getChildrenRegistry !== "function") {
|
|
24525
|
-
return
|
|
24502
|
+
return void 0;
|
|
24526
24503
|
}
|
|
24527
24504
|
try {
|
|
24528
24505
|
const entries = await parentStub.getChildrenRegistry(parentThreadId);
|
|
24529
|
-
|
|
24530
|
-
return childEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
|
|
24506
|
+
return entries.find((entry) => entry.reference === childThreadId);
|
|
24531
24507
|
} catch {
|
|
24532
|
-
return
|
|
24508
|
+
return void 0;
|
|
24533
24509
|
}
|
|
24534
24510
|
}
|
|
24535
24511
|
/**
|
|
@@ -26077,7 +26053,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26077
26053
|
void 0,
|
|
26078
26054
|
INTERNAL_TOOL_DELIVERY
|
|
26079
26055
|
);
|
|
26080
|
-
if (delivered
|
|
26056
|
+
if (delivered) sides.add(delivered.side);
|
|
26081
26057
|
}
|
|
26082
26058
|
if (threadId) {
|
|
26083
26059
|
for (const side of sides) {
|
|
@@ -26379,17 +26355,14 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26379
26355
|
deliveredResultWaiters = /* @__PURE__ */ new Map();
|
|
26380
26356
|
notifyDeliveredResultWaiters(toolCallId) {
|
|
26381
26357
|
const waiters = this.deliveredResultWaiters?.get(toolCallId);
|
|
26382
|
-
if (!waiters
|
|
26358
|
+
if (!waiters) return;
|
|
26383
26359
|
this.deliveredResultWaiters.delete(toolCallId);
|
|
26384
|
-
let notified = false;
|
|
26385
26360
|
for (const wake of waiters) {
|
|
26386
26361
|
try {
|
|
26387
26362
|
wake();
|
|
26388
|
-
notified = true;
|
|
26389
26363
|
} catch {
|
|
26390
26364
|
}
|
|
26391
26365
|
}
|
|
26392
|
-
return notified;
|
|
26393
26366
|
}
|
|
26394
26367
|
/**
|
|
26395
26368
|
* Await a parked forwarded call's delivered result: one immediate read,
|
|
@@ -26534,46 +26507,37 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26534
26507
|
const side = pending.side === "b" ? "b" : "a";
|
|
26535
26508
|
const content = ok ? result ?? "" : `Error: ${error ?? "tool failed"}`;
|
|
26536
26509
|
const toolStatus = ok ? "success" : "error";
|
|
26537
|
-
|
|
26538
|
-
|
|
26539
|
-
|
|
26540
|
-
|
|
26541
|
-
|
|
26542
|
-
|
|
26543
|
-
|
|
26510
|
+
await this.ctx.storage.sql.exec(
|
|
26511
|
+
`UPDATE messages SET content = ?, tool_status = ? WHERE tool_call_id = ? AND role = 'tool'`,
|
|
26512
|
+
content,
|
|
26513
|
+
toolStatus,
|
|
26514
|
+
toolCallId
|
|
26515
|
+
);
|
|
26516
|
+
const updated = await this.ctx.storage.sql.exec(
|
|
26517
|
+
`SELECT COUNT(*) AS total FROM messages WHERE tool_call_id = ? AND role = 'tool'`,
|
|
26518
|
+
toolCallId
|
|
26519
|
+
);
|
|
26520
|
+
if (Number(updated.toArray()[0]?.total ?? 0) === 0) {
|
|
26521
|
+
const toolRow = await this.ctx.storage.sql.exec(
|
|
26522
|
+
`SELECT tool FROM pending_client_calls WHERE tool_call_id = ? LIMIT 1`,
|
|
26544
26523
|
toolCallId
|
|
26545
26524
|
);
|
|
26546
|
-
|
|
26547
|
-
|
|
26548
|
-
|
|
26525
|
+
await this.ctx.storage.sql.exec(
|
|
26526
|
+
`INSERT INTO messages (id, role, content, name, tool_call_id, tool_status, created_at, status, prompt)
|
|
26527
|
+
VALUES (?, 'tool', ?, ?, ?, ?, ?, 'completed', NULL)`,
|
|
26528
|
+
crypto.randomUUID(),
|
|
26549
26529
|
content,
|
|
26530
|
+
toolRow.toArray()[0]?.tool ?? null,
|
|
26531
|
+
toolCallId,
|
|
26550
26532
|
toolStatus,
|
|
26551
|
-
|
|
26552
|
-
);
|
|
26553
|
-
const updated = this.ctx.storage.sql.exec(
|
|
26554
|
-
`SELECT COUNT(*) AS total FROM messages WHERE tool_call_id = ? AND role = 'tool'`,
|
|
26555
|
-
toolCallId
|
|
26533
|
+
Date.now() * TIMESTAMP_MULTIPLIER
|
|
26556
26534
|
);
|
|
26557
|
-
|
|
26558
|
-
|
|
26559
|
-
|
|
26560
|
-
|
|
26561
|
-
|
|
26562
|
-
|
|
26563
|
-
`INSERT INTO messages (id, role, content, name, tool_call_id, tool_status, created_at, status, prompt)
|
|
26564
|
-
VALUES (?, 'tool', ?, ?, ?, ?, ?, 'completed', NULL)`,
|
|
26565
|
-
resultMessageId,
|
|
26566
|
-
content,
|
|
26567
|
-
toolRow.toArray()[0]?.tool ?? null,
|
|
26568
|
-
toolCallId,
|
|
26569
|
-
toolStatus,
|
|
26570
|
-
resultCreatedAt
|
|
26571
|
-
);
|
|
26572
|
-
}
|
|
26573
|
-
return true;
|
|
26574
|
-
});
|
|
26575
|
-
if (!accepted) return null;
|
|
26576
|
-
const resumedInline = this.notifyDeliveredResultWaiters(toolCallId);
|
|
26535
|
+
}
|
|
26536
|
+
await this.ctx.storage.sql.exec(
|
|
26537
|
+
`UPDATE pending_client_calls SET status = 'resolved' WHERE tool_call_id = ?`,
|
|
26538
|
+
toolCallId
|
|
26539
|
+
);
|
|
26540
|
+
this.notifyDeliveredResultWaiters(toolCallId);
|
|
26577
26541
|
try {
|
|
26578
26542
|
const msgCursor = await this.ctx.storage.sql.exec(
|
|
26579
26543
|
`SELECT id, role, content, name, tool_call_id, tool_status, created_at, depth
|
|
@@ -26584,7 +26548,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26584
26548
|
if (msg) this.broadcastMessage(msg);
|
|
26585
26549
|
} catch {
|
|
26586
26550
|
}
|
|
26587
|
-
return { side
|
|
26551
|
+
return { side };
|
|
26588
26552
|
}
|
|
26589
26553
|
// ─── Runtime byte streams ──────────────────────────────────────────────────
|
|
26590
26554
|
// The existing bridge frames carry opaque capability metadata and bytes
|
|
@@ -26650,8 +26614,138 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26650
26614
|
});
|
|
26651
26615
|
}
|
|
26652
26616
|
}
|
|
26617
|
+
parseProxyStreamAttachments(value) {
|
|
26618
|
+
if (!Array.isArray(value)) return [];
|
|
26619
|
+
const parsed = [];
|
|
26620
|
+
for (const item of value) {
|
|
26621
|
+
if (!item || typeof item !== "object") continue;
|
|
26622
|
+
const candidate = item;
|
|
26623
|
+
if (typeof candidate.id === "string" && candidate.target && typeof candidate.target.threadId === "string" && typeof candidate.target.receiverId === "string") {
|
|
26624
|
+
parsed.push({
|
|
26625
|
+
id: candidate.id,
|
|
26626
|
+
target: {
|
|
26627
|
+
threadId: candidate.target.threadId,
|
|
26628
|
+
receiverId: candidate.target.receiverId
|
|
26629
|
+
}
|
|
26630
|
+
});
|
|
26631
|
+
}
|
|
26632
|
+
}
|
|
26633
|
+
return parsed;
|
|
26634
|
+
}
|
|
26635
|
+
/** Keep live proxy routes on the hibernating bridge socket for restart cleanup. */
|
|
26636
|
+
updateBridgeProxyAttachment(socket) {
|
|
26637
|
+
if (typeof socket.serializeAttachment !== "function") return;
|
|
26638
|
+
let attachment = { type: "bridge" };
|
|
26639
|
+
try {
|
|
26640
|
+
const current = socket.deserializeAttachment();
|
|
26641
|
+
if (current && typeof current === "object") {
|
|
26642
|
+
attachment = { ...current };
|
|
26643
|
+
}
|
|
26644
|
+
} catch {
|
|
26645
|
+
}
|
|
26646
|
+
const proxyStreams = Array.from(this.clientStreams.entries()).filter(([, state]) => state.socket === socket && state.proxyTarget !== null).map(([id, state]) => ({ id, target: state.proxyTarget }));
|
|
26647
|
+
try {
|
|
26648
|
+
socket.serializeAttachment({ ...attachment, proxyStreams });
|
|
26649
|
+
} catch {
|
|
26650
|
+
}
|
|
26651
|
+
}
|
|
26652
|
+
async deliverProxyStreamFrame(target, frame) {
|
|
26653
|
+
try {
|
|
26654
|
+
const namespace = this.env.AGENT_BUILDER_THREAD;
|
|
26655
|
+
const stub = namespace.get(namespace.idFromName(target.threadId));
|
|
26656
|
+
return await stub.proxyStreamReceive(target.receiverId, frame);
|
|
26657
|
+
} catch {
|
|
26658
|
+
return false;
|
|
26659
|
+
}
|
|
26660
|
+
}
|
|
26661
|
+
/** Abort live proxy routes restored without their in-memory stream state. */
|
|
26662
|
+
recoverInterruptedProxyStreams(socket, streams) {
|
|
26663
|
+
const error = "The stream ended because its runtime restarted.";
|
|
26664
|
+
for (const stream of streams) {
|
|
26665
|
+
try {
|
|
26666
|
+
if (socket.readyState === WebSocket.OPEN) {
|
|
26667
|
+
socket.send(JSON.stringify({ type: "stream_abort", id: stream.id, error }));
|
|
26668
|
+
}
|
|
26669
|
+
} catch {
|
|
26670
|
+
}
|
|
26671
|
+
this.ctx.waitUntil(
|
|
26672
|
+
this.deliverProxyStreamFrame(stream.target, { type: "abort", error }).then(() => {
|
|
26673
|
+
})
|
|
26674
|
+
);
|
|
26675
|
+
}
|
|
26676
|
+
this.updateBridgeProxyAttachment(socket);
|
|
26677
|
+
}
|
|
26678
|
+
/** Register the child side before any ancestor opens an owner stream. */
|
|
26679
|
+
createProxyStreamReceiver(onCancel) {
|
|
26680
|
+
const id = crypto.randomUUID();
|
|
26681
|
+
let controller = null;
|
|
26682
|
+
let settleDone;
|
|
26683
|
+
const done = new Promise((resolve) => {
|
|
26684
|
+
settleDone = resolve;
|
|
26685
|
+
});
|
|
26686
|
+
const readable = new ReadableStream({
|
|
26687
|
+
start(value) {
|
|
26688
|
+
controller = value;
|
|
26689
|
+
},
|
|
26690
|
+
cancel: (reason) => {
|
|
26691
|
+
const receiver2 = this.proxyStreamReceivers.get(id);
|
|
26692
|
+
if (!receiver2 || receiver2.settled) return;
|
|
26693
|
+
const error = reason instanceof Error ? reason.message : typeof reason === "string" ? reason : "The proxy stream reader was canceled.";
|
|
26694
|
+
receiver2.settle({ ok: false, error });
|
|
26695
|
+
receiver2.onCancel(error);
|
|
26696
|
+
}
|
|
26697
|
+
});
|
|
26698
|
+
const receiver = {
|
|
26699
|
+
controller,
|
|
26700
|
+
settle: (result) => {
|
|
26701
|
+
if (receiver.settled) return;
|
|
26702
|
+
receiver.settled = true;
|
|
26703
|
+
this.proxyStreamReceivers.delete(id);
|
|
26704
|
+
settleDone(result);
|
|
26705
|
+
},
|
|
26706
|
+
onCancel,
|
|
26707
|
+
settled: false
|
|
26708
|
+
};
|
|
26709
|
+
this.proxyStreamReceivers.set(id, receiver);
|
|
26710
|
+
return { id, readable, done };
|
|
26711
|
+
}
|
|
26712
|
+
async proxyStreamReceiverExists(receiverId) {
|
|
26713
|
+
return this.proxyStreamReceivers.has(receiverId);
|
|
26714
|
+
}
|
|
26715
|
+
async proxyStreamReceive(receiverId, frame) {
|
|
26716
|
+
const receiver = this.proxyStreamReceivers.get(receiverId);
|
|
26717
|
+
if (!receiver || receiver.settled) return false;
|
|
26718
|
+
if (frame.type === "data") {
|
|
26719
|
+
try {
|
|
26720
|
+
receiver.controller?.enqueue(decodeStreamChunk(frame.data));
|
|
26721
|
+
} catch (error2) {
|
|
26722
|
+
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
26723
|
+
try {
|
|
26724
|
+
receiver.controller?.error(error2 instanceof Error ? error2 : new Error(message));
|
|
26725
|
+
} catch {
|
|
26726
|
+
}
|
|
26727
|
+
receiver.settle({ ok: false, error: message });
|
|
26728
|
+
}
|
|
26729
|
+
return true;
|
|
26730
|
+
}
|
|
26731
|
+
if (frame.type === "end") {
|
|
26732
|
+
try {
|
|
26733
|
+
receiver.controller?.close();
|
|
26734
|
+
} catch {
|
|
26735
|
+
}
|
|
26736
|
+
receiver.settle({ ok: true });
|
|
26737
|
+
return true;
|
|
26738
|
+
}
|
|
26739
|
+
const error = frame.error ?? "The proxied client stream was aborted.";
|
|
26740
|
+
try {
|
|
26741
|
+
receiver.controller?.error(new Error(error));
|
|
26742
|
+
} catch {
|
|
26743
|
+
}
|
|
26744
|
+
receiver.settle({ ok: false, error });
|
|
26745
|
+
return true;
|
|
26746
|
+
}
|
|
26653
26747
|
/** Open a bidirectional byte stream to the connected owner client. */
|
|
26654
|
-
async openClientStream(request) {
|
|
26748
|
+
async openClientStream(request, proxyTarget = null) {
|
|
26655
26749
|
const owner = await this.getExecutionOwner();
|
|
26656
26750
|
let socket = this.getOpenBridgeSocket(owner?.client_id ?? null);
|
|
26657
26751
|
if (!socket && owner) {
|
|
@@ -26684,9 +26778,12 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26684
26778
|
opened: null,
|
|
26685
26779
|
openTimer: null,
|
|
26686
26780
|
settleDone,
|
|
26687
|
-
settled: false
|
|
26781
|
+
settled: false,
|
|
26782
|
+
proxyTarget,
|
|
26783
|
+
delivery: Promise.resolve()
|
|
26688
26784
|
};
|
|
26689
26785
|
this.clientStreams.set(id, state);
|
|
26786
|
+
this.updateBridgeProxyAttachment(socket);
|
|
26690
26787
|
this.bridgeLastSeen.set(socket, Date.now());
|
|
26691
26788
|
const openResult = await new Promise((resolve) => {
|
|
26692
26789
|
state.opened = resolve;
|
|
@@ -26722,6 +26819,7 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26722
26819
|
}
|
|
26723
26820
|
if (!openResult.ok) {
|
|
26724
26821
|
this.clientStreams.delete(id);
|
|
26822
|
+
this.updateBridgeProxyAttachment(socket);
|
|
26725
26823
|
state.settled = true;
|
|
26726
26824
|
settleDone({ ok: false, error: openResult.error });
|
|
26727
26825
|
return {
|
|
@@ -26763,14 +26861,28 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26763
26861
|
};
|
|
26764
26862
|
return { ok: true, duplex };
|
|
26765
26863
|
}
|
|
26766
|
-
// ───
|
|
26767
|
-
// A
|
|
26768
|
-
//
|
|
26769
|
-
//
|
|
26770
|
-
//
|
|
26771
|
-
|
|
26772
|
-
|
|
26773
|
-
|
|
26864
|
+
// ─── Event-driven subagent stream proxy ──────────────────────────────────
|
|
26865
|
+
// A child registers a local receiver before the bridge-holding ancestor
|
|
26866
|
+
// opens the client stream. The ancestor invokes that receiver only for real
|
|
26867
|
+
// data/end/abort events; there is no pull loop or permanently outstanding
|
|
26868
|
+
// cross-DO RPC while the stream is idle.
|
|
26869
|
+
async proxyStreamOpen(request, target) {
|
|
26870
|
+
const namespace = this.env.AGENT_BUILDER_THREAD;
|
|
26871
|
+
let receiverExists = false;
|
|
26872
|
+
try {
|
|
26873
|
+
const destination = namespace.get(namespace.idFromName(target.threadId));
|
|
26874
|
+
receiverExists = await destination.proxyStreamReceiverExists(target.receiverId);
|
|
26875
|
+
} catch {
|
|
26876
|
+
receiverExists = false;
|
|
26877
|
+
}
|
|
26878
|
+
if (!receiverExists) {
|
|
26879
|
+
return {
|
|
26880
|
+
ok: false,
|
|
26881
|
+
error: "The destination stream receiver is unavailable.",
|
|
26882
|
+
code: "unavailable"
|
|
26883
|
+
};
|
|
26884
|
+
}
|
|
26885
|
+
const opened = await this.openClientStream(request, target);
|
|
26774
26886
|
if (!opened.ok) {
|
|
26775
26887
|
const failureData = opened.data;
|
|
26776
26888
|
const noClient = failureData?.noClient === true;
|
|
@@ -26782,82 +26894,23 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26782
26894
|
};
|
|
26783
26895
|
}
|
|
26784
26896
|
const id = crypto.randomUUID();
|
|
26785
|
-
|
|
26786
|
-
|
|
26787
|
-
|
|
26788
|
-
|
|
26789
|
-
writer,
|
|
26790
|
-
reader,
|
|
26791
|
-
buffer: [],
|
|
26792
|
-
done: false,
|
|
26793
|
-
error: void 0,
|
|
26794
|
-
pump: Promise.resolve(),
|
|
26795
|
-
close: (error) => duplex.close(error),
|
|
26796
|
-
waiter: null,
|
|
26797
|
-
notify: () => {
|
|
26798
|
-
const waiter = entry.waiter;
|
|
26799
|
-
entry.waiter = null;
|
|
26800
|
-
waiter?.();
|
|
26801
|
-
}
|
|
26802
|
-
};
|
|
26803
|
-
entry.pump = (async () => {
|
|
26804
|
-
try {
|
|
26805
|
-
while (true) {
|
|
26806
|
-
const { value, done } = await reader.read();
|
|
26807
|
-
if (done) break;
|
|
26808
|
-
if (value) {
|
|
26809
|
-
entry.buffer.push(value);
|
|
26810
|
-
entry.notify();
|
|
26811
|
-
}
|
|
26812
|
-
}
|
|
26813
|
-
} catch (error) {
|
|
26814
|
-
entry.error = error instanceof Error ? error.message : String(error);
|
|
26815
|
-
} finally {
|
|
26816
|
-
entry.done = true;
|
|
26817
|
-
entry.notify();
|
|
26818
|
-
}
|
|
26819
|
-
})();
|
|
26820
|
-
void duplex.done.then((d) => {
|
|
26821
|
-
entry.done = true;
|
|
26822
|
-
if (!d.ok && !entry.error) entry.error = d.error;
|
|
26823
|
-
entry.notify();
|
|
26897
|
+
this.eventProxyStreams.set(id, {
|
|
26898
|
+
writer: opened.duplex.writable.getWriter(),
|
|
26899
|
+
close: (error) => opened.duplex.close(error),
|
|
26900
|
+
target
|
|
26824
26901
|
});
|
|
26825
|
-
|
|
26826
|
-
return { ok: true, id, parkedPull: true };
|
|
26902
|
+
return { ok: true, id, eventDriven: true };
|
|
26827
26903
|
}
|
|
26828
26904
|
async proxyStreamWrite(id, dataB64) {
|
|
26829
|
-
const entry = this.
|
|
26905
|
+
const entry = this.eventProxyStreams.get(id);
|
|
26830
26906
|
if (!entry) return;
|
|
26831
26907
|
try {
|
|
26832
26908
|
await entry.writer.write(decodeStreamChunk(dataB64));
|
|
26833
26909
|
} catch {
|
|
26834
26910
|
}
|
|
26835
26911
|
}
|
|
26836
|
-
async proxyStreamPull(id, maxWaitMs) {
|
|
26837
|
-
const entry = this.proxyStreams.get(id);
|
|
26838
|
-
if (!entry) return { chunks: [], done: true, error: "unknown proxy stream" };
|
|
26839
|
-
if (entry.buffer.length === 0 && !entry.done) {
|
|
26840
|
-
await new Promise((resolve) => {
|
|
26841
|
-
const deadline = typeof maxWaitMs === "number" && maxWaitMs > 0 ? setTimeout(() => {
|
|
26842
|
-
if (entry.waiter === wake) entry.waiter = null;
|
|
26843
|
-
resolve();
|
|
26844
|
-
}, maxWaitMs) : null;
|
|
26845
|
-
const wake = () => {
|
|
26846
|
-
if (deadline) clearTimeout(deadline);
|
|
26847
|
-
resolve();
|
|
26848
|
-
};
|
|
26849
|
-
entry.waiter = wake;
|
|
26850
|
-
});
|
|
26851
|
-
}
|
|
26852
|
-
const chunks = entry.buffer.splice(0).map((b) => encodeStreamChunk(b));
|
|
26853
|
-
if (entry.done && entry.buffer.length === 0) {
|
|
26854
|
-
this.proxyStreams.delete(id);
|
|
26855
|
-
return { chunks, done: true, error: entry.error };
|
|
26856
|
-
}
|
|
26857
|
-
return { chunks, done: false };
|
|
26858
|
-
}
|
|
26859
26912
|
async proxyStreamEnd(id) {
|
|
26860
|
-
const entry = this.
|
|
26913
|
+
const entry = this.eventProxyStreams.get(id);
|
|
26861
26914
|
if (!entry) return;
|
|
26862
26915
|
try {
|
|
26863
26916
|
await entry.writer.close();
|
|
@@ -26865,30 +26918,49 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26865
26918
|
}
|
|
26866
26919
|
}
|
|
26867
26920
|
async proxyStreamAbort(id) {
|
|
26868
|
-
const entry = this.
|
|
26921
|
+
const entry = this.eventProxyStreams.get(id);
|
|
26869
26922
|
if (!entry) return;
|
|
26870
|
-
this.
|
|
26871
|
-
entry.done = true;
|
|
26872
|
-
if (!entry.error) entry.error = "aborted";
|
|
26873
|
-
entry.notify();
|
|
26923
|
+
this.eventProxyStreams.delete(id);
|
|
26874
26924
|
try {
|
|
26875
26925
|
entry.close("aborted");
|
|
26876
26926
|
} catch {
|
|
26877
26927
|
}
|
|
26878
26928
|
}
|
|
26929
|
+
forgetEventProxyStream(clientStreamId, target) {
|
|
26930
|
+
const matchesTarget = (candidate) => candidate.threadId === target.threadId && candidate.receiverId === target.receiverId;
|
|
26931
|
+
for (const [id, entry] of Array.from(this.eventProxyStreams.entries())) {
|
|
26932
|
+
if (id !== clientStreamId && !matchesTarget(entry.target)) continue;
|
|
26933
|
+
this.eventProxyStreams.delete(id);
|
|
26934
|
+
try {
|
|
26935
|
+
entry.writer.releaseLock();
|
|
26936
|
+
} catch {
|
|
26937
|
+
}
|
|
26938
|
+
}
|
|
26939
|
+
}
|
|
26879
26940
|
/** Settle and remove a client stream exactly once. */
|
|
26880
26941
|
settleClientStream(id, result, openCode) {
|
|
26881
26942
|
const state = this.clientStreams.get(id);
|
|
26882
26943
|
if (!state) return;
|
|
26883
26944
|
this.clientStreams.delete(id);
|
|
26945
|
+
this.updateBridgeProxyAttachment(state.socket);
|
|
26884
26946
|
if (state.openTimer) clearTimeout(state.openTimer);
|
|
26885
26947
|
if (state.opened) state.opened({ ok: false, error: result.error ?? "Stream closed.", code: openCode });
|
|
26886
26948
|
if (!state.settled) {
|
|
26887
26949
|
state.settled = true;
|
|
26888
|
-
|
|
26889
|
-
|
|
26890
|
-
|
|
26891
|
-
|
|
26950
|
+
if (state.proxyTarget) {
|
|
26951
|
+
const target = state.proxyTarget;
|
|
26952
|
+
const frame = result.ok ? { type: "end" } : { type: "abort", error: result.error ?? "Client stream aborted." };
|
|
26953
|
+
state.delivery = state.delivery.then(async () => {
|
|
26954
|
+
await this.deliverProxyStreamFrame(target, frame);
|
|
26955
|
+
});
|
|
26956
|
+
this.ctx.waitUntil(state.delivery);
|
|
26957
|
+
this.forgetEventProxyStream(id, target);
|
|
26958
|
+
} else {
|
|
26959
|
+
try {
|
|
26960
|
+
if (result.ok) state.controller?.close();
|
|
26961
|
+
else state.controller?.error(new Error(result.error ?? "Client stream aborted."));
|
|
26962
|
+
} catch {
|
|
26963
|
+
}
|
|
26892
26964
|
}
|
|
26893
26965
|
state.settleDone(result);
|
|
26894
26966
|
}
|
|
@@ -26931,6 +27003,18 @@ ${resultContent}${attachmentSummary}`;
|
|
|
26931
27003
|
}
|
|
26932
27004
|
case "stream_data": {
|
|
26933
27005
|
if (typeof parsed.data !== "string") return;
|
|
27006
|
+
if (state.proxyTarget) {
|
|
27007
|
+
const target = state.proxyTarget;
|
|
27008
|
+
const frame = { type: "data", data: parsed.data };
|
|
27009
|
+
state.delivery = state.delivery.then(async () => {
|
|
27010
|
+
const delivered = await this.deliverProxyStreamFrame(target, frame);
|
|
27011
|
+
if (!delivered && this.clientStreams.get(id) === state) {
|
|
27012
|
+
this.abortClientStream(id, "The destination stream receiver is unavailable.");
|
|
27013
|
+
}
|
|
27014
|
+
});
|
|
27015
|
+
this.ctx.waitUntil(state.delivery);
|
|
27016
|
+
return;
|
|
27017
|
+
}
|
|
26934
27018
|
try {
|
|
26935
27019
|
state.controller?.enqueue(decodeStreamChunk(parsed.data));
|
|
26936
27020
|
} catch {
|
|
@@ -27758,11 +27842,12 @@ ${resultContent}${attachmentSummary}`;
|
|
|
27758
27842
|
if (!parentThreadId) return;
|
|
27759
27843
|
const parentId = this.env.AGENT_BUILDER_THREAD.idFromName(parentThreadId);
|
|
27760
27844
|
const parentStub = this.env.AGENT_BUILDER_THREAD.get(parentId);
|
|
27761
|
-
const
|
|
27845
|
+
const childRegistryEntry = await this.getParentRegistryEntryForChild(
|
|
27762
27846
|
parentStub,
|
|
27763
27847
|
parentThreadId,
|
|
27764
27848
|
threadId
|
|
27765
27849
|
);
|
|
27850
|
+
const parentCommunication = childRegistryEntry?.parentCommunication === "explicit" ? "explicit" : "implicit";
|
|
27766
27851
|
if (parentCommunication !== "explicit") {
|
|
27767
27852
|
await parentStub.queueMessage(parentThreadId, {
|
|
27768
27853
|
role: "user",
|
|
@@ -28521,11 +28606,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28521
28606
|
/**
|
|
28522
28607
|
* Write a file to storage (RPC method)
|
|
28523
28608
|
*/
|
|
28524
|
-
async writeFile(
|
|
28609
|
+
async writeFile(path2, data, mimeType, options) {
|
|
28525
28610
|
await this.ensureMigrated();
|
|
28526
28611
|
try {
|
|
28527
|
-
const
|
|
28528
|
-
const existingFile = await
|
|
28612
|
+
const fs2 = this.getFileStorage();
|
|
28613
|
+
const existingFile = await fs2.stat(path2);
|
|
28529
28614
|
const isUpdate = existingFile !== null;
|
|
28530
28615
|
const binaryString = atob(data);
|
|
28531
28616
|
const dataBuffer = new Uint8Array(binaryString.length);
|
|
@@ -28547,12 +28632,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28547
28632
|
}
|
|
28548
28633
|
}
|
|
28549
28634
|
}
|
|
28550
|
-
const record = await
|
|
28635
|
+
const record = await fs2.writeFile(path2, dataBuffer, mimeType, {
|
|
28551
28636
|
metadata: options?.metadata,
|
|
28552
28637
|
thumbnail: thumbnailBuffer
|
|
28553
28638
|
});
|
|
28554
28639
|
this.broadcastEvent(isUpdate ? "file_updated" : "file_created", {
|
|
28555
|
-
path,
|
|
28640
|
+
path: path2,
|
|
28556
28641
|
file: record
|
|
28557
28642
|
});
|
|
28558
28643
|
return { success: true, file: record };
|
|
@@ -28564,15 +28649,15 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28564
28649
|
/**
|
|
28565
28650
|
* Write a text file to storage (RPC method)
|
|
28566
28651
|
*/
|
|
28567
|
-
async writeTextFile(
|
|
28652
|
+
async writeTextFile(path2, content, mimeType = "text/plain", options) {
|
|
28568
28653
|
await this.ensureMigrated();
|
|
28569
28654
|
try {
|
|
28570
|
-
const
|
|
28571
|
-
const existingFile = await
|
|
28655
|
+
const fs2 = this.getFileStorage();
|
|
28656
|
+
const existingFile = await fs2.stat(path2);
|
|
28572
28657
|
const isUpdate = existingFile !== null;
|
|
28573
|
-
const record = await
|
|
28658
|
+
const record = await fs2.writeFile(path2, content, mimeType, options);
|
|
28574
28659
|
this.broadcastEvent(isUpdate ? "file_updated" : "file_created", {
|
|
28575
|
-
path,
|
|
28660
|
+
path: path2,
|
|
28576
28661
|
file: record
|
|
28577
28662
|
});
|
|
28578
28663
|
return { success: true, file: record };
|
|
@@ -28609,11 +28694,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28609
28694
|
/**
|
|
28610
28695
|
* Link to an external file (RPC method)
|
|
28611
28696
|
*/
|
|
28612
|
-
async linkFile(
|
|
28697
|
+
async linkFile(path2, location, options) {
|
|
28613
28698
|
await this.ensureMigrated();
|
|
28614
28699
|
try {
|
|
28615
|
-
const
|
|
28616
|
-
const record = await
|
|
28700
|
+
const fs2 = this.getFileStorage();
|
|
28701
|
+
const record = await fs2.linkFile(path2, location, options);
|
|
28617
28702
|
return { success: true, file: record };
|
|
28618
28703
|
} catch (error) {
|
|
28619
28704
|
console.error("Error in linkFile:", error);
|
|
@@ -28624,11 +28709,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28624
28709
|
* Read a file from storage (RPC method)
|
|
28625
28710
|
* Returns base64-encoded data
|
|
28626
28711
|
*/
|
|
28627
|
-
async readFile(
|
|
28712
|
+
async readFile(path2) {
|
|
28628
28713
|
await this.ensureMigrated();
|
|
28629
28714
|
try {
|
|
28630
|
-
const
|
|
28631
|
-
const data = await
|
|
28715
|
+
const fs2 = this.getFileStorage();
|
|
28716
|
+
const data = await fs2.readFile(path2);
|
|
28632
28717
|
if (data === null) {
|
|
28633
28718
|
return { success: false, error: "File not found or external" };
|
|
28634
28719
|
}
|
|
@@ -28647,11 +28732,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28647
28732
|
/**
|
|
28648
28733
|
* Read a text file from storage (RPC method)
|
|
28649
28734
|
*/
|
|
28650
|
-
async readTextFile(
|
|
28735
|
+
async readTextFile(path2) {
|
|
28651
28736
|
await this.ensureMigrated();
|
|
28652
28737
|
try {
|
|
28653
|
-
const
|
|
28654
|
-
const content = await
|
|
28738
|
+
const fs2 = this.getFileStorage();
|
|
28739
|
+
const content = await fs2.readTextFile(path2);
|
|
28655
28740
|
if (content === null) {
|
|
28656
28741
|
return { success: false, error: "File not found or external" };
|
|
28657
28742
|
}
|
|
@@ -28664,11 +28749,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28664
28749
|
/**
|
|
28665
28750
|
* Get file metadata (RPC method)
|
|
28666
28751
|
*/
|
|
28667
|
-
async statFile(
|
|
28752
|
+
async statFile(path2) {
|
|
28668
28753
|
await this.ensureMigrated();
|
|
28669
28754
|
try {
|
|
28670
|
-
const
|
|
28671
|
-
const record = await
|
|
28755
|
+
const fs2 = this.getFileStorage();
|
|
28756
|
+
const record = await fs2.stat(path2);
|
|
28672
28757
|
if (record === null) {
|
|
28673
28758
|
return { success: false, error: "File not found" };
|
|
28674
28759
|
}
|
|
@@ -28681,11 +28766,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28681
28766
|
/**
|
|
28682
28767
|
* Check if file exists (RPC method)
|
|
28683
28768
|
*/
|
|
28684
|
-
async fileExists(
|
|
28769
|
+
async fileExists(path2) {
|
|
28685
28770
|
await this.ensureMigrated();
|
|
28686
28771
|
try {
|
|
28687
|
-
const
|
|
28688
|
-
const exists2 = await
|
|
28772
|
+
const fs2 = this.getFileStorage();
|
|
28773
|
+
const exists2 = await fs2.exists(path2);
|
|
28689
28774
|
return { success: true, exists: exists2 };
|
|
28690
28775
|
} catch (error) {
|
|
28691
28776
|
console.error("Error in fileExists:", error);
|
|
@@ -28695,12 +28780,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28695
28780
|
/**
|
|
28696
28781
|
* Delete a file (RPC method)
|
|
28697
28782
|
*/
|
|
28698
|
-
async unlinkFile(
|
|
28783
|
+
async unlinkFile(path2) {
|
|
28699
28784
|
await this.ensureMigrated();
|
|
28700
28785
|
try {
|
|
28701
|
-
const
|
|
28702
|
-
await
|
|
28703
|
-
this.broadcastEvent("file_deleted", { path });
|
|
28786
|
+
const fs2 = this.getFileStorage();
|
|
28787
|
+
await fs2.unlink(path2);
|
|
28788
|
+
this.broadcastEvent("file_deleted", { path: path2 });
|
|
28704
28789
|
return { success: true };
|
|
28705
28790
|
} catch (error) {
|
|
28706
28791
|
console.error("Error in unlinkFile:", error);
|
|
@@ -28710,12 +28795,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28710
28795
|
/**
|
|
28711
28796
|
* Create a directory (RPC method)
|
|
28712
28797
|
*/
|
|
28713
|
-
async mkdirFile(
|
|
28798
|
+
async mkdirFile(path2) {
|
|
28714
28799
|
await this.ensureMigrated();
|
|
28715
28800
|
try {
|
|
28716
|
-
const
|
|
28717
|
-
const record = await
|
|
28718
|
-
this.broadcastEvent("file_created", { path, file: record });
|
|
28801
|
+
const fs2 = this.getFileStorage();
|
|
28802
|
+
const record = await fs2.mkdir(path2);
|
|
28803
|
+
this.broadcastEvent("file_created", { path: path2, file: record });
|
|
28719
28804
|
return { success: true, directory: record };
|
|
28720
28805
|
} catch (error) {
|
|
28721
28806
|
console.error("Error in mkdirFile:", error);
|
|
@@ -28725,11 +28810,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28725
28810
|
/**
|
|
28726
28811
|
* List directory contents (RPC method)
|
|
28727
28812
|
*/
|
|
28728
|
-
async readdirFile(
|
|
28813
|
+
async readdirFile(path2) {
|
|
28729
28814
|
await this.ensureMigrated();
|
|
28730
28815
|
try {
|
|
28731
|
-
const
|
|
28732
|
-
const files = await
|
|
28816
|
+
const fs2 = this.getFileStorage();
|
|
28817
|
+
const files = await fs2.readdir(path2);
|
|
28733
28818
|
return { success: true, files };
|
|
28734
28819
|
} catch (error) {
|
|
28735
28820
|
console.error("Error in readdirFile:", error);
|
|
@@ -28739,12 +28824,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28739
28824
|
/**
|
|
28740
28825
|
* Remove empty directory (RPC method)
|
|
28741
28826
|
*/
|
|
28742
|
-
async rmdirFile(
|
|
28827
|
+
async rmdirFile(path2) {
|
|
28743
28828
|
await this.ensureMigrated();
|
|
28744
28829
|
try {
|
|
28745
|
-
const
|
|
28746
|
-
await
|
|
28747
|
-
this.broadcastEvent("file_deleted", { path });
|
|
28830
|
+
const fs2 = this.getFileStorage();
|
|
28831
|
+
await fs2.rmdir(path2);
|
|
28832
|
+
this.broadcastEvent("file_deleted", { path: path2 });
|
|
28748
28833
|
return { success: true };
|
|
28749
28834
|
} catch (error) {
|
|
28750
28835
|
console.error("Error in rmdirFile:", error);
|
|
@@ -28759,9 +28844,9 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28759
28844
|
await this.ensureMigrated();
|
|
28760
28845
|
try {
|
|
28761
28846
|
const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28762
|
-
const
|
|
28847
|
+
const fs2 = this.getFileStorage();
|
|
28763
28848
|
const from = normalizePath2(sourcePath);
|
|
28764
|
-
const record = await
|
|
28849
|
+
const record = await fs2.move(sourcePath, destinationPath);
|
|
28765
28850
|
this.broadcastEvent("file_moved", { from, path: record.path, file: record });
|
|
28766
28851
|
this.broadcastEvent("file_deleted", { path: from });
|
|
28767
28852
|
this.broadcastEvent("file_created", { path: record.path, file: record });
|
|
@@ -28774,13 +28859,13 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28774
28859
|
/**
|
|
28775
28860
|
* Rename a file or directory in place (RPC method).
|
|
28776
28861
|
*/
|
|
28777
|
-
async renameFile(
|
|
28862
|
+
async renameFile(path2, newName) {
|
|
28778
28863
|
await this.ensureMigrated();
|
|
28779
28864
|
try {
|
|
28780
28865
|
const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28781
|
-
const
|
|
28782
|
-
const from = normalizePath2(
|
|
28783
|
-
const record = await
|
|
28866
|
+
const fs2 = this.getFileStorage();
|
|
28867
|
+
const from = normalizePath2(path2);
|
|
28868
|
+
const record = await fs2.rename(path2, newName);
|
|
28784
28869
|
this.broadcastEvent("file_moved", { from, path: record.path, file: record });
|
|
28785
28870
|
this.broadcastEvent("file_deleted", { path: from });
|
|
28786
28871
|
this.broadcastEvent("file_created", { path: record.path, file: record });
|
|
@@ -28796,8 +28881,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28796
28881
|
async getFileStats() {
|
|
28797
28882
|
await this.ensureMigrated();
|
|
28798
28883
|
try {
|
|
28799
|
-
const
|
|
28800
|
-
const stats = await
|
|
28884
|
+
const fs2 = this.getFileStorage();
|
|
28885
|
+
const stats = await fs2.getFileStats();
|
|
28801
28886
|
return { success: true, stats };
|
|
28802
28887
|
} catch (error) {
|
|
28803
28888
|
console.error("Error in getFileStats:", error);
|
|
@@ -28808,11 +28893,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28808
28893
|
* Get thumbnail for an image (RPC method)
|
|
28809
28894
|
* Returns base64-encoded data
|
|
28810
28895
|
*/
|
|
28811
|
-
async getFileThumbnail(
|
|
28896
|
+
async getFileThumbnail(path2) {
|
|
28812
28897
|
await this.ensureMigrated();
|
|
28813
28898
|
try {
|
|
28814
|
-
const
|
|
28815
|
-
const data = await
|
|
28899
|
+
const fs2 = this.getFileStorage();
|
|
28900
|
+
const data = await fs2.getThumbnail(path2);
|
|
28816
28901
|
if (data === null) {
|
|
28817
28902
|
return { success: false, error: "Thumbnail not found" };
|
|
28818
28903
|
}
|
|
@@ -28834,8 +28919,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28834
28919
|
async grepFiles(pattern, options) {
|
|
28835
28920
|
await this.ensureMigrated();
|
|
28836
28921
|
try {
|
|
28837
|
-
const
|
|
28838
|
-
const results = await
|
|
28922
|
+
const fs2 = this.getFileStorage();
|
|
28923
|
+
const results = await fs2.grep(pattern, options);
|
|
28839
28924
|
return { success: true, results };
|
|
28840
28925
|
} catch (error) {
|
|
28841
28926
|
console.error("Error in grepFiles:", error);
|
|
@@ -28848,8 +28933,8 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28848
28933
|
async findFiles(pattern, options) {
|
|
28849
28934
|
await this.ensureMigrated();
|
|
28850
28935
|
try {
|
|
28851
|
-
const
|
|
28852
|
-
const files = await
|
|
28936
|
+
const fs2 = this.getFileStorage();
|
|
28937
|
+
const files = await fs2.find(pattern, options);
|
|
28853
28938
|
return { success: true, files };
|
|
28854
28939
|
} catch (error) {
|
|
28855
28940
|
console.error("Error in findFiles:", error);
|
|
@@ -28864,11 +28949,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28864
28949
|
* Creates file record with is_chunked=1 and chunk_count=null.
|
|
28865
28950
|
* Caller should then use writeFileChunk() to write chunks.
|
|
28866
28951
|
*/
|
|
28867
|
-
async startChunkedUpload(
|
|
28952
|
+
async startChunkedUpload(path2, totalSize, mimeType, options) {
|
|
28868
28953
|
await this.ensureMigrated();
|
|
28869
28954
|
try {
|
|
28870
28955
|
const { CHUNK_SIZE: CHUNK_SIZE2, normalizePath: normalizePath2, basename: basename2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28871
|
-
const normalizedPath = normalizePath2(
|
|
28956
|
+
const normalizedPath = normalizePath2(path2);
|
|
28872
28957
|
const name = basename2(normalizedPath);
|
|
28873
28958
|
const now = Date.now();
|
|
28874
28959
|
const expectedChunks = Math.ceil(totalSize / CHUNK_SIZE2);
|
|
@@ -28905,11 +28990,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28905
28990
|
* @param chunkIndex - 0-based chunk index
|
|
28906
28991
|
* @param data - Base64 encoded chunk data
|
|
28907
28992
|
*/
|
|
28908
|
-
async writeFileChunk(
|
|
28993
|
+
async writeFileChunk(path2, chunkIndex, data) {
|
|
28909
28994
|
await this.ensureMigrated();
|
|
28910
28995
|
try {
|
|
28911
28996
|
const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28912
|
-
const normalizedPath = normalizePath2(
|
|
28997
|
+
const normalizedPath = normalizePath2(path2);
|
|
28913
28998
|
const binaryString = atob(data);
|
|
28914
28999
|
const dataBuffer = new Uint8Array(binaryString.length);
|
|
28915
29000
|
for (let i = 0; i < binaryString.length; i++) {
|
|
@@ -28931,12 +29016,12 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28931
29016
|
* Complete a chunked file upload.
|
|
28932
29017
|
* Validates all chunks are present and sets chunk_count.
|
|
28933
29018
|
*/
|
|
28934
|
-
async completeChunkedUpload(
|
|
29019
|
+
async completeChunkedUpload(path2, expectedChunks, options) {
|
|
28935
29020
|
await this.ensureMigrated();
|
|
28936
29021
|
try {
|
|
28937
29022
|
const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28938
|
-
const
|
|
28939
|
-
const normalizedPath = normalizePath2(
|
|
29023
|
+
const fs2 = this.getFileStorage();
|
|
29024
|
+
const normalizedPath = normalizePath2(path2);
|
|
28940
29025
|
const countResult = await this.ctx.storage.sql.exec(
|
|
28941
29026
|
`SELECT COUNT(*) as count FROM file_chunks WHERE file_path = ?`,
|
|
28942
29027
|
normalizedPath
|
|
@@ -28962,7 +29047,7 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28962
29047
|
thumbnailBuffer || null,
|
|
28963
29048
|
normalizedPath
|
|
28964
29049
|
);
|
|
28965
|
-
const file = await
|
|
29050
|
+
const file = await fs2.stat(normalizedPath);
|
|
28966
29051
|
if (file) {
|
|
28967
29052
|
this.broadcastEvent("file_created", { path: normalizedPath, file });
|
|
28968
29053
|
}
|
|
@@ -28976,11 +29061,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
28976
29061
|
* Read a single chunk of a file.
|
|
28977
29062
|
* Use for streaming large files to client.
|
|
28978
29063
|
*/
|
|
28979
|
-
async readFileChunk(
|
|
29064
|
+
async readFileChunk(path2, chunkIndex) {
|
|
28980
29065
|
await this.ensureMigrated();
|
|
28981
29066
|
try {
|
|
28982
29067
|
const { normalizePath: normalizePath2 } = await Promise.resolve().then(() => (init_files(), files_exports));
|
|
28983
|
-
const normalizedPath = normalizePath2(
|
|
29068
|
+
const normalizedPath = normalizePath2(path2);
|
|
28984
29069
|
const cursor = await this.ctx.storage.sql.exec(
|
|
28985
29070
|
`SELECT data FROM file_chunks WHERE file_path = ? AND chunk_index = ?`,
|
|
28986
29071
|
normalizedPath,
|
|
@@ -29005,11 +29090,11 @@ Its execution was lost (the executor restarted or hung) and automatic recovery w
|
|
|
29005
29090
|
/**
|
|
29006
29091
|
* Get file info including chunking metadata.
|
|
29007
29092
|
*/
|
|
29008
|
-
async getFileInfo(
|
|
29093
|
+
async getFileInfo(path2) {
|
|
29009
29094
|
await this.ensureMigrated();
|
|
29010
29095
|
try {
|
|
29011
|
-
const
|
|
29012
|
-
const file = await
|
|
29096
|
+
const fs2 = this.getFileStorage();
|
|
29097
|
+
const file = await fs2.stat(path2);
|
|
29013
29098
|
if (!file) {
|
|
29014
29099
|
return { success: false, error: "File not found" };
|
|
29015
29100
|
}
|
|
@@ -29227,16 +29312,16 @@ function parseUserRouteKey(key) {
|
|
|
29227
29312
|
}
|
|
29228
29313
|
return { key, method, segments, dynamism };
|
|
29229
29314
|
}
|
|
29230
|
-
function matchSegments(route,
|
|
29315
|
+
function matchSegments(route, path2) {
|
|
29231
29316
|
const params = {};
|
|
29232
29317
|
for (let i = 0; i < route.length; i++) {
|
|
29233
29318
|
const seg = route[i];
|
|
29234
29319
|
if (seg === "[*]") {
|
|
29235
29320
|
if (i !== route.length - 1) return null;
|
|
29236
|
-
params["*"] =
|
|
29321
|
+
params["*"] = path2.slice(i).join("/");
|
|
29237
29322
|
return params;
|
|
29238
29323
|
}
|
|
29239
|
-
const value =
|
|
29324
|
+
const value = path2[i];
|
|
29240
29325
|
if (value === void 0) return null;
|
|
29241
29326
|
if (seg.startsWith("[") && seg.endsWith("]")) {
|
|
29242
29327
|
params[seg.slice(1, -1)] = value;
|
|
@@ -29244,16 +29329,16 @@ function matchSegments(route, path) {
|
|
|
29244
29329
|
return null;
|
|
29245
29330
|
}
|
|
29246
29331
|
}
|
|
29247
|
-
return
|
|
29332
|
+
return path2.length === route.length ? params : null;
|
|
29248
29333
|
}
|
|
29249
29334
|
function matchUserRoute(keys, method, endpointPath) {
|
|
29250
|
-
const
|
|
29335
|
+
const path2 = endpointPath.split("/").filter((s) => s.length > 0);
|
|
29251
29336
|
const wanted = method.toUpperCase();
|
|
29252
29337
|
let best = null;
|
|
29253
29338
|
for (const key of keys) {
|
|
29254
29339
|
const route = parseUserRouteKey(key);
|
|
29255
29340
|
if (route.method !== wanted) continue;
|
|
29256
|
-
const params = matchSegments(route.segments,
|
|
29341
|
+
const params = matchSegments(route.segments, path2);
|
|
29257
29342
|
if (!params) continue;
|
|
29258
29343
|
if (!best || route.dynamism < best.route.dynamism) {
|
|
29259
29344
|
best = { route, params };
|