zeitlich 0.2.46 → 0.2.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -6
- package/dist/{activities-CyeiqK_f.d.cts → activities-CPwKoUlD.d.cts} +3 -3
- package/dist/{activities-Bm4TLTid.d.ts → activities-DlaBxNID.d.ts} +3 -3
- package/dist/adapters/thread/anthropic/index.cjs +105 -6
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +48 -9
- package/dist/adapters/thread/anthropic/index.d.ts +48 -9
- package/dist/adapters/thread/anthropic/index.js +104 -7
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +38 -22
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -4
- package/dist/adapters/thread/anthropic/workflow.js +38 -22
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +6 -5
- package/dist/adapters/thread/google-genai/index.d.ts +6 -5
- package/dist/adapters/thread/google-genai/workflow.cjs +38 -22
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +7 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +7 -5
- package/dist/adapters/thread/google-genai/workflow.js +38 -22
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +6 -5
- package/dist/adapters/thread/langchain/index.d.ts +6 -5
- package/dist/adapters/thread/langchain/workflow.cjs +38 -22
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -4
- package/dist/adapters/thread/langchain/workflow.js +38 -22
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/{cold-store-CFHwemBJ.d.ts → cold-store-BDgJpwLI.d.ts} +8 -11
- package/dist/{cold-store-BC5L5Z8A.d.cts → cold-store-Z2wvK2cV.d.cts} +8 -11
- package/dist/index.cjs +264 -90
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +265 -93
- package/dist/index.js.map +1 -1
- package/dist/proxy-CDh3Rsa7.d.cts +40 -0
- package/dist/proxy-Du8ggERu.d.ts +40 -0
- package/dist/{thread-manager-D33SUmZa.d.cts → thread-manager-BjoYYXgd.d.cts} +2 -2
- package/dist/{thread-manager-9tezUcLW.d.cts → thread-manager-D8zKNFZ9.d.cts} +2 -2
- package/dist/{thread-manager-B-zy3xrs.d.ts → thread-manager-DtHYws2F.d.ts} +2 -2
- package/dist/{thread-manager-DduoSkvJ.d.ts → thread-manager-Dw96FKH1.d.ts} +2 -2
- package/dist/{types-oxt8GN97.d.cts → types-BMJrsHo0.d.cts} +1 -1
- package/dist/{types-L5bvbF-n.d.ts → types-CtdOquo3.d.ts} +1 -1
- package/dist/{types-CnuN9T6t.d.cts → types-DNEl5uxQ.d.cts} +16 -0
- package/dist/{types-CwN6_tAL.d.ts → types-qQVZfhoT.d.ts} +16 -0
- package/dist/{workflow-DIaIV7L2.d.cts → workflow-BH9ImDGq.d.cts} +17 -2
- package/dist/{workflow-B1TOcHbt.d.ts → workflow-Cdw3-RNB.d.ts} +17 -2
- package/dist/workflow.cjs +33 -3
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +33 -4
- package/dist/workflow.js.map +1 -1
- package/package.json +9 -3
- package/src/adapters/thread/anthropic/activities.ts +18 -11
- package/src/adapters/thread/anthropic/index.ts +8 -0
- package/src/adapters/thread/anthropic/model-invoker.test.ts +110 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +26 -5
- package/src/adapters/thread/anthropic/prompt-cache.test.ts +134 -0
- package/src/adapters/thread/anthropic/prompt-cache.ts +163 -0
- package/src/adapters/thread/anthropic/proxy.ts +1 -0
- package/src/adapters/thread/google-genai/proxy.ts +1 -0
- package/src/adapters/thread/langchain/proxy.ts +1 -0
- package/src/index.ts +1 -1
- package/src/lib/subagent/define.ts +1 -0
- package/src/lib/subagent/handler.ts +11 -2
- package/src/lib/subagent/subagent.integration.test.ts +139 -0
- package/src/lib/subagent/types.ts +16 -0
- package/src/lib/thread/cold-store.test.ts +33 -5
- package/src/lib/thread/cold-store.ts +50 -31
- package/src/lib/thread/proxy.ts +79 -29
- package/src/tools/edit/handler.test.ts +177 -0
- package/src/tools/edit/handler.ts +249 -47
- package/src/tools/edit/tool.ts +40 -0
- package/src/tools/task-create/handler.ts +1 -1
- package/src/tools/task-update/handler.ts +1 -1
- package/src/workflow.ts +2 -2
- package/dist/proxy-BxFyd6cg.d.cts +0 -24
- package/dist/proxy-Cskmj4Yx.d.ts +0 -24
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,9 @@ var crypto = require('crypto');
|
|
|
6
6
|
var common = require('@temporalio/common');
|
|
7
7
|
var path = require('path');
|
|
8
8
|
var zlib = require('zlib');
|
|
9
|
+
var util = require('util');
|
|
9
10
|
var clientS3 = require('@aws-sdk/client-s3');
|
|
11
|
+
var libStorage = require('@aws-sdk/lib-storage');
|
|
10
12
|
var activity = require('@temporalio/activity');
|
|
11
13
|
var fs = require('fs');
|
|
12
14
|
|
|
@@ -572,7 +574,8 @@ function createSubagentHandler(subagents) {
|
|
|
572
574
|
}
|
|
573
575
|
const threadMode = config.thread ?? "new";
|
|
574
576
|
const allowsContinuation = threadMode !== "new";
|
|
575
|
-
const
|
|
577
|
+
const newThreadSource = config.newThreadSource ?? "new";
|
|
578
|
+
const continuationThreadId = !allowsContinuation ? void 0 : args.threadId ?? (newThreadSource === "from-parent" ? context.threadId : void 0);
|
|
576
579
|
let thread;
|
|
577
580
|
if (continuationThreadId) {
|
|
578
581
|
thread = {
|
|
@@ -2220,6 +2223,13 @@ IMPORTANT:
|
|
|
2220
2223
|
}),
|
|
2221
2224
|
strict: true
|
|
2222
2225
|
};
|
|
2226
|
+
var textEditSchema = z14.z.object({
|
|
2227
|
+
old_string: z14.z.string().describe("The exact text to replace"),
|
|
2228
|
+
new_string: z14.z.string().describe("The text to replace it with"),
|
|
2229
|
+
replace_all: z14.z.boolean().optional().describe(
|
|
2230
|
+
"If true, replace all occurrences of old_string for this edit (default: false)"
|
|
2231
|
+
)
|
|
2232
|
+
});
|
|
2223
2233
|
var editTool = {
|
|
2224
2234
|
name: "FileEdit",
|
|
2225
2235
|
description: `Edit specific sections of a file by replacing text.
|
|
@@ -2248,6 +2258,27 @@ IMPORTANT:
|
|
|
2248
2258
|
}),
|
|
2249
2259
|
strict: true
|
|
2250
2260
|
};
|
|
2261
|
+
var multiEditTool = {
|
|
2262
|
+
name: "FileMultiEdit",
|
|
2263
|
+
description: `Apply multiple exact text replacements to one file in order.
|
|
2264
|
+
|
|
2265
|
+
Usage:
|
|
2266
|
+
- Use this when a task needs several related edits in the same file
|
|
2267
|
+
- Each edit is applied to the file content produced by the prior edit
|
|
2268
|
+
- The operation is atomic: if any edit fails, the file is left unchanged
|
|
2269
|
+
|
|
2270
|
+
IMPORTANT:
|
|
2271
|
+
- You must read the file first (in this session) before editing it
|
|
2272
|
+
- Each old_string must match exactly (whitespace-sensitive)
|
|
2273
|
+
- Each old_string must be unique unless that edit uses replace_all: true
|
|
2274
|
+
- old_string and new_string must be different for every edit
|
|
2275
|
+
`,
|
|
2276
|
+
schema: z14.z.object({
|
|
2277
|
+
file_path: z14.z.string().describe("The absolute virtual path to the file to modify"),
|
|
2278
|
+
edits: z14.z.array(textEditSchema).min(1).describe("Exact replacements to apply sequentially to the file")
|
|
2279
|
+
}),
|
|
2280
|
+
strict: true
|
|
2281
|
+
};
|
|
2251
2282
|
var taskCreateTool = {
|
|
2252
2283
|
name: "TaskCreate",
|
|
2253
2284
|
description: `Use this tool to create a structured task list. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
@@ -2318,7 +2349,7 @@ function createTaskCreateHandler(stateManager) {
|
|
|
2318
2349
|
};
|
|
2319
2350
|
stateManager.setTask(task);
|
|
2320
2351
|
return {
|
|
2321
|
-
toolResponse:
|
|
2352
|
+
toolResponse: `Task ${task.id} created`,
|
|
2322
2353
|
data: task
|
|
2323
2354
|
};
|
|
2324
2355
|
};
|
|
@@ -2417,7 +2448,7 @@ function createTaskUpdateHandler(stateManager) {
|
|
|
2417
2448
|
}
|
|
2418
2449
|
stateManager.setTask(task);
|
|
2419
2450
|
return {
|
|
2420
|
-
toolResponse:
|
|
2451
|
+
toolResponse: `Task ${task.id} updated`,
|
|
2421
2452
|
data: task
|
|
2422
2453
|
};
|
|
2423
2454
|
};
|
|
@@ -2749,6 +2780,44 @@ function createThreadManager(config) {
|
|
|
2749
2780
|
}
|
|
2750
2781
|
};
|
|
2751
2782
|
}
|
|
2783
|
+
function getActivityContext() {
|
|
2784
|
+
try {
|
|
2785
|
+
const ctx = activity.Context.current();
|
|
2786
|
+
return { heartbeat: () => ctx.heartbeat(), signal: ctx.cancellationSignal };
|
|
2787
|
+
} catch {
|
|
2788
|
+
return {};
|
|
2789
|
+
}
|
|
2790
|
+
}
|
|
2791
|
+
async function queryParentWorkflowState(client) {
|
|
2792
|
+
const { workflowExecution } = activity.Context.current().info;
|
|
2793
|
+
if (!workflowExecution) {
|
|
2794
|
+
throw new Error("No workflow execution found");
|
|
2795
|
+
}
|
|
2796
|
+
const handle = client.getHandle(
|
|
2797
|
+
workflowExecution.workflowId,
|
|
2798
|
+
workflowExecution.runId
|
|
2799
|
+
);
|
|
2800
|
+
return handle.query("getAgentState");
|
|
2801
|
+
}
|
|
2802
|
+
function createRunAgentActivity(client, handler, scope) {
|
|
2803
|
+
const name = `run${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
|
|
2804
|
+
return {
|
|
2805
|
+
[name]: async (config) => {
|
|
2806
|
+
const state = await queryParentWorkflowState(client);
|
|
2807
|
+
return handler({ ...config, state });
|
|
2808
|
+
}
|
|
2809
|
+
};
|
|
2810
|
+
}
|
|
2811
|
+
function withParentWorkflowState(client, handler) {
|
|
2812
|
+
return async (args, context) => {
|
|
2813
|
+
const state = await queryParentWorkflowState(client);
|
|
2814
|
+
return handler(args, { ...context, state });
|
|
2815
|
+
};
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
// src/lib/thread/cold-store.ts
|
|
2819
|
+
var gzipAsync = util.promisify(zlib.gzip);
|
|
2820
|
+
var gunzipAsync = util.promisify(zlib.gunzip);
|
|
2752
2821
|
function joinKey(parts) {
|
|
2753
2822
|
return parts.map((p) => p.replace(/^\/+|\/+$/g, "")).filter((p) => p.length > 0).join("/");
|
|
2754
2823
|
}
|
|
@@ -2760,9 +2829,17 @@ function buildKey(prefix, threadKey, threadId, gzip) {
|
|
|
2760
2829
|
`${threadId}.${ext}`
|
|
2761
2830
|
]);
|
|
2762
2831
|
}
|
|
2763
|
-
async function streamToBuffer(body) {
|
|
2832
|
+
async function streamToBuffer(body, onChunk) {
|
|
2764
2833
|
if (body == null) return Buffer.alloc(0);
|
|
2765
2834
|
if (body instanceof Uint8Array) return Buffer.from(body);
|
|
2835
|
+
if (typeof body[Symbol.asyncIterator] === "function") {
|
|
2836
|
+
const chunks = [];
|
|
2837
|
+
for await (const chunk of body) {
|
|
2838
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
2839
|
+
onChunk?.();
|
|
2840
|
+
}
|
|
2841
|
+
return Buffer.concat(chunks);
|
|
2842
|
+
}
|
|
2766
2843
|
if (typeof body.transformToByteArray === "function") {
|
|
2767
2844
|
const bytes = await body.transformToByteArray();
|
|
2768
2845
|
return Buffer.from(bytes);
|
|
@@ -2771,11 +2848,7 @@ async function streamToBuffer(body) {
|
|
|
2771
2848
|
const ab = await body.arrayBuffer();
|
|
2772
2849
|
return Buffer.from(ab);
|
|
2773
2850
|
}
|
|
2774
|
-
|
|
2775
|
-
for await (const chunk of body) {
|
|
2776
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
2777
|
-
}
|
|
2778
|
-
return Buffer.concat(chunks);
|
|
2851
|
+
return Buffer.alloc(0);
|
|
2779
2852
|
}
|
|
2780
2853
|
function createS3ColdStore(config) {
|
|
2781
2854
|
const { s3, bucket, prefix, gzip = true } = config;
|
|
@@ -2787,8 +2860,9 @@ function createS3ColdStore(config) {
|
|
|
2787
2860
|
const resp = await s3.send(
|
|
2788
2861
|
new clientS3.GetObjectCommand({ Bucket: bucket, Key })
|
|
2789
2862
|
);
|
|
2790
|
-
const
|
|
2791
|
-
const
|
|
2863
|
+
const { heartbeat } = getActivityContext();
|
|
2864
|
+
const buf = await streamToBuffer(resp.Body, heartbeat);
|
|
2865
|
+
const json = gzip ? (await gunzipAsync(buf)).toString("utf8") : buf.toString("utf8");
|
|
2792
2866
|
return JSON.parse(json);
|
|
2793
2867
|
} catch (err) {
|
|
2794
2868
|
if (isNotFound(err)) return null;
|
|
@@ -2798,15 +2872,14 @@ function createS3ColdStore(config) {
|
|
|
2798
2872
|
async write(threadKey, threadId, snapshot) {
|
|
2799
2873
|
const Key = buildKey(prefix, threadKey, threadId, gzip);
|
|
2800
2874
|
const json = JSON.stringify(snapshot);
|
|
2801
|
-
const body = gzip ?
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
);
|
|
2875
|
+
const body = gzip ? await gzipAsync(Buffer.from(json, "utf8")) : json;
|
|
2876
|
+
const upload = new libStorage.Upload({
|
|
2877
|
+
client: s3,
|
|
2878
|
+
params: { Bucket: bucket, Key, Body: body, ContentType: contentType }
|
|
2879
|
+
});
|
|
2880
|
+
const { heartbeat } = getActivityContext();
|
|
2881
|
+
if (heartbeat) upload.on("httpUploadProgress", heartbeat);
|
|
2882
|
+
await upload.done();
|
|
2810
2883
|
},
|
|
2811
2884
|
async delete(threadKey, threadId) {
|
|
2812
2885
|
const Key = buildKey(prefix, threadKey, threadId, gzip);
|
|
@@ -2934,40 +3007,6 @@ function createTieredThreadManager(config) {
|
|
|
2934
3007
|
}
|
|
2935
3008
|
});
|
|
2936
3009
|
}
|
|
2937
|
-
function getActivityContext() {
|
|
2938
|
-
try {
|
|
2939
|
-
const ctx = activity.Context.current();
|
|
2940
|
-
return { heartbeat: () => ctx.heartbeat(), signal: ctx.cancellationSignal };
|
|
2941
|
-
} catch {
|
|
2942
|
-
return {};
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
async function queryParentWorkflowState(client) {
|
|
2946
|
-
const { workflowExecution } = activity.Context.current().info;
|
|
2947
|
-
if (!workflowExecution) {
|
|
2948
|
-
throw new Error("No workflow execution found");
|
|
2949
|
-
}
|
|
2950
|
-
const handle = client.getHandle(
|
|
2951
|
-
workflowExecution.workflowId,
|
|
2952
|
-
workflowExecution.runId
|
|
2953
|
-
);
|
|
2954
|
-
return handle.query("getAgentState");
|
|
2955
|
-
}
|
|
2956
|
-
function createRunAgentActivity(client, handler, scope) {
|
|
2957
|
-
const name = `run${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
|
|
2958
|
-
return {
|
|
2959
|
-
[name]: async (config) => {
|
|
2960
|
-
const state = await queryParentWorkflowState(client);
|
|
2961
|
-
return handler({ ...config, state });
|
|
2962
|
-
}
|
|
2963
|
-
};
|
|
2964
|
-
}
|
|
2965
|
-
function withParentWorkflowState(client, handler) {
|
|
2966
|
-
return async (args, context) => {
|
|
2967
|
-
const state = await queryParentWorkflowState(client);
|
|
2968
|
-
return handler(args, { ...context, state });
|
|
2969
|
-
};
|
|
2970
|
-
}
|
|
2971
3010
|
|
|
2972
3011
|
// src/lib/sandbox/manager.ts
|
|
2973
3012
|
var CAP_METHOD_TO_CAPABILITY = [
|
|
@@ -3639,57 +3678,190 @@ ${result.stderr}`,
|
|
|
3639
3678
|
};
|
|
3640
3679
|
|
|
3641
3680
|
// src/tools/edit/handler.ts
|
|
3642
|
-
function
|
|
3643
|
-
|
|
3681
|
+
function splitLines(text) {
|
|
3682
|
+
if (text.length === 0) return [];
|
|
3683
|
+
return text.replace(/\r\n/g, "\n").split("\n");
|
|
3684
|
+
}
|
|
3685
|
+
function lineNumberAt(content, index) {
|
|
3686
|
+
let line = 1;
|
|
3687
|
+
for (let i = 0; i < index; i++) {
|
|
3688
|
+
if (content.charCodeAt(i) === 10) line++;
|
|
3689
|
+
}
|
|
3690
|
+
return line;
|
|
3691
|
+
}
|
|
3692
|
+
function lineEnd(startLine, lines) {
|
|
3693
|
+
return lines.length === 0 ? startLine : startLine + lines.length - 1;
|
|
3694
|
+
}
|
|
3695
|
+
function indicesOf(content, needle) {
|
|
3696
|
+
const indices = [];
|
|
3697
|
+
let cursor = 0;
|
|
3698
|
+
while (cursor <= content.length) {
|
|
3699
|
+
const index = content.indexOf(needle, cursor);
|
|
3700
|
+
if (index === -1) break;
|
|
3701
|
+
indices.push(index);
|
|
3702
|
+
cursor = index + needle.length;
|
|
3703
|
+
}
|
|
3704
|
+
return indices;
|
|
3705
|
+
}
|
|
3706
|
+
function makeHunk(editIndex, beforeContent, replacementIndex, oldString, newString) {
|
|
3707
|
+
const oldStartLine = lineNumberAt(beforeContent, replacementIndex);
|
|
3708
|
+
const oldLines = splitLines(oldString);
|
|
3709
|
+
const newLines = splitLines(newString);
|
|
3710
|
+
return {
|
|
3711
|
+
editIndex,
|
|
3712
|
+
oldStartLine,
|
|
3713
|
+
oldEndLine: lineEnd(oldStartLine, oldLines),
|
|
3714
|
+
newStartLine: oldStartLine,
|
|
3715
|
+
newEndLine: lineEnd(oldStartLine, newLines),
|
|
3716
|
+
oldLines,
|
|
3717
|
+
newLines
|
|
3718
|
+
};
|
|
3719
|
+
}
|
|
3720
|
+
function applyOneEdit(content, edit, editIndex) {
|
|
3721
|
+
const { old_string, new_string, replace_all = false } = edit;
|
|
3722
|
+
if (old_string.length === 0) {
|
|
3723
|
+
return {
|
|
3724
|
+
ok: false,
|
|
3725
|
+
editIndex,
|
|
3726
|
+
message: `Error: old_string for edit ${editIndex} must not be empty.`
|
|
3727
|
+
};
|
|
3728
|
+
}
|
|
3729
|
+
if (old_string === new_string) {
|
|
3730
|
+
return {
|
|
3731
|
+
ok: false,
|
|
3732
|
+
editIndex,
|
|
3733
|
+
message: `Error: old_string and new_string must be different for edit ${editIndex}.`
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
const matches = indicesOf(content, old_string);
|
|
3737
|
+
if (matches.length === 0) {
|
|
3738
|
+
return {
|
|
3739
|
+
ok: false,
|
|
3740
|
+
editIndex,
|
|
3741
|
+
message: `Error: Could not find old_string for edit ${editIndex}. Make sure it matches exactly (whitespace-sensitive).`
|
|
3742
|
+
};
|
|
3743
|
+
}
|
|
3744
|
+
if (!replace_all && matches.length > 1) {
|
|
3745
|
+
return {
|
|
3746
|
+
ok: false,
|
|
3747
|
+
editIndex,
|
|
3748
|
+
message: `Error: old_string for edit ${editIndex} appears ${matches.length} times. Provide more context to make it unique, or use replace_all: true for that edit.`
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
if (replace_all) {
|
|
3752
|
+
const hunks = matches.map(
|
|
3753
|
+
(index2) => makeHunk(editIndex, content, index2, old_string, new_string)
|
|
3754
|
+
);
|
|
3755
|
+
return {
|
|
3756
|
+
ok: true,
|
|
3757
|
+
content: content.split(old_string).join(new_string),
|
|
3758
|
+
replacements: matches.length,
|
|
3759
|
+
hunks
|
|
3760
|
+
};
|
|
3761
|
+
}
|
|
3762
|
+
const index = matches[0];
|
|
3763
|
+
if (index === void 0) {
|
|
3764
|
+
return {
|
|
3765
|
+
ok: false,
|
|
3766
|
+
editIndex,
|
|
3767
|
+
message: `Error: Could not find old_string for edit ${editIndex}.`
|
|
3768
|
+
};
|
|
3769
|
+
}
|
|
3770
|
+
return {
|
|
3771
|
+
ok: true,
|
|
3772
|
+
content: content.slice(0, index) + new_string + content.slice(index + old_string.length),
|
|
3773
|
+
replacements: 1,
|
|
3774
|
+
hunks: [makeHunk(editIndex, content, index, old_string, new_string)]
|
|
3775
|
+
};
|
|
3776
|
+
}
|
|
3777
|
+
function applyEditPlan(content, edits) {
|
|
3778
|
+
if (edits.length === 0) {
|
|
3779
|
+
return {
|
|
3780
|
+
ok: false,
|
|
3781
|
+
message: "Error: edits must contain at least one edit."
|
|
3782
|
+
};
|
|
3783
|
+
}
|
|
3784
|
+
let current = content;
|
|
3785
|
+
let replacements = 0;
|
|
3786
|
+
const hunks = [];
|
|
3787
|
+
for (const [index, edit] of edits.entries()) {
|
|
3788
|
+
const result = applyOneEdit(current, edit, index);
|
|
3789
|
+
if (!result.ok) return result;
|
|
3790
|
+
current = result.content;
|
|
3791
|
+
replacements += result.replacements;
|
|
3792
|
+
hunks.push(...result.hunks);
|
|
3793
|
+
}
|
|
3794
|
+
return { ok: true, content: current, replacements, hunks };
|
|
3795
|
+
}
|
|
3796
|
+
function editFailureResult(filePath, message) {
|
|
3797
|
+
return {
|
|
3798
|
+
toolResponse: message,
|
|
3799
|
+
data: { path: filePath, success: false, replacements: 0 }
|
|
3800
|
+
};
|
|
3644
3801
|
}
|
|
3645
3802
|
var editHandler = async (args, { sandbox }) => {
|
|
3646
3803
|
const { fs } = sandbox;
|
|
3647
3804
|
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
3648
|
-
|
|
3805
|
+
try {
|
|
3806
|
+
const exists = await fs.exists(file_path);
|
|
3807
|
+
if (!exists) {
|
|
3808
|
+
return editFailureResult(
|
|
3809
|
+
file_path,
|
|
3810
|
+
`Error: File "${file_path}" does not exist.`
|
|
3811
|
+
);
|
|
3812
|
+
}
|
|
3813
|
+
const content = await fs.readFile(file_path);
|
|
3814
|
+
const result = applyEditPlan(content, [
|
|
3815
|
+
{ old_string, new_string, replace_all }
|
|
3816
|
+
]);
|
|
3817
|
+
if (!result.ok) {
|
|
3818
|
+
return editFailureResult(file_path, result.message);
|
|
3819
|
+
}
|
|
3820
|
+
await fs.writeFile(file_path, result.content);
|
|
3821
|
+
const summary = replace_all ? `Replaced ${result.replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
3822
|
+
return {
|
|
3823
|
+
toolResponse: `${summary} in ${file_path}`,
|
|
3824
|
+
data: {
|
|
3825
|
+
path: file_path,
|
|
3826
|
+
success: true,
|
|
3827
|
+
replacements: result.replacements,
|
|
3828
|
+
hunks: result.hunks
|
|
3829
|
+
}
|
|
3830
|
+
};
|
|
3831
|
+
} catch (error) {
|
|
3832
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3649
3833
|
return {
|
|
3650
|
-
toolResponse: `Error
|
|
3834
|
+
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
3651
3835
|
data: { path: file_path, success: false, replacements: 0 }
|
|
3652
3836
|
};
|
|
3653
3837
|
}
|
|
3838
|
+
};
|
|
3839
|
+
var multiEditHandler = async (args, { sandbox }) => {
|
|
3840
|
+
const { fs } = sandbox;
|
|
3841
|
+
const { file_path, edits } = args;
|
|
3654
3842
|
try {
|
|
3655
3843
|
const exists = await fs.exists(file_path);
|
|
3656
3844
|
if (!exists) {
|
|
3657
|
-
return
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3845
|
+
return editFailureResult(
|
|
3846
|
+
file_path,
|
|
3847
|
+
`Error: File "${file_path}" does not exist.`
|
|
3848
|
+
);
|
|
3661
3849
|
}
|
|
3662
3850
|
const content = await fs.readFile(file_path);
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
};
|
|
3668
|
-
}
|
|
3669
|
-
const escapedOldString = escapeRegExp(old_string);
|
|
3670
|
-
const globalRegex = new RegExp(escapedOldString, "g");
|
|
3671
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
3672
|
-
if (!replace_all && occurrences > 1) {
|
|
3673
|
-
return {
|
|
3674
|
-
toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
3675
|
-
data: { path: file_path, success: false, replacements: 0 }
|
|
3676
|
-
};
|
|
3677
|
-
}
|
|
3678
|
-
let newContent;
|
|
3679
|
-
let replacements;
|
|
3680
|
-
if (replace_all) {
|
|
3681
|
-
newContent = content.split(old_string).join(new_string);
|
|
3682
|
-
replacements = occurrences;
|
|
3683
|
-
} else {
|
|
3684
|
-
const index = content.indexOf(old_string);
|
|
3685
|
-
newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
|
|
3686
|
-
replacements = 1;
|
|
3851
|
+
const result = applyEditPlan(content, edits);
|
|
3852
|
+
if (!result.ok) {
|
|
3853
|
+
const suffix = result.editIndex === void 0 ? "" : ` in ${file_path}`;
|
|
3854
|
+
return editFailureResult(file_path, `${result.message}${suffix}`);
|
|
3687
3855
|
}
|
|
3688
|
-
await fs.writeFile(file_path,
|
|
3689
|
-
const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
3856
|
+
await fs.writeFile(file_path, result.content);
|
|
3690
3857
|
return {
|
|
3691
|
-
toolResponse:
|
|
3692
|
-
data: {
|
|
3858
|
+
toolResponse: `Applied ${edits.length} edit(s), ${result.replacements} replacement(s) in ${file_path}`,
|
|
3859
|
+
data: {
|
|
3860
|
+
path: file_path,
|
|
3861
|
+
success: true,
|
|
3862
|
+
replacements: result.replacements,
|
|
3863
|
+
hunks: result.hunks
|
|
3864
|
+
}
|
|
3693
3865
|
};
|
|
3694
3866
|
} catch (error) {
|
|
3695
3867
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -3923,6 +4095,8 @@ exports.hasDirectory = hasDirectory;
|
|
|
3923
4095
|
exports.hasFileWithMimeType = hasFileWithMimeType;
|
|
3924
4096
|
exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
|
|
3925
4097
|
exports.isTerminalStatus = isTerminalStatus;
|
|
4098
|
+
exports.multiEditHandler = multiEditHandler;
|
|
4099
|
+
exports.multiEditTool = multiEditTool;
|
|
3926
4100
|
exports.parseSkillFile = parseSkillFile;
|
|
3927
4101
|
exports.proxyRunAgent = proxyRunAgent;
|
|
3928
4102
|
exports.proxyVirtualFsOps = proxyVirtualFsOps;
|