zeitlich 0.2.46 → 0.2.48
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 +66 -6
- package/dist/{activities-CyeiqK_f.d.cts → activities-BlQR5gX4.d.cts} +3 -3
- package/dist/{activities-Bm4TLTid.d.ts → activities-DCaIPQBT.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-BC5L5Z8A.d.cts → cold-store-UL13Sstw.d.cts} +8 -11
- package/dist/{cold-store-CFHwemBJ.d.ts → cold-store-aD4TSKlU.d.ts} +8 -11
- package/dist/index.cjs +311 -99
- 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 +312 -102
- package/dist/index.js.map +1 -1
- package/dist/proxy-BAty3CWM.d.cts +40 -0
- package/dist/proxy-mbnwBhHw.d.ts +40 -0
- package/dist/{thread-manager-DduoSkvJ.d.ts → thread-manager-CICj68PI.d.ts} +2 -2
- package/dist/{thread-manager-D33SUmZa.d.cts → thread-manager-DsXvJ5cJ.d.cts} +2 -2
- package/dist/{thread-manager-B-zy3xrs.d.ts → thread-manager-DtEtbUkp.d.ts} +2 -2
- package/dist/{thread-manager-9tezUcLW.d.cts → thread-manager-R6c3lnJy.d.cts} +2 -2
- package/dist/{types-oxt8GN97.d.cts → types-DDLPnxBh.d.cts} +1 -1
- package/dist/{types-L5bvbF-n.d.ts → types-DF4wzWQG.d.ts} +1 -1
- package/dist/{types-CnuN9T6t.d.cts → types-DWeyCTYK.d.cts} +47 -0
- package/dist/{types-CwN6_tAL.d.ts → types-DwBYd0ij.d.ts} +47 -0
- package/dist/{workflow-DIaIV7L2.d.cts → workflow-DVNPR7eX.d.cts} +17 -2
- package/dist/{workflow-B1TOcHbt.d.ts → workflow-DdaU7_j4.d.ts} +17 -2
- package/dist/workflow.cjs +80 -12
- 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 +80 -13
- package/dist/workflow.js.map +1 -1
- package/package.json +14 -8
- 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/lifecycle.ts +13 -1
- package/src/lib/session/session-edge-cases.integration.test.ts +44 -0
- package/src/lib/session/session.ts +15 -0
- package/src/lib/subagent/define.ts +1 -0
- package/src/lib/subagent/handler.ts +41 -6
- package/src/lib/subagent/subagent.integration.test.ts +178 -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/lib/tool-router/router-edge-cases.integration.test.ts +36 -0
- package/src/lib/tool-router/router.ts +21 -3
- package/src/lib/tool-router/types.ts +20 -0
- 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.js
CHANGED
|
@@ -3,8 +3,10 @@ import z14, { z } from 'zod';
|
|
|
3
3
|
import { randomUUID, randomFillSync } from 'crypto';
|
|
4
4
|
import { ApplicationFailure as ApplicationFailure$1 } from '@temporalio/common';
|
|
5
5
|
import { join, resolve, posix } from 'path';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { gzip, gunzip } from 'zlib';
|
|
7
|
+
import { promisify } from 'util';
|
|
8
|
+
import { DeleteObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
|
|
9
|
+
import { Upload } from '@aws-sdk/lib-storage';
|
|
8
10
|
import { Context } from '@temporalio/activity';
|
|
9
11
|
import { promises } from 'fs';
|
|
10
12
|
|
|
@@ -123,7 +125,7 @@ function createToolRouter(options) {
|
|
|
123
125
|
});
|
|
124
126
|
}
|
|
125
127
|
}
|
|
126
|
-
async function processToolCall(toolCall, turn, sandboxId, onRewindRequested) {
|
|
128
|
+
async function processToolCall(toolCall, turn, sandboxId, onRewindRequested, assistantMessageId) {
|
|
127
129
|
const startTime = Date.now();
|
|
128
130
|
const tool = toolMap.get(toolCall.name);
|
|
129
131
|
const preResult = await runPreHooks(toolCall, tool, turn);
|
|
@@ -158,7 +160,8 @@ function createToolRouter(options) {
|
|
|
158
160
|
...options.threadKey && { threadKey: options.threadKey },
|
|
159
161
|
toolCallId: toolCall.id,
|
|
160
162
|
toolName: toolCall.name,
|
|
161
|
-
...sandboxId !== void 0 && { sandboxId }
|
|
163
|
+
...sandboxId !== void 0 && { sandboxId },
|
|
164
|
+
...assistantMessageId !== void 0 && { assistantMessageId }
|
|
162
165
|
};
|
|
163
166
|
const response = await tool.handler(
|
|
164
167
|
effectiveArgs,
|
|
@@ -285,6 +288,7 @@ function createToolRouter(options) {
|
|
|
285
288
|
}
|
|
286
289
|
const turn = context?.turn ?? 0;
|
|
287
290
|
const sandboxId = context?.sandboxId;
|
|
291
|
+
const assistantMessageId = context?.assistantMessageId;
|
|
288
292
|
let rewindSignal;
|
|
289
293
|
if (options.parallel) {
|
|
290
294
|
const scope = new CancellationScope({ cancellable: true });
|
|
@@ -297,7 +301,13 @@ function createToolRouter(options) {
|
|
|
297
301
|
const outcomes = await scope.run(
|
|
298
302
|
async () => Promise.allSettled(
|
|
299
303
|
toolCalls.map(
|
|
300
|
-
(tc) => processToolCall(
|
|
304
|
+
(tc) => processToolCall(
|
|
305
|
+
tc,
|
|
306
|
+
turn,
|
|
307
|
+
sandboxId,
|
|
308
|
+
onRewindRequested,
|
|
309
|
+
assistantMessageId
|
|
310
|
+
)
|
|
301
311
|
)
|
|
302
312
|
)
|
|
303
313
|
);
|
|
@@ -317,7 +327,13 @@ function createToolRouter(options) {
|
|
|
317
327
|
}
|
|
318
328
|
const results = [];
|
|
319
329
|
for (const toolCall of toolCalls) {
|
|
320
|
-
const outcome = await processToolCall(
|
|
330
|
+
const outcome = await processToolCall(
|
|
331
|
+
toolCall,
|
|
332
|
+
turn,
|
|
333
|
+
sandboxId,
|
|
334
|
+
void 0,
|
|
335
|
+
assistantMessageId
|
|
336
|
+
);
|
|
321
337
|
if (outcome.kind === "rewind") {
|
|
322
338
|
rewindSignal = outcome.signal;
|
|
323
339
|
break;
|
|
@@ -341,6 +357,9 @@ function createToolRouter(options) {
|
|
|
341
357
|
toolName: toolCall.name,
|
|
342
358
|
...context?.sandboxId !== void 0 && {
|
|
343
359
|
sandboxId: context.sandboxId
|
|
360
|
+
},
|
|
361
|
+
...context?.assistantMessageId !== void 0 && {
|
|
362
|
+
assistantMessageId: context.assistantMessageId
|
|
344
363
|
}
|
|
345
364
|
};
|
|
346
365
|
const response = await handler(
|
|
@@ -566,13 +585,27 @@ function createSubagentHandler(subagents) {
|
|
|
566
585
|
}
|
|
567
586
|
const threadMode = config.thread ?? "new";
|
|
568
587
|
const allowsContinuation = threadMode !== "new";
|
|
569
|
-
const
|
|
588
|
+
const newThreadSource = config.newThreadSource ?? "new";
|
|
589
|
+
const usingParentFallback = allowsContinuation && !args.threadId && newThreadSource === "from-parent";
|
|
590
|
+
const continuationThreadId = !allowsContinuation ? void 0 : args.threadId ?? (usingParentFallback ? context.threadId : void 0);
|
|
570
591
|
let thread;
|
|
571
592
|
if (continuationThreadId) {
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
593
|
+
if (threadMode === "fork") {
|
|
594
|
+
thread = {
|
|
595
|
+
mode: "fork",
|
|
596
|
+
threadId: continuationThreadId,
|
|
597
|
+
...usingParentFallback && context.assistantMessageId ? {
|
|
598
|
+
truncateAfterFork: {
|
|
599
|
+
fromMessageId: context.assistantMessageId
|
|
600
|
+
}
|
|
601
|
+
} : {}
|
|
602
|
+
};
|
|
603
|
+
} else {
|
|
604
|
+
thread = {
|
|
605
|
+
mode: "continue",
|
|
606
|
+
threadId: continuationThreadId
|
|
607
|
+
};
|
|
608
|
+
}
|
|
576
609
|
}
|
|
577
610
|
let sandbox;
|
|
578
611
|
let sandboxShutdownOverride;
|
|
@@ -1033,6 +1066,7 @@ async function createSession(config) {
|
|
|
1033
1066
|
appendSystemMessage,
|
|
1034
1067
|
appendAgentMessage,
|
|
1035
1068
|
forkThread,
|
|
1069
|
+
truncateThread,
|
|
1036
1070
|
loadThreadState,
|
|
1037
1071
|
saveThreadState,
|
|
1038
1072
|
hydrateThread,
|
|
@@ -1182,6 +1216,10 @@ async function createSession(config) {
|
|
|
1182
1216
|
if (threadMode === "fork" && sourceThreadId) {
|
|
1183
1217
|
await hydrateThread(sourceThreadId, threadKey);
|
|
1184
1218
|
await forkThread(sourceThreadId, threadId, threadKey);
|
|
1219
|
+
const truncate = threadInit.truncateAfterFork;
|
|
1220
|
+
if (truncate?.fromMessageId) {
|
|
1221
|
+
await truncateThread(threadId, truncate.fromMessageId, threadKey);
|
|
1222
|
+
}
|
|
1185
1223
|
const forkedSlice = await loadThreadState(threadId, threadKey);
|
|
1186
1224
|
if (forkedSlice) rehydrateFromSlice(forkedSlice);
|
|
1187
1225
|
} else if (threadMode === "continue") {
|
|
@@ -1311,7 +1349,10 @@ async function createSession(config) {
|
|
|
1311
1349
|
parsedToolCalls,
|
|
1312
1350
|
{
|
|
1313
1351
|
turn: currentTurn,
|
|
1314
|
-
...sandboxId !== void 0 && { sandboxId }
|
|
1352
|
+
...sandboxId !== void 0 && { sandboxId },
|
|
1353
|
+
...assistantId !== void 0 && {
|
|
1354
|
+
assistantMessageId: assistantId
|
|
1355
|
+
}
|
|
1315
1356
|
}
|
|
1316
1357
|
);
|
|
1317
1358
|
for (const result of toolCallResults) {
|
|
@@ -2214,6 +2255,13 @@ IMPORTANT:
|
|
|
2214
2255
|
}),
|
|
2215
2256
|
strict: true
|
|
2216
2257
|
};
|
|
2258
|
+
var textEditSchema = z.object({
|
|
2259
|
+
old_string: z.string().describe("The exact text to replace"),
|
|
2260
|
+
new_string: z.string().describe("The text to replace it with"),
|
|
2261
|
+
replace_all: z.boolean().optional().describe(
|
|
2262
|
+
"If true, replace all occurrences of old_string for this edit (default: false)"
|
|
2263
|
+
)
|
|
2264
|
+
});
|
|
2217
2265
|
var editTool = {
|
|
2218
2266
|
name: "FileEdit",
|
|
2219
2267
|
description: `Edit specific sections of a file by replacing text.
|
|
@@ -2242,6 +2290,27 @@ IMPORTANT:
|
|
|
2242
2290
|
}),
|
|
2243
2291
|
strict: true
|
|
2244
2292
|
};
|
|
2293
|
+
var multiEditTool = {
|
|
2294
|
+
name: "FileMultiEdit",
|
|
2295
|
+
description: `Apply multiple exact text replacements to one file in order.
|
|
2296
|
+
|
|
2297
|
+
Usage:
|
|
2298
|
+
- Use this when a task needs several related edits in the same file
|
|
2299
|
+
- Each edit is applied to the file content produced by the prior edit
|
|
2300
|
+
- The operation is atomic: if any edit fails, the file is left unchanged
|
|
2301
|
+
|
|
2302
|
+
IMPORTANT:
|
|
2303
|
+
- You must read the file first (in this session) before editing it
|
|
2304
|
+
- Each old_string must match exactly (whitespace-sensitive)
|
|
2305
|
+
- Each old_string must be unique unless that edit uses replace_all: true
|
|
2306
|
+
- old_string and new_string must be different for every edit
|
|
2307
|
+
`,
|
|
2308
|
+
schema: z.object({
|
|
2309
|
+
file_path: z.string().describe("The absolute virtual path to the file to modify"),
|
|
2310
|
+
edits: z.array(textEditSchema).min(1).describe("Exact replacements to apply sequentially to the file")
|
|
2311
|
+
}),
|
|
2312
|
+
strict: true
|
|
2313
|
+
};
|
|
2245
2314
|
var taskCreateTool = {
|
|
2246
2315
|
name: "TaskCreate",
|
|
2247
2316
|
description: `Use this tool to create a structured task list. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
@@ -2312,7 +2381,7 @@ function createTaskCreateHandler(stateManager) {
|
|
|
2312
2381
|
};
|
|
2313
2382
|
stateManager.setTask(task);
|
|
2314
2383
|
return {
|
|
2315
|
-
toolResponse:
|
|
2384
|
+
toolResponse: `Task ${task.id} created`,
|
|
2316
2385
|
data: task
|
|
2317
2386
|
};
|
|
2318
2387
|
};
|
|
@@ -2411,7 +2480,7 @@ function createTaskUpdateHandler(stateManager) {
|
|
|
2411
2480
|
}
|
|
2412
2481
|
stateManager.setTask(task);
|
|
2413
2482
|
return {
|
|
2414
|
-
toolResponse:
|
|
2483
|
+
toolResponse: `Task ${task.id} updated`,
|
|
2415
2484
|
data: task
|
|
2416
2485
|
};
|
|
2417
2486
|
};
|
|
@@ -2743,6 +2812,44 @@ function createThreadManager(config) {
|
|
|
2743
2812
|
}
|
|
2744
2813
|
};
|
|
2745
2814
|
}
|
|
2815
|
+
function getActivityContext() {
|
|
2816
|
+
try {
|
|
2817
|
+
const ctx = Context.current();
|
|
2818
|
+
return { heartbeat: () => ctx.heartbeat(), signal: ctx.cancellationSignal };
|
|
2819
|
+
} catch {
|
|
2820
|
+
return {};
|
|
2821
|
+
}
|
|
2822
|
+
}
|
|
2823
|
+
async function queryParentWorkflowState(client) {
|
|
2824
|
+
const { workflowExecution } = Context.current().info;
|
|
2825
|
+
if (!workflowExecution) {
|
|
2826
|
+
throw new Error("No workflow execution found");
|
|
2827
|
+
}
|
|
2828
|
+
const handle = client.getHandle(
|
|
2829
|
+
workflowExecution.workflowId,
|
|
2830
|
+
workflowExecution.runId
|
|
2831
|
+
);
|
|
2832
|
+
return handle.query("getAgentState");
|
|
2833
|
+
}
|
|
2834
|
+
function createRunAgentActivity(client, handler, scope) {
|
|
2835
|
+
const name = `run${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
|
|
2836
|
+
return {
|
|
2837
|
+
[name]: async (config) => {
|
|
2838
|
+
const state = await queryParentWorkflowState(client);
|
|
2839
|
+
return handler({ ...config, state });
|
|
2840
|
+
}
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
function withParentWorkflowState(client, handler) {
|
|
2844
|
+
return async (args, context) => {
|
|
2845
|
+
const state = await queryParentWorkflowState(client);
|
|
2846
|
+
return handler(args, { ...context, state });
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
// src/lib/thread/cold-store.ts
|
|
2851
|
+
var gzipAsync = promisify(gzip);
|
|
2852
|
+
var gunzipAsync = promisify(gunzip);
|
|
2746
2853
|
function joinKey(parts) {
|
|
2747
2854
|
return parts.map((p) => p.replace(/^\/+|\/+$/g, "")).filter((p) => p.length > 0).join("/");
|
|
2748
2855
|
}
|
|
@@ -2754,9 +2861,17 @@ function buildKey(prefix, threadKey, threadId, gzip) {
|
|
|
2754
2861
|
`${threadId}.${ext}`
|
|
2755
2862
|
]);
|
|
2756
2863
|
}
|
|
2757
|
-
async function streamToBuffer(body) {
|
|
2864
|
+
async function streamToBuffer(body, onChunk) {
|
|
2758
2865
|
if (body == null) return Buffer.alloc(0);
|
|
2759
2866
|
if (body instanceof Uint8Array) return Buffer.from(body);
|
|
2867
|
+
if (typeof body[Symbol.asyncIterator] === "function") {
|
|
2868
|
+
const chunks = [];
|
|
2869
|
+
for await (const chunk of body) {
|
|
2870
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
2871
|
+
onChunk?.();
|
|
2872
|
+
}
|
|
2873
|
+
return Buffer.concat(chunks);
|
|
2874
|
+
}
|
|
2760
2875
|
if (typeof body.transformToByteArray === "function") {
|
|
2761
2876
|
const bytes = await body.transformToByteArray();
|
|
2762
2877
|
return Buffer.from(bytes);
|
|
@@ -2765,11 +2880,7 @@ async function streamToBuffer(body) {
|
|
|
2765
2880
|
const ab = await body.arrayBuffer();
|
|
2766
2881
|
return Buffer.from(ab);
|
|
2767
2882
|
}
|
|
2768
|
-
|
|
2769
|
-
for await (const chunk of body) {
|
|
2770
|
-
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
2771
|
-
}
|
|
2772
|
-
return Buffer.concat(chunks);
|
|
2883
|
+
return Buffer.alloc(0);
|
|
2773
2884
|
}
|
|
2774
2885
|
function createS3ColdStore(config) {
|
|
2775
2886
|
const { s3, bucket, prefix, gzip = true } = config;
|
|
@@ -2781,8 +2892,9 @@ function createS3ColdStore(config) {
|
|
|
2781
2892
|
const resp = await s3.send(
|
|
2782
2893
|
new GetObjectCommand({ Bucket: bucket, Key })
|
|
2783
2894
|
);
|
|
2784
|
-
const
|
|
2785
|
-
const
|
|
2895
|
+
const { heartbeat } = getActivityContext();
|
|
2896
|
+
const buf = await streamToBuffer(resp.Body, heartbeat);
|
|
2897
|
+
const json = gzip ? (await gunzipAsync(buf)).toString("utf8") : buf.toString("utf8");
|
|
2786
2898
|
return JSON.parse(json);
|
|
2787
2899
|
} catch (err) {
|
|
2788
2900
|
if (isNotFound(err)) return null;
|
|
@@ -2792,15 +2904,14 @@ function createS3ColdStore(config) {
|
|
|
2792
2904
|
async write(threadKey, threadId, snapshot) {
|
|
2793
2905
|
const Key = buildKey(prefix, threadKey, threadId, gzip);
|
|
2794
2906
|
const json = JSON.stringify(snapshot);
|
|
2795
|
-
const body = gzip ?
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
);
|
|
2907
|
+
const body = gzip ? await gzipAsync(Buffer.from(json, "utf8")) : json;
|
|
2908
|
+
const upload = new Upload({
|
|
2909
|
+
client: s3,
|
|
2910
|
+
params: { Bucket: bucket, Key, Body: body, ContentType: contentType }
|
|
2911
|
+
});
|
|
2912
|
+
const { heartbeat } = getActivityContext();
|
|
2913
|
+
if (heartbeat) upload.on("httpUploadProgress", heartbeat);
|
|
2914
|
+
await upload.done();
|
|
2804
2915
|
},
|
|
2805
2916
|
async delete(threadKey, threadId) {
|
|
2806
2917
|
const Key = buildKey(prefix, threadKey, threadId, gzip);
|
|
@@ -2928,40 +3039,6 @@ function createTieredThreadManager(config) {
|
|
|
2928
3039
|
}
|
|
2929
3040
|
});
|
|
2930
3041
|
}
|
|
2931
|
-
function getActivityContext() {
|
|
2932
|
-
try {
|
|
2933
|
-
const ctx = Context.current();
|
|
2934
|
-
return { heartbeat: () => ctx.heartbeat(), signal: ctx.cancellationSignal };
|
|
2935
|
-
} catch {
|
|
2936
|
-
return {};
|
|
2937
|
-
}
|
|
2938
|
-
}
|
|
2939
|
-
async function queryParentWorkflowState(client) {
|
|
2940
|
-
const { workflowExecution } = Context.current().info;
|
|
2941
|
-
if (!workflowExecution) {
|
|
2942
|
-
throw new Error("No workflow execution found");
|
|
2943
|
-
}
|
|
2944
|
-
const handle = client.getHandle(
|
|
2945
|
-
workflowExecution.workflowId,
|
|
2946
|
-
workflowExecution.runId
|
|
2947
|
-
);
|
|
2948
|
-
return handle.query("getAgentState");
|
|
2949
|
-
}
|
|
2950
|
-
function createRunAgentActivity(client, handler, scope) {
|
|
2951
|
-
const name = `run${scope.charAt(0).toUpperCase()}${scope.slice(1)}`;
|
|
2952
|
-
return {
|
|
2953
|
-
[name]: async (config) => {
|
|
2954
|
-
const state = await queryParentWorkflowState(client);
|
|
2955
|
-
return handler({ ...config, state });
|
|
2956
|
-
}
|
|
2957
|
-
};
|
|
2958
|
-
}
|
|
2959
|
-
function withParentWorkflowState(client, handler) {
|
|
2960
|
-
return async (args, context) => {
|
|
2961
|
-
const state = await queryParentWorkflowState(client);
|
|
2962
|
-
return handler(args, { ...context, state });
|
|
2963
|
-
};
|
|
2964
|
-
}
|
|
2965
3042
|
|
|
2966
3043
|
// src/lib/sandbox/manager.ts
|
|
2967
3044
|
var CAP_METHOD_TO_CAPABILITY = [
|
|
@@ -3633,57 +3710,190 @@ ${result.stderr}`,
|
|
|
3633
3710
|
};
|
|
3634
3711
|
|
|
3635
3712
|
// src/tools/edit/handler.ts
|
|
3636
|
-
function
|
|
3637
|
-
|
|
3713
|
+
function splitLines(text) {
|
|
3714
|
+
if (text.length === 0) return [];
|
|
3715
|
+
return text.replace(/\r\n/g, "\n").split("\n");
|
|
3716
|
+
}
|
|
3717
|
+
function lineNumberAt(content, index) {
|
|
3718
|
+
let line = 1;
|
|
3719
|
+
for (let i = 0; i < index; i++) {
|
|
3720
|
+
if (content.charCodeAt(i) === 10) line++;
|
|
3721
|
+
}
|
|
3722
|
+
return line;
|
|
3723
|
+
}
|
|
3724
|
+
function lineEnd(startLine, lines) {
|
|
3725
|
+
return lines.length === 0 ? startLine : startLine + lines.length - 1;
|
|
3726
|
+
}
|
|
3727
|
+
function indicesOf(content, needle) {
|
|
3728
|
+
const indices = [];
|
|
3729
|
+
let cursor = 0;
|
|
3730
|
+
while (cursor <= content.length) {
|
|
3731
|
+
const index = content.indexOf(needle, cursor);
|
|
3732
|
+
if (index === -1) break;
|
|
3733
|
+
indices.push(index);
|
|
3734
|
+
cursor = index + needle.length;
|
|
3735
|
+
}
|
|
3736
|
+
return indices;
|
|
3737
|
+
}
|
|
3738
|
+
function makeHunk(editIndex, beforeContent, replacementIndex, oldString, newString) {
|
|
3739
|
+
const oldStartLine = lineNumberAt(beforeContent, replacementIndex);
|
|
3740
|
+
const oldLines = splitLines(oldString);
|
|
3741
|
+
const newLines = splitLines(newString);
|
|
3742
|
+
return {
|
|
3743
|
+
editIndex,
|
|
3744
|
+
oldStartLine,
|
|
3745
|
+
oldEndLine: lineEnd(oldStartLine, oldLines),
|
|
3746
|
+
newStartLine: oldStartLine,
|
|
3747
|
+
newEndLine: lineEnd(oldStartLine, newLines),
|
|
3748
|
+
oldLines,
|
|
3749
|
+
newLines
|
|
3750
|
+
};
|
|
3751
|
+
}
|
|
3752
|
+
function applyOneEdit(content, edit, editIndex) {
|
|
3753
|
+
const { old_string, new_string, replace_all = false } = edit;
|
|
3754
|
+
if (old_string.length === 0) {
|
|
3755
|
+
return {
|
|
3756
|
+
ok: false,
|
|
3757
|
+
editIndex,
|
|
3758
|
+
message: `Error: old_string for edit ${editIndex} must not be empty.`
|
|
3759
|
+
};
|
|
3760
|
+
}
|
|
3761
|
+
if (old_string === new_string) {
|
|
3762
|
+
return {
|
|
3763
|
+
ok: false,
|
|
3764
|
+
editIndex,
|
|
3765
|
+
message: `Error: old_string and new_string must be different for edit ${editIndex}.`
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3768
|
+
const matches = indicesOf(content, old_string);
|
|
3769
|
+
if (matches.length === 0) {
|
|
3770
|
+
return {
|
|
3771
|
+
ok: false,
|
|
3772
|
+
editIndex,
|
|
3773
|
+
message: `Error: Could not find old_string for edit ${editIndex}. Make sure it matches exactly (whitespace-sensitive).`
|
|
3774
|
+
};
|
|
3775
|
+
}
|
|
3776
|
+
if (!replace_all && matches.length > 1) {
|
|
3777
|
+
return {
|
|
3778
|
+
ok: false,
|
|
3779
|
+
editIndex,
|
|
3780
|
+
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.`
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
if (replace_all) {
|
|
3784
|
+
const hunks = matches.map(
|
|
3785
|
+
(index2) => makeHunk(editIndex, content, index2, old_string, new_string)
|
|
3786
|
+
);
|
|
3787
|
+
return {
|
|
3788
|
+
ok: true,
|
|
3789
|
+
content: content.split(old_string).join(new_string),
|
|
3790
|
+
replacements: matches.length,
|
|
3791
|
+
hunks
|
|
3792
|
+
};
|
|
3793
|
+
}
|
|
3794
|
+
const index = matches[0];
|
|
3795
|
+
if (index === void 0) {
|
|
3796
|
+
return {
|
|
3797
|
+
ok: false,
|
|
3798
|
+
editIndex,
|
|
3799
|
+
message: `Error: Could not find old_string for edit ${editIndex}.`
|
|
3800
|
+
};
|
|
3801
|
+
}
|
|
3802
|
+
return {
|
|
3803
|
+
ok: true,
|
|
3804
|
+
content: content.slice(0, index) + new_string + content.slice(index + old_string.length),
|
|
3805
|
+
replacements: 1,
|
|
3806
|
+
hunks: [makeHunk(editIndex, content, index, old_string, new_string)]
|
|
3807
|
+
};
|
|
3808
|
+
}
|
|
3809
|
+
function applyEditPlan(content, edits) {
|
|
3810
|
+
if (edits.length === 0) {
|
|
3811
|
+
return {
|
|
3812
|
+
ok: false,
|
|
3813
|
+
message: "Error: edits must contain at least one edit."
|
|
3814
|
+
};
|
|
3815
|
+
}
|
|
3816
|
+
let current = content;
|
|
3817
|
+
let replacements = 0;
|
|
3818
|
+
const hunks = [];
|
|
3819
|
+
for (const [index, edit] of edits.entries()) {
|
|
3820
|
+
const result = applyOneEdit(current, edit, index);
|
|
3821
|
+
if (!result.ok) return result;
|
|
3822
|
+
current = result.content;
|
|
3823
|
+
replacements += result.replacements;
|
|
3824
|
+
hunks.push(...result.hunks);
|
|
3825
|
+
}
|
|
3826
|
+
return { ok: true, content: current, replacements, hunks };
|
|
3827
|
+
}
|
|
3828
|
+
function editFailureResult(filePath, message) {
|
|
3829
|
+
return {
|
|
3830
|
+
toolResponse: message,
|
|
3831
|
+
data: { path: filePath, success: false, replacements: 0 }
|
|
3832
|
+
};
|
|
3638
3833
|
}
|
|
3639
3834
|
var editHandler = async (args, { sandbox }) => {
|
|
3640
3835
|
const { fs } = sandbox;
|
|
3641
3836
|
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
3642
|
-
|
|
3837
|
+
try {
|
|
3838
|
+
const exists = await fs.exists(file_path);
|
|
3839
|
+
if (!exists) {
|
|
3840
|
+
return editFailureResult(
|
|
3841
|
+
file_path,
|
|
3842
|
+
`Error: File "${file_path}" does not exist.`
|
|
3843
|
+
);
|
|
3844
|
+
}
|
|
3845
|
+
const content = await fs.readFile(file_path);
|
|
3846
|
+
const result = applyEditPlan(content, [
|
|
3847
|
+
{ old_string, new_string, replace_all }
|
|
3848
|
+
]);
|
|
3849
|
+
if (!result.ok) {
|
|
3850
|
+
return editFailureResult(file_path, result.message);
|
|
3851
|
+
}
|
|
3852
|
+
await fs.writeFile(file_path, result.content);
|
|
3853
|
+
const summary = replace_all ? `Replaced ${result.replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
3643
3854
|
return {
|
|
3644
|
-
toolResponse:
|
|
3855
|
+
toolResponse: `${summary} in ${file_path}`,
|
|
3856
|
+
data: {
|
|
3857
|
+
path: file_path,
|
|
3858
|
+
success: true,
|
|
3859
|
+
replacements: result.replacements,
|
|
3860
|
+
hunks: result.hunks
|
|
3861
|
+
}
|
|
3862
|
+
};
|
|
3863
|
+
} catch (error) {
|
|
3864
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3865
|
+
return {
|
|
3866
|
+
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
3645
3867
|
data: { path: file_path, success: false, replacements: 0 }
|
|
3646
3868
|
};
|
|
3647
3869
|
}
|
|
3870
|
+
};
|
|
3871
|
+
var multiEditHandler = async (args, { sandbox }) => {
|
|
3872
|
+
const { fs } = sandbox;
|
|
3873
|
+
const { file_path, edits } = args;
|
|
3648
3874
|
try {
|
|
3649
3875
|
const exists = await fs.exists(file_path);
|
|
3650
3876
|
if (!exists) {
|
|
3651
|
-
return
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3877
|
+
return editFailureResult(
|
|
3878
|
+
file_path,
|
|
3879
|
+
`Error: File "${file_path}" does not exist.`
|
|
3880
|
+
);
|
|
3655
3881
|
}
|
|
3656
3882
|
const content = await fs.readFile(file_path);
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
};
|
|
3662
|
-
}
|
|
3663
|
-
const escapedOldString = escapeRegExp(old_string);
|
|
3664
|
-
const globalRegex = new RegExp(escapedOldString, "g");
|
|
3665
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
3666
|
-
if (!replace_all && occurrences > 1) {
|
|
3667
|
-
return {
|
|
3668
|
-
toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
3669
|
-
data: { path: file_path, success: false, replacements: 0 }
|
|
3670
|
-
};
|
|
3671
|
-
}
|
|
3672
|
-
let newContent;
|
|
3673
|
-
let replacements;
|
|
3674
|
-
if (replace_all) {
|
|
3675
|
-
newContent = content.split(old_string).join(new_string);
|
|
3676
|
-
replacements = occurrences;
|
|
3677
|
-
} else {
|
|
3678
|
-
const index = content.indexOf(old_string);
|
|
3679
|
-
newContent = content.slice(0, index) + new_string + content.slice(index + old_string.length);
|
|
3680
|
-
replacements = 1;
|
|
3883
|
+
const result = applyEditPlan(content, edits);
|
|
3884
|
+
if (!result.ok) {
|
|
3885
|
+
const suffix = result.editIndex === void 0 ? "" : ` in ${file_path}`;
|
|
3886
|
+
return editFailureResult(file_path, `${result.message}${suffix}`);
|
|
3681
3887
|
}
|
|
3682
|
-
await fs.writeFile(file_path,
|
|
3683
|
-
const summary = replace_all ? `Replaced ${replacements} occurrence(s)` : `Replaced 1 occurrence`;
|
|
3888
|
+
await fs.writeFile(file_path, result.content);
|
|
3684
3889
|
return {
|
|
3685
|
-
toolResponse:
|
|
3686
|
-
data: {
|
|
3890
|
+
toolResponse: `Applied ${edits.length} edit(s), ${result.replacements} replacement(s) in ${file_path}`,
|
|
3891
|
+
data: {
|
|
3892
|
+
path: file_path,
|
|
3893
|
+
success: true,
|
|
3894
|
+
replacements: result.replacements,
|
|
3895
|
+
hunks: result.hunks
|
|
3896
|
+
}
|
|
3687
3897
|
};
|
|
3688
3898
|
} catch (error) {
|
|
3689
3899
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
@@ -3863,6 +4073,6 @@ var toTree = async (fs, opts = {}) => {
|
|
|
3863
4073
|
return base + subtree;
|
|
3864
4074
|
};
|
|
3865
4075
|
|
|
3866
|
-
export { DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT, FileSystemSkillProvider, NodeFsSandboxFileSystem, SandboxManager, SandboxNotFoundError, SandboxNotSupportedError, THREAD_TTL_SECONDS, VirtualFileSystem, applySnapshot, applyVirtualTreeMutations, askUserQuestionTool, bashHandler, bashTool, clearHotTier, composeHooks, createAgentStateManager, createAskUserQuestionHandler, createBashToolDescription, createObservabilityHooks, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createS3ColdStore, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createTieredThreadManager, createToolRouter, createVirtualFsActivities, defineSubagent, defineSubagentWorkflow, defineTool, defineWorkflow, editHandler, editTool, encodeSnapshot, filesWithMimeType, formatVirtualFileTree, getActivityContext, getShortId, getThreadDedupKey, getThreadListKey, getThreadMetaKey, getThreadStateKey, globHandler, globTool, grepTool, hasDirectory, hasFileWithMimeType, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyRunAgent, proxyVirtualFsOps, queryParentWorkflowState, readFileHandler, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, withParentWorkflowState, withSandbox, withVirtualFs, writeFileHandler, writeFileTool };
|
|
4076
|
+
export { DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT, FileSystemSkillProvider, NodeFsSandboxFileSystem, SandboxManager, SandboxNotFoundError, SandboxNotSupportedError, THREAD_TTL_SECONDS, VirtualFileSystem, applySnapshot, applyVirtualTreeMutations, askUserQuestionTool, bashHandler, bashTool, clearHotTier, composeHooks, createAgentStateManager, createAskUserQuestionHandler, createBashToolDescription, createObservabilityHooks, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createS3ColdStore, createSession, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createTieredThreadManager, createToolRouter, createVirtualFsActivities, defineSubagent, defineSubagentWorkflow, defineTool, defineWorkflow, editHandler, editTool, encodeSnapshot, filesWithMimeType, formatVirtualFileTree, getActivityContext, getShortId, getThreadDedupKey, getThreadListKey, getThreadMetaKey, getThreadStateKey, globHandler, globTool, grepTool, hasDirectory, hasFileWithMimeType, hasNoOtherToolCalls, isTerminalStatus, multiEditHandler, multiEditTool, parseSkillFile, proxyRunAgent, proxyVirtualFsOps, queryParentWorkflowState, readFileHandler, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, withParentWorkflowState, withSandbox, withVirtualFs, writeFileHandler, writeFileTool };
|
|
3867
4077
|
//# sourceMappingURL=index.js.map
|
|
3868
4078
|
//# sourceMappingURL=index.js.map
|