zeitlich 0.2.13 → 0.2.14
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 +49 -38
- package/dist/adapters/sandbox/daytona/index.cjs +205 -0
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -0
- package/dist/adapters/sandbox/daytona/index.d.cts +86 -0
- package/dist/adapters/sandbox/daytona/index.d.ts +86 -0
- package/dist/adapters/sandbox/daytona/index.js +202 -0
- package/dist/adapters/sandbox/daytona/index.js.map +1 -0
- package/dist/adapters/sandbox/inmemory/index.cjs +174 -0
- package/dist/adapters/sandbox/inmemory/index.cjs.map +1 -0
- package/dist/adapters/sandbox/inmemory/index.d.cts +28 -0
- package/dist/adapters/sandbox/inmemory/index.d.ts +28 -0
- package/dist/adapters/sandbox/inmemory/index.js +172 -0
- package/dist/adapters/sandbox/inmemory/index.js.map +1 -0
- package/dist/adapters/sandbox/virtual/index.cjs +405 -0
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -0
- package/dist/adapters/sandbox/virtual/index.d.cts +85 -0
- package/dist/adapters/sandbox/virtual/index.d.ts +85 -0
- package/dist/adapters/sandbox/virtual/index.js +400 -0
- package/dist/adapters/sandbox/virtual/index.js.map +1 -0
- package/dist/adapters/thread/google-genai/index.cjs +284 -0
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -0
- package/dist/adapters/thread/google-genai/index.d.cts +145 -0
- package/dist/adapters/thread/google-genai/index.d.ts +145 -0
- package/dist/adapters/thread/google-genai/index.js +278 -0
- package/dist/adapters/thread/google-genai/index.js.map +1 -0
- package/dist/adapters/{langchain → thread/langchain}/index.cjs +7 -9
- package/dist/adapters/thread/langchain/index.cjs.map +1 -0
- package/dist/adapters/{langchain → thread/langchain}/index.d.cts +17 -21
- package/dist/adapters/{langchain → thread/langchain}/index.d.ts +17 -21
- package/dist/adapters/{langchain → thread/langchain}/index.js +7 -9
- package/dist/adapters/thread/langchain/index.js.map +1 -0
- package/dist/index.cjs +816 -545
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +235 -74
- package/dist/index.d.ts +235 -74
- package/dist/index.js +804 -540
- package/dist/index.js.map +1 -1
- package/dist/types-B4C9txdq.d.ts +389 -0
- package/dist/{thread-manager-qc0g5Rvd.d.cts → types-B9ljZewB.d.cts} +1 -6
- package/dist/{thread-manager-qc0g5Rvd.d.ts → types-B9ljZewB.d.ts} +1 -6
- package/dist/types-BMXzv7TN.d.cts +476 -0
- package/dist/types-BMXzv7TN.d.ts +476 -0
- package/dist/types-BVP87m_W.d.cts +121 -0
- package/dist/types-CDubRtad.d.cts +115 -0
- package/dist/types-CDubRtad.d.ts +115 -0
- package/dist/types-CwwgQ_9H.d.ts +121 -0
- package/dist/types-GpMU4b0w.d.cts +389 -0
- package/dist/workflow.cjs +444 -318
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +271 -222
- package/dist/workflow.d.ts +271 -222
- package/dist/workflow.js +440 -316
- package/dist/workflow.js.map +1 -1
- package/package.json +59 -6
- package/src/adapters/sandbox/daytona/filesystem.ts +136 -0
- package/src/adapters/sandbox/daytona/index.ts +149 -0
- package/src/adapters/sandbox/daytona/types.ts +34 -0
- package/src/adapters/sandbox/inmemory/index.ts +213 -0
- package/src/adapters/sandbox/virtual/filesystem.ts +345 -0
- package/src/adapters/sandbox/virtual/index.ts +88 -0
- package/src/adapters/sandbox/virtual/mutations.ts +38 -0
- package/src/adapters/sandbox/virtual/provider.ts +101 -0
- package/src/adapters/sandbox/virtual/tree.ts +82 -0
- package/src/adapters/sandbox/virtual/types.ts +127 -0
- package/src/adapters/sandbox/virtual/virtual-sandbox.test.ts +523 -0
- package/src/adapters/sandbox/virtual/with-virtual-sandbox.ts +91 -0
- package/src/adapters/thread/google-genai/activities.ts +121 -0
- package/src/adapters/thread/google-genai/index.ts +41 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +154 -0
- package/src/adapters/thread/google-genai/thread-manager.ts +169 -0
- package/src/adapters/{langchain → thread/langchain}/activities.ts +11 -15
- package/src/adapters/{langchain → thread/langchain}/index.ts +1 -1
- package/src/adapters/{langchain → thread/langchain}/model-invoker.ts +15 -18
- package/src/adapters/{langchain → thread/langchain}/thread-manager.ts +1 -1
- package/src/index.ts +32 -24
- package/src/lib/activity.ts +87 -0
- package/src/lib/hooks/index.ts +11 -0
- package/src/lib/hooks/types.ts +98 -0
- package/src/lib/model/helpers.ts +6 -0
- package/src/lib/model/index.ts +13 -0
- package/src/lib/{model-invoker.ts → model/types.ts} +18 -1
- package/src/lib/sandbox/index.ts +19 -0
- package/src/lib/sandbox/manager.ts +76 -0
- package/src/lib/sandbox/sandbox.test.ts +158 -0
- package/src/lib/{fs.ts → sandbox/tree.ts} +6 -6
- package/src/lib/sandbox/types.ts +164 -0
- package/src/lib/session/index.ts +11 -0
- package/src/lib/{session.ts → session/session.ts} +76 -48
- package/src/lib/session/types.ts +93 -0
- package/src/lib/skills/fs-provider.ts +16 -15
- package/src/lib/skills/handler.ts +31 -0
- package/src/lib/skills/index.ts +5 -1
- package/src/lib/skills/register.ts +20 -0
- package/src/lib/skills/tool.ts +47 -0
- package/src/lib/state/index.ts +9 -0
- package/src/lib/{state-manager.ts → state/manager.ts} +10 -147
- package/src/lib/state/types.ts +134 -0
- package/src/lib/subagent/define.ts +71 -0
- package/src/lib/subagent/handler.ts +99 -0
- package/src/lib/subagent/index.ts +13 -0
- package/src/lib/subagent/register.ts +53 -0
- package/src/lib/subagent/tool.ts +80 -0
- package/src/lib/subagent/types.ts +92 -0
- package/src/lib/thread/index.ts +7 -0
- package/src/lib/{thread-manager.ts → thread/manager.ts} +1 -33
- package/src/lib/thread/types.ts +33 -0
- package/src/lib/tool-router/auto-append.ts +55 -0
- package/src/lib/tool-router/index.ts +41 -0
- package/src/lib/tool-router/router.ts +462 -0
- package/src/lib/tool-router/types.ts +478 -0
- package/src/lib/tool-router/with-sandbox.ts +70 -0
- package/src/lib/types.ts +5 -382
- package/src/tools/bash/bash.test.ts +53 -55
- package/src/tools/bash/handler.ts +23 -51
- package/src/tools/edit/handler.ts +67 -81
- package/src/tools/glob/handler.ts +60 -17
- package/src/tools/read-file/handler.ts +67 -0
- package/src/tools/read-skill/handler.ts +1 -31
- package/src/tools/read-skill/tool.ts +5 -47
- package/src/tools/subagent/handler.ts +1 -100
- package/src/tools/subagent/tool.ts +5 -93
- package/src/tools/task-create/handler.ts +1 -1
- package/src/tools/task-get/handler.ts +1 -1
- package/src/tools/task-list/handler.ts +1 -1
- package/src/tools/task-update/handler.ts +1 -1
- package/src/tools/write-file/handler.ts +47 -0
- package/src/workflow.ts +88 -47
- package/tsup.config.ts +8 -1
- package/dist/adapters/langchain/index.cjs.map +0 -1
- package/dist/adapters/langchain/index.js.map +0 -1
- package/dist/model-invoker-y_zlyMqu.d.cts +0 -892
- package/dist/model-invoker-y_zlyMqu.d.ts +0 -892
- package/src/lib/tool-router.ts +0 -977
- package/src/lib/workflow-helpers.ts +0 -50
- /package/src/lib/{thread-id.ts → thread/id.ts} +0 -0
|
@@ -1,111 +1,97 @@
|
|
|
1
1
|
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { SandboxContext } from "../../lib/tool-router/with-sandbox";
|
|
2
3
|
import type { FileEditArgs } from "./tool";
|
|
3
|
-
import type { IFileSystem } from "just-bash";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Result of an edit operation
|
|
7
|
-
*/
|
|
8
5
|
interface EditResult {
|
|
9
6
|
path: string;
|
|
10
7
|
success: boolean;
|
|
11
8
|
replacements: number;
|
|
12
9
|
}
|
|
13
10
|
|
|
14
|
-
/**
|
|
15
|
-
* Escape special regex characters in a string
|
|
16
|
-
*/
|
|
17
11
|
function escapeRegExp(str: string): string {
|
|
18
12
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
19
13
|
}
|
|
20
14
|
|
|
21
15
|
/**
|
|
22
|
-
*
|
|
16
|
+
* Edit tool handler — performs string replacements in sandbox files.
|
|
23
17
|
*
|
|
24
|
-
* @
|
|
25
|
-
*
|
|
18
|
+
* Wrap with {@link withSandbox} at activity registration time to inject the
|
|
19
|
+
* sandbox automatically.
|
|
26
20
|
*/
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
export const editHandler: ActivityToolHandler<
|
|
22
|
+
FileEditArgs,
|
|
23
|
+
EditResult,
|
|
24
|
+
SandboxContext
|
|
25
|
+
> = async (args, { sandbox }) => {
|
|
26
|
+
const { fs } = sandbox;
|
|
27
|
+
const { file_path, old_string, new_string, replace_all = false } = args;
|
|
28
|
+
|
|
29
|
+
if (old_string === new_string) {
|
|
30
|
+
return {
|
|
31
|
+
toolResponse: `Error: old_string and new_string must be different.`,
|
|
32
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
33
|
+
};
|
|
34
|
+
}
|
|
32
35
|
|
|
33
|
-
|
|
34
|
-
|
|
36
|
+
try {
|
|
37
|
+
const exists = await fs.exists(file_path);
|
|
38
|
+
if (!exists) {
|
|
35
39
|
return {
|
|
36
|
-
toolResponse: `Error:
|
|
40
|
+
toolResponse: `Error: File "${file_path}" does not exist.`,
|
|
37
41
|
data: { path: file_path, success: false, replacements: 0 },
|
|
38
42
|
};
|
|
39
43
|
}
|
|
40
44
|
|
|
41
|
-
|
|
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);
|
|
45
|
+
const content = await fs.readFile(file_path);
|
|
53
46
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
47
|
+
if (!content.includes(old_string)) {
|
|
48
|
+
return {
|
|
49
|
+
toolResponse: `Error: Could not find the specified text in "${file_path}". Make sure old_string matches exactly (whitespace-sensitive).`,
|
|
50
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
61
53
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const occurrences = (content.match(globalRegex) || []).length;
|
|
54
|
+
const escapedOldString = escapeRegExp(old_string);
|
|
55
|
+
const globalRegex = new RegExp(escapedOldString, "g");
|
|
56
|
+
const occurrences = (content.match(globalRegex) || []).length;
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
58
|
+
if (!replace_all && occurrences > 1) {
|
|
59
|
+
return {
|
|
60
|
+
toolResponse: `Error: old_string appears ${occurrences} times in "${file_path}". Either provide more context to make it unique, or use replace_all: true.`,
|
|
61
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
62
|
+
};
|
|
63
|
+
}
|
|
74
64
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
let replacements: number;
|
|
65
|
+
let newContent: string;
|
|
66
|
+
let replacements: number;
|
|
78
67
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
68
|
+
if (replace_all) {
|
|
69
|
+
newContent = content.split(old_string).join(new_string);
|
|
70
|
+
replacements = occurrences;
|
|
71
|
+
} else {
|
|
72
|
+
const index = content.indexOf(old_string);
|
|
73
|
+
newContent =
|
|
74
|
+
content.slice(0, index) +
|
|
75
|
+
new_string +
|
|
76
|
+
content.slice(index + old_string.length);
|
|
77
|
+
replacements = 1;
|
|
78
|
+
}
|
|
91
79
|
|
|
92
|
-
|
|
93
|
-
await fs.writeFile(file_path, newContent);
|
|
80
|
+
await fs.writeFile(file_path, newContent);
|
|
94
81
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
82
|
+
const summary = replace_all
|
|
83
|
+
? `Replaced ${replacements} occurrence(s)`
|
|
84
|
+
: `Replaced 1 occurrence`;
|
|
98
85
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
86
|
+
return {
|
|
87
|
+
toolResponse: `${summary} in ${file_path}`,
|
|
88
|
+
data: { path: file_path, success: true, replacements },
|
|
89
|
+
};
|
|
90
|
+
} catch (error) {
|
|
91
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
92
|
+
return {
|
|
93
|
+
toolResponse: `Error editing file "${file_path}": ${message}`,
|
|
94
|
+
data: { path: file_path, success: false, replacements: 0 },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
};
|
|
@@ -1,31 +1,74 @@
|
|
|
1
1
|
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { SandboxContext } from "../../lib/tool-router/with-sandbox";
|
|
2
3
|
import type { GlobArgs } from "./tool";
|
|
3
|
-
import type {
|
|
4
|
-
import { Bash } from "just-bash";
|
|
4
|
+
import type { Sandbox } from "../../lib/sandbox/types";
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Result of a glob operation
|
|
8
|
-
*/
|
|
9
6
|
interface GlobResult {
|
|
10
7
|
files: string[];
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
/**
|
|
14
|
-
*
|
|
11
|
+
* Simple glob-style matcher (supports `*` and `**`).
|
|
12
|
+
*/
|
|
13
|
+
function matchGlob(pattern: string, path: string): boolean {
|
|
14
|
+
const regex = pattern
|
|
15
|
+
.replace(/[.+^${}()|[\]\\]/g, "\\$&")
|
|
16
|
+
.replace(/\*\*/g, "{{GLOBSTAR}}")
|
|
17
|
+
.replace(/\*/g, "[^/]*")
|
|
18
|
+
.replace(/\{\{GLOBSTAR\}\}/g, ".*");
|
|
19
|
+
return new RegExp(`^${regex}$`).test(path);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function walk(
|
|
23
|
+
fs: Sandbox["fs"],
|
|
24
|
+
dir: string,
|
|
25
|
+
): Promise<string[]> {
|
|
26
|
+
const results: string[] = [];
|
|
27
|
+
const entries = await fs.readdirWithFileTypes(dir);
|
|
28
|
+
for (const entry of entries) {
|
|
29
|
+
const full = dir === "/" ? `/${entry.name}` : `${dir}/${entry.name}`;
|
|
30
|
+
if (entry.isDirectory) {
|
|
31
|
+
results.push(...(await walk(fs, full)));
|
|
32
|
+
} else {
|
|
33
|
+
results.push(full);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return results;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Glob tool handler — searches files within a {@link Sandbox} filesystem.
|
|
15
41
|
*
|
|
16
|
-
* @
|
|
17
|
-
*
|
|
42
|
+
* Wrap with {@link withSandbox} at activity registration time to inject the
|
|
43
|
+
* sandbox automatically.
|
|
18
44
|
*/
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
export const globHandler: ActivityToolHandler<
|
|
46
|
+
GlobArgs,
|
|
47
|
+
GlobResult,
|
|
48
|
+
SandboxContext
|
|
49
|
+
> = async (args, { sandbox }) => {
|
|
50
|
+
const { fs } = sandbox;
|
|
51
|
+
const { pattern, root = "/" } = args;
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const allFiles = await walk(fs, root);
|
|
55
|
+
const relativeTo = root.endsWith("/") ? root : `${root}/`;
|
|
56
|
+
const matched = allFiles
|
|
57
|
+
.map((f) => (f.startsWith(relativeTo) ? f.slice(relativeTo.length) : f))
|
|
58
|
+
.filter((f) => matchGlob(pattern, f));
|
|
25
59
|
|
|
26
60
|
return {
|
|
27
|
-
toolResponse:
|
|
61
|
+
toolResponse:
|
|
62
|
+
matched.length > 0
|
|
63
|
+
? `Found ${matched.length} file(s):\n${matched.join("\n")}`
|
|
64
|
+
: `No files matched pattern "${pattern}"`,
|
|
65
|
+
data: { files: matched },
|
|
66
|
+
};
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
69
|
+
return {
|
|
70
|
+
toolResponse: `Error running glob: ${message}`,
|
|
28
71
|
data: { files: [] },
|
|
29
72
|
};
|
|
30
|
-
}
|
|
31
|
-
}
|
|
73
|
+
}
|
|
74
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
2
|
+
import type { SandboxContext } from "../../lib/tool-router/with-sandbox";
|
|
3
|
+
import type { FileReadArgs } from "./tool";
|
|
4
|
+
|
|
5
|
+
interface ReadFileResult {
|
|
6
|
+
path: string;
|
|
7
|
+
content: string;
|
|
8
|
+
totalLines?: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Read-file tool handler — reads files from a {@link Sandbox} filesystem.
|
|
13
|
+
*
|
|
14
|
+
* Wrap with {@link withSandbox} at activity registration time to inject the
|
|
15
|
+
* sandbox automatically.
|
|
16
|
+
*/
|
|
17
|
+
export const readFileHandler: ActivityToolHandler<
|
|
18
|
+
FileReadArgs,
|
|
19
|
+
ReadFileResult | null,
|
|
20
|
+
SandboxContext
|
|
21
|
+
> = async (args, { sandbox }) => {
|
|
22
|
+
const { fs } = sandbox;
|
|
23
|
+
const { path, offset, limit } = args;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const exists = await fs.exists(path);
|
|
27
|
+
if (!exists) {
|
|
28
|
+
return {
|
|
29
|
+
toolResponse: `Error: File "${path}" does not exist.`,
|
|
30
|
+
data: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const raw = await fs.readFile(path);
|
|
35
|
+
const lines = raw.split("\n");
|
|
36
|
+
const totalLines = lines.length;
|
|
37
|
+
|
|
38
|
+
if (offset !== undefined || limit !== undefined) {
|
|
39
|
+
const start = Math.max(0, (offset ?? 1) - 1);
|
|
40
|
+
const end = limit !== undefined ? start + limit : lines.length;
|
|
41
|
+
const slice = lines.slice(start, end);
|
|
42
|
+
const numbered = slice
|
|
43
|
+
.map((line, i) => `${String(start + i + 1).padStart(6)}|${line}`)
|
|
44
|
+
.join("\n");
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
toolResponse: numbered,
|
|
48
|
+
data: { path, content: numbered, totalLines },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const numbered = lines
|
|
53
|
+
.map((line, i) => `${String(i + 1).padStart(6)}|${line}`)
|
|
54
|
+
.join("\n");
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
toolResponse: numbered,
|
|
58
|
+
data: { path, content: numbered, totalLines },
|
|
59
|
+
};
|
|
60
|
+
} catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
62
|
+
return {
|
|
63
|
+
toolResponse: `Error reading file "${path}": ${message}`,
|
|
64
|
+
data: null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
};
|
|
@@ -1,31 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import type { ToolHandlerResponse } from "../../lib/tool-router";
|
|
3
|
-
import type { ReadSkillArgs } from "./tool";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Creates a ReadSkill handler that looks up skills from an in-memory array.
|
|
7
|
-
* Runs directly in the workflow (like task tools) — no activity needed.
|
|
8
|
-
*/
|
|
9
|
-
export function createReadSkillHandler(
|
|
10
|
-
skills: Skill[]
|
|
11
|
-
): (args: ReadSkillArgs) => ToolHandlerResponse<null> {
|
|
12
|
-
const skillMap = new Map(skills.map((s) => [s.name, s]));
|
|
13
|
-
|
|
14
|
-
return (args: ReadSkillArgs): ToolHandlerResponse<null> => {
|
|
15
|
-
const skill = skillMap.get(args.skill_name);
|
|
16
|
-
|
|
17
|
-
if (!skill) {
|
|
18
|
-
return {
|
|
19
|
-
toolResponse: JSON.stringify({
|
|
20
|
-
error: `Skill "${args.skill_name}" not found`,
|
|
21
|
-
}),
|
|
22
|
-
data: null,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
toolResponse: skill.instructions,
|
|
28
|
-
data: null,
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
}
|
|
1
|
+
export { createReadSkillHandler } from "../../lib/skills/handler";
|
|
@@ -1,47 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
function buildReadSkillDescription(skills: Skill[]): string {
|
|
7
|
-
const skillList = skills
|
|
8
|
-
.map((s) => `- **${s.name}**: ${s.description}`)
|
|
9
|
-
.join("\n");
|
|
10
|
-
|
|
11
|
-
return `Load the full instructions for a skill. Read the skill before following its instructions.
|
|
12
|
-
|
|
13
|
-
# Available skills:
|
|
14
|
-
${skillList}
|
|
15
|
-
`;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Creates a ReadSkill tool configured with the available skills.
|
|
20
|
-
* The tool description embeds skill metadata so the agent discovers
|
|
21
|
-
* skills purely through the tool definition.
|
|
22
|
-
*/
|
|
23
|
-
export function createReadSkillTool(skills: Skill[]): {
|
|
24
|
-
name: string;
|
|
25
|
-
description: string;
|
|
26
|
-
schema: z.ZodObject<{
|
|
27
|
-
skill_name: z.ZodEnum<Record<string, string>>;
|
|
28
|
-
}>;
|
|
29
|
-
} {
|
|
30
|
-
if (skills.length === 0) {
|
|
31
|
-
throw new Error("createReadSkillTool requires at least one skill");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const names = skills.map((s) => s.name);
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
name: READ_SKILL_TOOL_NAME,
|
|
38
|
-
description: buildReadSkillDescription(skills),
|
|
39
|
-
schema: z.object({
|
|
40
|
-
skill_name: z.enum(names).describe("The name of the skill to load"),
|
|
41
|
-
}),
|
|
42
|
-
} as const;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type ReadSkillArgs = {
|
|
46
|
-
skill_name: string;
|
|
47
|
-
};
|
|
1
|
+
export {
|
|
2
|
+
createReadSkillTool,
|
|
3
|
+
READ_SKILL_TOOL_NAME,
|
|
4
|
+
type ReadSkillArgs,
|
|
5
|
+
} from "../../lib/skills/tool";
|
|
@@ -1,100 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import { getShortId } from "../../lib/thread-id";
|
|
3
|
-
import type { ToolHandlerResponse } from "../../lib/tool-router";
|
|
4
|
-
import type { ToolMessageContent } from "../../lib/types";
|
|
5
|
-
import type {
|
|
6
|
-
InferSubagentResult,
|
|
7
|
-
SubagentConfig,
|
|
8
|
-
SubagentInput,
|
|
9
|
-
} from "../../lib/types";
|
|
10
|
-
import type { SubagentArgs } from "./tool";
|
|
11
|
-
import type { z } from "zod";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Creates a Subagent tool handler that spawns child workflows for configured subagents.
|
|
15
|
-
*
|
|
16
|
-
* @param subagents - Array of subagent configurations
|
|
17
|
-
* @returns A tool handler function that can be used with the tool router
|
|
18
|
-
*
|
|
19
|
-
* @example
|
|
20
|
-
* const subagentHandler = subagentHandler([
|
|
21
|
-
* {
|
|
22
|
-
* name: "researcher",
|
|
23
|
-
* description: "Researches topics",
|
|
24
|
-
* workflow: "researcherWorkflow",
|
|
25
|
-
* resultSchema: z.object({ findings: z.string() }),
|
|
26
|
-
* },
|
|
27
|
-
* ]);
|
|
28
|
-
*/
|
|
29
|
-
export function createSubagentHandler<
|
|
30
|
-
const T extends readonly SubagentConfig[],
|
|
31
|
-
>(subagents: [...T]) {
|
|
32
|
-
const { taskQueue: parentTaskQueue } = workflowInfo();
|
|
33
|
-
|
|
34
|
-
return async (
|
|
35
|
-
args: SubagentArgs
|
|
36
|
-
): Promise<ToolHandlerResponse<InferSubagentResult<T[number]> | null>> => {
|
|
37
|
-
const config = subagents.find((s) => s.agentName === args.subagent);
|
|
38
|
-
|
|
39
|
-
if (!config) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
`Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
const childWorkflowId = `${args.subagent}-${getShortId()}`;
|
|
46
|
-
|
|
47
|
-
const input: SubagentInput = {
|
|
48
|
-
prompt: args.prompt,
|
|
49
|
-
...(config.context && { context: config.context }),
|
|
50
|
-
...(args.threadId &&
|
|
51
|
-
config.allowThreadContinuation && { threadId: args.threadId }),
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
const childOpts = {
|
|
55
|
-
workflowId: childWorkflowId,
|
|
56
|
-
args: [input] as const,
|
|
57
|
-
taskQueue: config.taskQueue ?? parentTaskQueue,
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const { toolResponse, data, usage, threadId: childThreadId } =
|
|
61
|
-
typeof config.workflow === "string"
|
|
62
|
-
? await executeChild(config.workflow, childOpts)
|
|
63
|
-
: await executeChild(config.workflow, childOpts);
|
|
64
|
-
|
|
65
|
-
if (!toolResponse) {
|
|
66
|
-
return {
|
|
67
|
-
toolResponse: "Subagent workflow returned no response",
|
|
68
|
-
data: null,
|
|
69
|
-
...(usage && { usage }),
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Validate result if schema provided, otherwise pass through as-is
|
|
74
|
-
const validated = (
|
|
75
|
-
config.resultSchema ? config.resultSchema.safeParse(data) : null
|
|
76
|
-
) as z.ZodSafeParseResult<InferSubagentResult<T[number]>> | null;
|
|
77
|
-
|
|
78
|
-
if (validated && !validated.success) {
|
|
79
|
-
return {
|
|
80
|
-
toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
|
|
81
|
-
data: null,
|
|
82
|
-
...(usage && { usage }),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
let finalToolResponse: ToolMessageContent = toolResponse;
|
|
87
|
-
if (config.allowThreadContinuation && childThreadId) {
|
|
88
|
-
finalToolResponse =
|
|
89
|
-
typeof toolResponse === "string"
|
|
90
|
-
? `${toolResponse}\n\n[Thread ID: ${childThreadId}]`
|
|
91
|
-
: toolResponse;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
toolResponse: finalToolResponse,
|
|
96
|
-
data: validated ? validated.data : data,
|
|
97
|
-
...(usage && { usage }),
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
}
|
|
1
|
+
export { createSubagentHandler } from "../../lib/subagent/handler";
|
|
@@ -1,93 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Builds the tool description with available subagent information
|
|
8
|
-
*/
|
|
9
|
-
function buildSubagentDescription(subagents: SubagentConfig[]): string {
|
|
10
|
-
const subagentList = subagents
|
|
11
|
-
.map((s) => {
|
|
12
|
-
const continuation = s.allowThreadContinuation
|
|
13
|
-
? "\n*(Supports thread continuation — pass a threadId to resume a previous conversation)*"
|
|
14
|
-
: "";
|
|
15
|
-
return `## ${s.agentName}\n${s.description}${continuation}`;
|
|
16
|
-
})
|
|
17
|
-
.join("\n\n");
|
|
18
|
-
|
|
19
|
-
return `The ${SUBAGENT_TOOL_NAME} tool launches specialized agents (subagents) that autonomously handle complex work. Each agent type has specific capabilities and tools available to it.
|
|
20
|
-
|
|
21
|
-
# Available subagents:
|
|
22
|
-
${subagentList}
|
|
23
|
-
`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Creates a Subagent tool configured with the available subagents.
|
|
28
|
-
*
|
|
29
|
-
* @param subagents - Array of subagent configurations (must have at least one)
|
|
30
|
-
* @returns A tool definition with dynamic schema based on available subagents
|
|
31
|
-
*
|
|
32
|
-
* @example
|
|
33
|
-
* const subagentTool = createSubagentTool([
|
|
34
|
-
* {
|
|
35
|
-
* agentName: "researcher",
|
|
36
|
-
* description: "Researches topics and gathers information",
|
|
37
|
-
* workflow: "researcherWorkflow",
|
|
38
|
-
* resultSchema: z.object({ findings: z.string() }),
|
|
39
|
-
* },
|
|
40
|
-
* ]);
|
|
41
|
-
*/
|
|
42
|
-
export function createSubagentTool<T extends SubagentConfig[]>(
|
|
43
|
-
subagents: T
|
|
44
|
-
): {
|
|
45
|
-
readonly name: typeof SUBAGENT_TOOL_NAME;
|
|
46
|
-
readonly description: string;
|
|
47
|
-
readonly schema: z.ZodObject<z.ZodRawShape>;
|
|
48
|
-
} {
|
|
49
|
-
if (subagents.length === 0) {
|
|
50
|
-
throw new Error("createTaskTool requires at least one subagent");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const names = subagents.map((s) => s.agentName);
|
|
54
|
-
const hasThreadContinuation = subagents.some(
|
|
55
|
-
(s) => s.allowThreadContinuation
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
const baseFields = {
|
|
59
|
-
subagent: z.enum(names).describe("The type of subagent to launch"),
|
|
60
|
-
description: z
|
|
61
|
-
.string()
|
|
62
|
-
.describe("A short (3-5 word) description of the task"),
|
|
63
|
-
prompt: z.string().describe("The task for the agent to perform"),
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const schema = hasThreadContinuation
|
|
67
|
-
? z.object({
|
|
68
|
-
...baseFields,
|
|
69
|
-
threadId: z
|
|
70
|
-
.string()
|
|
71
|
-
.nullable()
|
|
72
|
-
.describe(
|
|
73
|
-
"Thread ID to continue an existing conversation, or null to start a new one"
|
|
74
|
-
),
|
|
75
|
-
})
|
|
76
|
-
: z.object(baseFields);
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
name: SUBAGENT_TOOL_NAME,
|
|
80
|
-
description: buildSubagentDescription(subagents),
|
|
81
|
-
schema,
|
|
82
|
-
} as const;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Subagent tool args type (when subagent names are not known at compile time)
|
|
87
|
-
*/
|
|
88
|
-
export type SubagentArgs = {
|
|
89
|
-
subagent: string;
|
|
90
|
-
description: string;
|
|
91
|
-
prompt: string;
|
|
92
|
-
threadId?: string;
|
|
93
|
-
};
|
|
1
|
+
export {
|
|
2
|
+
createSubagentTool,
|
|
3
|
+
SUBAGENT_TOOL_NAME,
|
|
4
|
+
type SubagentArgs,
|
|
5
|
+
} from "../../lib/subagent/tool";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
|
-
} from "../../lib/state
|
|
4
|
+
} from "../../lib/state";
|
|
5
5
|
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
7
|
import type { TaskCreateArgs } from "./tool";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
|
-
} from "../../lib/state
|
|
4
|
+
} from "../../lib/state";
|
|
5
5
|
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
7
|
import type { TaskGetArgs } from "./tool";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
|
-
} from "../../lib/state
|
|
4
|
+
} from "../../lib/state";
|
|
5
5
|
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
7
|
import type { TaskListArgs } from "./tool";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentStateManager,
|
|
3
3
|
JsonSerializable,
|
|
4
|
-
} from "../../lib/state
|
|
4
|
+
} from "../../lib/state";
|
|
5
5
|
import type { ToolHandler } from "../../lib/tool-router";
|
|
6
6
|
import type { WorkflowTask } from "../../lib/types";
|
|
7
7
|
import type { TaskUpdateArgs } from "./tool";
|