zeitlich 0.2.2 → 0.2.3
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 +34 -31
- package/dist/index.cjs +305 -361
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -43
- package/dist/index.d.ts +24 -43
- package/dist/index.js +277 -336
- package/dist/index.js.map +1 -1
- package/dist/{workflow-BQf5EfNN.d.cts → workflow-D-2vp4Pq.d.cts} +265 -241
- package/dist/{workflow-BQf5EfNN.d.ts → workflow-D-2vp4Pq.d.ts} +265 -241
- package/dist/workflow.cjs +206 -253
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -3
- package/dist/workflow.d.ts +2 -3
- package/dist/workflow.js +182 -231
- package/dist/workflow.js.map +1 -1
- package/package.json +3 -2
- package/src/activities.ts +1 -14
- package/src/index.ts +14 -11
- package/src/lib/session.ts +56 -99
- package/src/lib/thread-manager.ts +45 -37
- package/src/lib/tool-router.ts +143 -103
- package/src/lib/types.ts +32 -25
- package/src/tools/ask-user-question/handler.ts +5 -5
- package/src/tools/ask-user-question/tool.ts +3 -2
- package/src/tools/bash/bash.test.ts +12 -12
- package/src/tools/bash/handler.ts +5 -5
- package/src/tools/bash/tool.ts +3 -2
- package/src/tools/edit/handler.ts +78 -123
- package/src/tools/edit/tool.ts +3 -2
- package/src/tools/glob/handler.ts +17 -48
- package/src/tools/glob/tool.ts +3 -2
- package/src/tools/grep/tool.ts +3 -2
- package/src/tools/{read → read-file}/tool.ts +3 -2
- package/src/tools/task/handler.ts +2 -2
- package/src/tools/task/tool.ts +2 -9
- package/src/tools/task-create/handler.ts +5 -11
- package/src/tools/task-create/tool.ts +3 -2
- package/src/tools/task-get/handler.ts +5 -10
- package/src/tools/task-get/tool.ts +3 -2
- package/src/tools/task-list/handler.ts +5 -10
- package/src/tools/task-list/tool.ts +3 -2
- package/src/tools/task-update/handler.ts +5 -12
- package/src/tools/task-update/tool.ts +3 -2
- package/src/tools/{write → write-file}/tool.ts +5 -6
- package/src/workflow.ts +23 -19
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { dirname } from "path";
|
|
2
2
|
import { fileURLToPath } from "url";
|
|
3
3
|
import { describe, expect, it } from "vitest";
|
|
4
|
-
import {
|
|
4
|
+
import { createBashHandler } from "./handler";
|
|
5
5
|
import { OverlayFs } from "just-bash";
|
|
6
6
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -10,7 +10,7 @@ describe("bash with default options", () => {
|
|
|
10
10
|
const fs = new OverlayFs({ root: __dirname, mountPoint: "/home/user" });
|
|
11
11
|
|
|
12
12
|
it("executes echo and captures stdout", async () => {
|
|
13
|
-
const { data } = await
|
|
13
|
+
const { data } = await createBashHandler({fs})(
|
|
14
14
|
{ command: "echo 'hello world'" },
|
|
15
15
|
{}
|
|
16
16
|
);
|
|
@@ -20,17 +20,17 @@ describe("bash with default options", () => {
|
|
|
20
20
|
});
|
|
21
21
|
|
|
22
22
|
it("returns exit code 0 for successful commands", async () => {
|
|
23
|
-
const { data } = await
|
|
23
|
+
const { data } = await createBashHandler({fs})({ command: "true" }, {});
|
|
24
24
|
expect(data?.exitCode).toBe(0);
|
|
25
25
|
});
|
|
26
26
|
|
|
27
27
|
it("returns non-zero exit code for failed commands", async () => {
|
|
28
|
-
const { data } = await
|
|
28
|
+
const { data } = await createBashHandler({fs})({ command: "false" }, {});
|
|
29
29
|
expect(data?.exitCode).toBe(1);
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
it("captures stderr output", async () => {
|
|
33
|
-
const { data } = await
|
|
33
|
+
const { data } = await createBashHandler({fs})(
|
|
34
34
|
{ command: "echo 'error message' >&2" },
|
|
35
35
|
{}
|
|
36
36
|
);
|
|
@@ -39,7 +39,7 @@ describe("bash with default options", () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
it("supports piping between commands", async () => {
|
|
42
|
-
const { data } = await
|
|
42
|
+
const { data } = await createBashHandler({fs})(
|
|
43
43
|
{ command: "echo 'hello world' | tr 'a-z' 'A-Z'" },
|
|
44
44
|
{}
|
|
45
45
|
);
|
|
@@ -47,7 +47,7 @@ describe("bash with default options", () => {
|
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it("supports command chaining with &&", async () => {
|
|
50
|
-
const { data } = await
|
|
50
|
+
const { data } = await createBashHandler({fs})(
|
|
51
51
|
{ command: "echo 'first' && echo 'second'" },
|
|
52
52
|
{}
|
|
53
53
|
);
|
|
@@ -56,7 +56,7 @@ describe("bash with default options", () => {
|
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
it("handles multi-line output", async () => {
|
|
59
|
-
const { data } = await
|
|
59
|
+
const { data } = await createBashHandler({fs})(
|
|
60
60
|
{ command: "printf 'line1\\nline2\\nline3'" },
|
|
61
61
|
{}
|
|
62
62
|
);
|
|
@@ -67,7 +67,7 @@ describe("bash with default options", () => {
|
|
|
67
67
|
});
|
|
68
68
|
|
|
69
69
|
it("handles commands with arguments and flags", async () => {
|
|
70
|
-
const { data } = await
|
|
70
|
+
const { data } = await createBashHandler({fs})(
|
|
71
71
|
{ command: "echo -n 'no newline'" },
|
|
72
72
|
{}
|
|
73
73
|
);
|
|
@@ -75,7 +75,7 @@ describe("bash with default options", () => {
|
|
|
75
75
|
});
|
|
76
76
|
|
|
77
77
|
it("supports command substitution", async () => {
|
|
78
|
-
const { data } = await
|
|
78
|
+
const { data } = await createBashHandler({fs})(
|
|
79
79
|
{ command: "echo \"count: $(echo 'a b c' | wc -w | tr -d ' ')\"" },
|
|
80
80
|
{}
|
|
81
81
|
);
|
|
@@ -83,7 +83,7 @@ describe("bash with default options", () => {
|
|
|
83
83
|
});
|
|
84
84
|
|
|
85
85
|
it("returns toolResponse string with formatted output", async () => {
|
|
86
|
-
const { toolResponse } = await
|
|
86
|
+
const { toolResponse } = await createBashHandler({fs})(
|
|
87
87
|
{ command: "echo 'test'" },
|
|
88
88
|
{}
|
|
89
89
|
);
|
|
@@ -96,7 +96,7 @@ describe("bash with default options", () => {
|
|
|
96
96
|
describe("bash with overlay filesystem", () => {
|
|
97
97
|
it("sees files in the current directory", async () => {
|
|
98
98
|
const fs = new OverlayFs({ root: __dirname, mountPoint: "/home/user" });
|
|
99
|
-
const { data } = await
|
|
99
|
+
const { data } = await createBashHandler({fs})({ command: "ls" }, {});
|
|
100
100
|
expect(data?.stdout).toContain("bash.test.ts");
|
|
101
101
|
expect(data?.stdout).toContain("handler.ts");
|
|
102
102
|
expect(data?.stdout).toContain("tool.ts");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { ActivityToolHandler } from "../../
|
|
2
|
-
import type {
|
|
1
|
+
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { BashArgs } from "./tool";
|
|
3
3
|
import { Bash, type BashOptions } from "just-bash";
|
|
4
4
|
|
|
5
5
|
type BashExecOut = {
|
|
@@ -11,10 +11,10 @@ type BashExecOut = {
|
|
|
11
11
|
/** BashOptions with `fs` required */
|
|
12
12
|
type BashToolOptions = Required<Pick<BashOptions, "fs">> & Omit<BashOptions, "fs">;
|
|
13
13
|
|
|
14
|
-
export const
|
|
14
|
+
export const createBashHandler: (
|
|
15
15
|
bashOptions: BashToolOptions,
|
|
16
|
-
) => ActivityToolHandler<
|
|
17
|
-
(bashOptions: BashToolOptions) => async (args:
|
|
16
|
+
) => ActivityToolHandler<BashArgs, BashExecOut | null> =
|
|
17
|
+
(bashOptions: BashToolOptions) => async (args: BashArgs, _context) => {
|
|
18
18
|
const { command } = args;
|
|
19
19
|
|
|
20
20
|
const mergedOptions: BashOptions = {
|
package/src/tools/bash/tool.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const createBashToolDescription = ({
|
|
4
5
|
fileTree,
|
|
@@ -31,6 +32,6 @@ Use this tool to:
|
|
|
31
32
|
),
|
|
32
33
|
}),
|
|
33
34
|
strict: true,
|
|
34
|
-
};
|
|
35
|
+
} satisfies ToolDefinition;
|
|
35
36
|
|
|
36
|
-
export type
|
|
37
|
+
export type BashArgs = z.infer<typeof bashTool.schema>;
|
|
@@ -1,38 +1,16 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { FileEditArgs } from "./tool";
|
|
2
3
|
import type { IFileSystem } from "just-bash";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Result of an edit operation
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
interface EditResult {
|
|
8
9
|
path: string;
|
|
9
10
|
success: boolean;
|
|
10
11
|
replacements: number;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
/**
|
|
14
|
-
* Edit handler response
|
|
15
|
-
*/
|
|
16
|
-
export interface EditHandlerResponse {
|
|
17
|
-
toolResponse: string;
|
|
18
|
-
data: EditResult;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Options for edit handler
|
|
23
|
-
*/
|
|
24
|
-
export interface EditHandlerOptions {
|
|
25
|
-
/**
|
|
26
|
-
* Set of file paths that have been read in this session.
|
|
27
|
-
* Required for enforcing read-before-write policy.
|
|
28
|
-
*/
|
|
29
|
-
readFiles: Set<string>;
|
|
30
|
-
/**
|
|
31
|
-
* If true, skip the read-before-write check (not recommended)
|
|
32
|
-
*/
|
|
33
|
-
skipReadCheck?: boolean;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
14
|
/**
|
|
37
15
|
* Escape special regex characters in a string
|
|
38
16
|
*/
|
|
@@ -41,116 +19,93 @@ function escapeRegExp(str: string): string {
|
|
|
41
19
|
}
|
|
42
20
|
|
|
43
21
|
/**
|
|
44
|
-
*
|
|
22
|
+
* Creates an edit handler that edits files within the scoped file tree.
|
|
45
23
|
*
|
|
46
|
-
* @param
|
|
47
|
-
* @
|
|
24
|
+
* @param fs - File system implementation for I/O operations
|
|
25
|
+
* @returns An ActivityToolHandler for edit tool calls
|
|
48
26
|
*/
|
|
49
|
-
export
|
|
50
|
-
args: EditToolSchemaType,
|
|
27
|
+
export function createEditHandler(
|
|
51
28
|
fs: IFileSystem
|
|
52
|
-
):
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
// Validate old_string !== new_string
|
|
56
|
-
if (old_string === new_string) {
|
|
57
|
-
return {
|
|
58
|
-
toolResponse: `Error: old_string and new_string must be different.`,
|
|
59
|
-
data: {
|
|
60
|
-
path: file_path,
|
|
61
|
-
success: false,
|
|
62
|
-
replacements: 0,
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
}
|
|
29
|
+
): ActivityToolHandler<FileEditArgs, EditResult> {
|
|
30
|
+
return async (args) => {
|
|
31
|
+
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
66
32
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const exists = await fs.exists(file_path);
|
|
70
|
-
if (!exists) {
|
|
33
|
+
// Validate old_string !== new_string
|
|
34
|
+
if (old_string === new_string) {
|
|
71
35
|
return {
|
|
72
|
-
toolResponse: `Error:
|
|
73
|
-
data: {
|
|
74
|
-
path: file_path,
|
|
75
|
-
success: false,
|
|
76
|
-
replacements: 0,
|
|
77
|
-
},
|
|
36
|
+
toolResponse: `Error: old_string and new_string must be different.`,
|
|
37
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
78
38
|
};
|
|
79
39
|
}
|
|
80
40
|
|
|
81
|
-
|
|
82
|
-
|
|
41
|
+
try {
|
|
42
|
+
// Check if file exists
|
|
43
|
+
const exists = await fs.exists(file_path);
|
|
44
|
+
if (!exists) {
|
|
45
|
+
return {
|
|
46
|
+
toolResponse: `Error: File "${file_path}" does not exist.`,
|
|
47
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Read current content
|
|
52
|
+
const content = await fs.readFile(file_path);
|
|
53
|
+
|
|
54
|
+
// Check if old_string exists in the file
|
|
55
|
+
if (!content.includes(old_string)) {
|
|
56
|
+
return {
|
|
57
|
+
toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
|
|
58
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Count occurrences
|
|
63
|
+
const escapedOldString = escapeRegExp(old_string);
|
|
64
|
+
const globalRegex = new RegExp(escapedOldString, "g");
|
|
65
|
+
const occurrences = (content.match(globalRegex) || []).length;
|
|
66
|
+
|
|
67
|
+
// Check uniqueness if not replace_all
|
|
68
|
+
if (!replace_all && occurrences > 1) {
|
|
69
|
+
return {
|
|
70
|
+
toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
71
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Perform replacement
|
|
76
|
+
let newContent: string;
|
|
77
|
+
let replacements: number;
|
|
78
|
+
|
|
79
|
+
if (replace_all) {
|
|
80
|
+
newContent = content.split(old_string).join(new_string);
|
|
81
|
+
replacements = occurrences;
|
|
82
|
+
} else {
|
|
83
|
+
// Replace only the first occurrence
|
|
84
|
+
const index = content.indexOf(old_string);
|
|
85
|
+
newContent =
|
|
86
|
+
content.slice(0, index) +
|
|
87
|
+
new_string +
|
|
88
|
+
content.slice(index + old_string.length);
|
|
89
|
+
replacements = 1;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Write the modified content
|
|
93
|
+
await fs.writeFile(file_path, newContent);
|
|
94
|
+
|
|
95
|
+
const summary = replace_all
|
|
96
|
+
? `Replaced ${replacements} occurrence(s)`
|
|
97
|
+
: `Replaced 1 occurrence`;
|
|
83
98
|
|
|
84
|
-
// Check if old_string exists in the file
|
|
85
|
-
if (!content.includes(old_string)) {
|
|
86
99
|
return {
|
|
87
|
-
toolResponse:
|
|
88
|
-
data: {
|
|
89
|
-
path: file_path,
|
|
90
|
-
success: false,
|
|
91
|
-
replacements: 0,
|
|
92
|
-
},
|
|
100
|
+
toolResponse: `${summary} in ${file_path}`,
|
|
101
|
+
data: { path: file_path, success: true, replacements },
|
|
93
102
|
};
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Count occurrences
|
|
97
|
-
const escapedOldString = escapeRegExp(old_string);
|
|
98
|
-
const globalRegex = new RegExp(escapedOldString, "g");
|
|
99
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
100
|
-
|
|
101
|
-
// Check uniqueness if not replace_all
|
|
102
|
-
if (!replace_all && occurrences > 1) {
|
|
103
|
+
} catch (error) {
|
|
104
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
103
105
|
return {
|
|
104
|
-
toolResponse: `Error
|
|
105
|
-
data: {
|
|
106
|
-
path: file_path,
|
|
107
|
-
success: false,
|
|
108
|
-
replacements: 0,
|
|
109
|
-
},
|
|
106
|
+
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
107
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
110
108
|
};
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
// Perform replacement
|
|
114
|
-
let newContent: string;
|
|
115
|
-
let replacements: number;
|
|
116
|
-
|
|
117
|
-
if (replace_all) {
|
|
118
|
-
newContent = content.split(old_string).join(new_string);
|
|
119
|
-
replacements = occurrences;
|
|
120
|
-
} else {
|
|
121
|
-
// Replace only the first occurrence
|
|
122
|
-
const index = content.indexOf(old_string);
|
|
123
|
-
newContent =
|
|
124
|
-
content.slice(0, index) +
|
|
125
|
-
new_string +
|
|
126
|
-
content.slice(index + old_string.length);
|
|
127
|
-
replacements = 1;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Write the modified content
|
|
131
|
-
await fs.writeFile(file_path, newContent);
|
|
132
|
-
|
|
133
|
-
const summary = replace_all
|
|
134
|
-
? `Replaced ${replacements} occurrence(s)`
|
|
135
|
-
: `Replaced 1 occurrence`;
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
toolResponse: `${summary} in ${file_path}`,
|
|
139
|
-
data: {
|
|
140
|
-
path: file_path,
|
|
141
|
-
success: true,
|
|
142
|
-
replacements,
|
|
143
|
-
},
|
|
144
|
-
};
|
|
145
|
-
} catch (error) {
|
|
146
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
147
|
-
return {
|
|
148
|
-
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
149
|
-
data: {
|
|
150
|
-
path: file_path,
|
|
151
|
-
success: false,
|
|
152
|
-
replacements: 0,
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
}
|
|
110
|
+
};
|
|
156
111
|
}
|
package/src/tools/edit/tool.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const editTool = {
|
|
4
5
|
name: "FileEdit" as const,
|
|
@@ -34,6 +35,6 @@ IMPORTANT:
|
|
|
34
35
|
),
|
|
35
36
|
}),
|
|
36
37
|
strict: true,
|
|
37
|
-
};
|
|
38
|
+
} satisfies ToolDefinition;
|
|
38
39
|
|
|
39
|
-
export type
|
|
40
|
+
export type FileEditArgs = z.infer<typeof editTool.schema>;
|
|
@@ -1,62 +1,31 @@
|
|
|
1
|
+
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { GlobArgs } from "./tool";
|
|
1
3
|
import type { IFileSystem } from "just-bash";
|
|
2
4
|
import { Bash } from "just-bash";
|
|
3
|
-
import type { GlobToolSchemaType } from "./tool";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Result of a glob operation
|
|
7
8
|
*/
|
|
8
|
-
|
|
9
|
+
interface GlobResult {
|
|
9
10
|
files: string[];
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
|
-
*
|
|
14
|
-
*/
|
|
15
|
-
export interface GlobHandlerResponse {
|
|
16
|
-
toolResponse: string;
|
|
17
|
-
data: GlobResult;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Glob handler that searches within the scoped file tree.
|
|
14
|
+
* Creates a glob handler that searches within the scoped file tree.
|
|
22
15
|
*
|
|
23
|
-
* @param
|
|
24
|
-
* @
|
|
16
|
+
* @param fs - File system implementation for I/O operations
|
|
17
|
+
* @returns An ActivityToolHandler for glob tool calls
|
|
25
18
|
*/
|
|
26
|
-
export
|
|
27
|
-
_args: GlobToolSchemaType,
|
|
19
|
+
export function createGlobHandler(
|
|
28
20
|
fs: IFileSystem
|
|
29
|
-
):
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// const matches = await bash.exec(`glob ${root} -name "${pattern}"`);
|
|
40
|
-
|
|
41
|
-
// if (matches.length === 0) {
|
|
42
|
-
// return {
|
|
43
|
-
// content: `No files found matching pattern: ${pattern}`,
|
|
44
|
-
// result: { files: [] },
|
|
45
|
-
// };
|
|
46
|
-
// }
|
|
47
|
-
|
|
48
|
-
// const paths = matches.map((node) => node.path);
|
|
49
|
-
// const fileList = paths.map((p) => ` ${p}`).join("\n");
|
|
50
|
-
|
|
51
|
-
// return {
|
|
52
|
-
// content: `Found ${matches.length} file(s) matching "${pattern}":\n${fileList}`,
|
|
53
|
-
// result: { files: matches },
|
|
54
|
-
// };
|
|
55
|
-
// } catch (error) {
|
|
56
|
-
// const message = error instanceof Error ? error.message : "Unknown error";
|
|
57
|
-
// return {
|
|
58
|
-
// content: `Error searching for files: ${message}`,
|
|
59
|
-
// result: { files: [] },
|
|
60
|
-
// };
|
|
61
|
-
// }
|
|
21
|
+
): ActivityToolHandler<GlobArgs, GlobResult> {
|
|
22
|
+
return async (_args) => {
|
|
23
|
+
// const { pattern, root } = args;
|
|
24
|
+
const _bash = new Bash({ fs });
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
toolResponse: "Hello, world!",
|
|
28
|
+
data: { files: [] },
|
|
29
|
+
};
|
|
30
|
+
};
|
|
62
31
|
}
|
package/src/tools/glob/tool.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const globTool = {
|
|
4
5
|
name: "Glob" as const,
|
|
@@ -22,6 +23,6 @@ Examples:
|
|
|
22
23
|
.describe("Optional root directory to search from"),
|
|
23
24
|
}),
|
|
24
25
|
strict: true,
|
|
25
|
-
};
|
|
26
|
+
} satisfies ToolDefinition;
|
|
26
27
|
|
|
27
|
-
export type
|
|
28
|
+
export type GlobArgs = z.infer<typeof globTool.schema>;
|
package/src/tools/grep/tool.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const grepTool = {
|
|
4
5
|
name: "Grep" as const,
|
|
@@ -40,6 +41,6 @@ Examples:
|
|
|
40
41
|
.describe("Number of context lines to show around matches"),
|
|
41
42
|
}),
|
|
42
43
|
strict: true,
|
|
43
|
-
};
|
|
44
|
+
} satisfies ToolDefinition;
|
|
44
45
|
|
|
45
|
-
export type
|
|
46
|
+
export type GrepArgs = z.infer<typeof grepTool.schema>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const readTool = {
|
|
4
5
|
name: "FileRead" as const,
|
|
@@ -28,6 +29,6 @@ The tool returns the file content in an appropriate format:
|
|
|
28
29
|
.describe("Maximum number of lines to read (for text files)"),
|
|
29
30
|
}),
|
|
30
31
|
strict: true,
|
|
31
|
-
};
|
|
32
|
+
} satisfies ToolDefinition;
|
|
32
33
|
|
|
33
|
-
export type
|
|
34
|
+
export type FileReadArgs = z.infer<typeof readTool.schema>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { executeChild, workflowInfo, uuid4 } from "@temporalio/workflow";
|
|
2
2
|
import type { ToolHandlerResponse } from "../../lib/tool-router";
|
|
3
3
|
import type { SubagentConfig, SubagentInput } from "../../lib/types";
|
|
4
|
-
import type {
|
|
4
|
+
import type { TaskArgs } from "./tool";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Result from a task handler execution
|
|
@@ -34,7 +34,7 @@ export function createTaskHandler(subagents: SubagentConfig[]) {
|
|
|
34
34
|
workflowInfo();
|
|
35
35
|
|
|
36
36
|
return async (
|
|
37
|
-
args:
|
|
37
|
+
args: TaskArgs
|
|
38
38
|
): Promise<ToolHandlerResponse<TaskHandlerResult>> => {
|
|
39
39
|
const config = subagents.find((s) => s.name === args.subagent);
|
|
40
40
|
|
package/src/tools/task/tool.ts
CHANGED
|
@@ -80,16 +80,9 @@ export function createTaskTool<T extends SubagentConfig[]>(
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
/**
|
|
83
|
-
*
|
|
83
|
+
* Task tool args type (when subagent names are not known at compile time)
|
|
84
84
|
*/
|
|
85
|
-
export type
|
|
86
|
-
ReturnType<typeof createTaskTool<T>>["schema"]
|
|
87
|
-
>;
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Generic task tool schema type (when subagent names are not known at compile time)
|
|
91
|
-
*/
|
|
92
|
-
export type GenericTaskToolSchemaType = {
|
|
85
|
+
export type TaskArgs = {
|
|
93
86
|
subagent: string;
|
|
94
87
|
description: string;
|
|
95
88
|
prompt: string;
|
|
@@ -2,29 +2,23 @@ import type {
|
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
4
|
} from "../../lib/state-manager";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
|
-
import type {
|
|
7
|
+
import type { TaskCreateArgs } from "./tool";
|
|
8
8
|
import { uuid4 } from "@temporalio/workflow";
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Creates a TaskCreate handler that adds tasks to the workflow state.
|
|
12
12
|
*
|
|
13
13
|
* @param stateManager - State manager containing tasks state
|
|
14
|
-
* @
|
|
15
|
-
* @returns A tool handler function
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* const handler = createTaskCreateHandler(stateManager, uuid4);
|
|
14
|
+
* @returns A ToolHandler for TaskCreate tool calls
|
|
19
15
|
*/
|
|
20
16
|
export function createTaskCreateHandler<
|
|
21
17
|
TCustom extends JsonSerializable<TCustom>,
|
|
22
18
|
>(
|
|
23
19
|
stateManager: AgentStateManager<TCustom>
|
|
24
|
-
):
|
|
25
|
-
return (
|
|
26
|
-
args: TaskCreateToolSchemaType
|
|
27
|
-
): ToolHandlerResponse<WorkflowTask> => {
|
|
20
|
+
): ToolHandler<TaskCreateArgs, WorkflowTask> {
|
|
21
|
+
return (args) => {
|
|
28
22
|
const task: WorkflowTask = {
|
|
29
23
|
id: uuid4(),
|
|
30
24
|
subject: args.subject,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const taskCreateTool = {
|
|
4
5
|
name: "TaskCreate" as const,
|
|
@@ -61,6 +62,6 @@ export const taskCreateTool = {
|
|
|
61
62
|
.record(z.string(), z.string())
|
|
62
63
|
.describe("Arbitrary key-value pairs for tracking"),
|
|
63
64
|
}),
|
|
64
|
-
};
|
|
65
|
+
} satisfies ToolDefinition;
|
|
65
66
|
|
|
66
|
-
export type
|
|
67
|
+
export type TaskCreateArgs = z.infer<typeof taskCreateTool.schema>;
|
|
@@ -2,25 +2,20 @@ import type {
|
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
4
|
} from "../../lib/state-manager";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
|
-
import type {
|
|
7
|
+
import type { TaskGetArgs } from "./tool";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Creates a TaskGet handler that retrieves a task by ID.
|
|
11
11
|
*
|
|
12
12
|
* @param stateManager - State manager containing tasks state
|
|
13
|
-
* @returns A tool
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* const handler = createTaskGetHandler(stateManager);
|
|
13
|
+
* @returns A ToolHandler for TaskGet tool calls
|
|
17
14
|
*/
|
|
18
15
|
export function createTaskGetHandler<TCustom extends JsonSerializable<TCustom>>(
|
|
19
16
|
stateManager: AgentStateManager<TCustom>
|
|
20
|
-
):
|
|
21
|
-
return (
|
|
22
|
-
args: TaskGetToolSchemaType
|
|
23
|
-
): ToolHandlerResponse<WorkflowTask | null> => {
|
|
17
|
+
): ToolHandler<TaskGetArgs, WorkflowTask | null> {
|
|
18
|
+
return (args) => {
|
|
24
19
|
const task = stateManager.getTask(args.taskId) ?? null;
|
|
25
20
|
|
|
26
21
|
if (!task) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import z from "zod";
|
|
2
|
+
import type { ToolDefinition } from "../../lib/tool-router";
|
|
2
3
|
|
|
3
4
|
export const taskGetTool = {
|
|
4
5
|
name: "TaskGet" as const,
|
|
@@ -6,6 +7,6 @@ export const taskGetTool = {
|
|
|
6
7
|
schema: z.object({
|
|
7
8
|
taskId: z.string().describe("The ID of the task to get"),
|
|
8
9
|
}),
|
|
9
|
-
};
|
|
10
|
+
} satisfies ToolDefinition;
|
|
10
11
|
|
|
11
|
-
export type
|
|
12
|
+
export type TaskGetArgs = z.infer<typeof taskGetTool.schema>;
|