zeitlich 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +346 -121
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +319 -98
- package/dist/index.js.map +1 -1
- package/dist/{workflow-C2ShwjC7.d.cts → workflow-BhjsEQc1.d.cts} +115 -21
- package/dist/{workflow-C2ShwjC7.d.ts → workflow-BhjsEQc1.d.ts} +115 -21
- package/dist/workflow.cjs +247 -111
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -1
- package/dist/workflow.d.ts +2 -1
- package/dist/workflow.js +220 -88
- package/dist/workflow.js.map +1 -1
- package/package.json +15 -15
- package/src/index.ts +3 -0
- package/src/lib/model-invoker.ts +2 -2
- package/src/lib/session.ts +14 -8
- package/src/lib/skills/fs-provider.ts +84 -0
- package/src/lib/skills/index.ts +3 -0
- package/src/lib/skills/parse.ts +117 -0
- package/src/lib/skills/types.ts +41 -0
- package/src/lib/state-manager.ts +42 -26
- package/src/lib/thread-manager.ts +61 -2
- package/src/lib/tool-router.ts +28 -5
- package/src/lib/types.ts +23 -6
- package/src/tools/read-skill/handler.ts +31 -0
- package/src/tools/read-skill/tool.ts +47 -0
- package/src/tools/subagent/handler.ts +21 -4
- package/src/tools/subagent/tool.ts +5 -20
- package/src/tools/task-create/tool.ts +1 -1
- package/src/workflow.ts +14 -5
package/dist/index.js
CHANGED
|
@@ -1,35 +1,23 @@
|
|
|
1
|
-
import { setHandler, defineUpdate, condition, proxyActivities, defineQuery, uuid4, workflowInfo, executeChild } from '@temporalio/workflow';
|
|
2
|
-
import
|
|
1
|
+
import { setHandler, defineUpdate, ApplicationFailure, condition, proxyActivities, defineQuery, uuid4, workflowInfo, executeChild } from '@temporalio/workflow';
|
|
2
|
+
import z14, { z } from 'zod';
|
|
3
3
|
import { SimplePlugin } from '@temporalio/plugin';
|
|
4
4
|
import { mapStoredMessagesToChatMessages, ToolMessage, AIMessage, SystemMessage, HumanMessage } from '@langchain/core/messages';
|
|
5
|
-
import
|
|
5
|
+
import { randomUUID, randomFillSync } from 'crypto';
|
|
6
6
|
import { Context } from '@temporalio/activity';
|
|
7
7
|
import { Bash } from 'just-bash';
|
|
8
|
+
import { readFile, readdir } from 'fs/promises';
|
|
9
|
+
import { join } from 'path';
|
|
8
10
|
|
|
9
11
|
// src/lib/session.ts
|
|
10
12
|
var SUBAGENT_TOOL_NAME = "Subagent";
|
|
11
13
|
function buildSubagentDescription(subagents) {
|
|
12
|
-
const subagentList = subagents.map((s) =>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
The ${SUBAGENT_TOOL_NAME} tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
|
|
16
|
-
|
|
17
|
-
Available agent types:
|
|
14
|
+
const subagentList = subagents.map((s) => `## ${s.agentName}
|
|
15
|
+
${s.description}`).join("\n\n");
|
|
16
|
+
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.
|
|
18
17
|
|
|
18
|
+
# Available subagents:
|
|
19
19
|
${subagentList}
|
|
20
|
-
|
|
21
|
-
When using the ${SUBAGENT_TOOL_NAME} tool, you must specify a subagent parameter to select which agent type to use.
|
|
22
|
-
|
|
23
|
-
Usage notes:
|
|
24
|
-
|
|
25
|
-
- Always include a short description (3-5 words) summarizing what the agent will do
|
|
26
|
-
- Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
27
|
-
- When the agent is done, it will return a single message back to you.
|
|
28
|
-
- Each invocation starts fresh - provide a detailed task description with all necessary context.
|
|
29
|
-
- Provide clear, detailed prompts so the agent can work autonomously and return exactly the information you need.
|
|
30
|
-
- The agent's outputs should generally be trusted
|
|
31
|
-
- Clearly tell the agent what type of work you expect since it is not aware of the user's intent
|
|
32
|
-
- If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.`;
|
|
20
|
+
`;
|
|
33
21
|
}
|
|
34
22
|
function createSubagentTool(subagents) {
|
|
35
23
|
if (subagents.length === 0) {
|
|
@@ -39,10 +27,10 @@ function createSubagentTool(subagents) {
|
|
|
39
27
|
return {
|
|
40
28
|
name: SUBAGENT_TOOL_NAME,
|
|
41
29
|
description: buildSubagentDescription(subagents),
|
|
42
|
-
schema:
|
|
43
|
-
subagent:
|
|
44
|
-
description:
|
|
45
|
-
prompt:
|
|
30
|
+
schema: z14.object({
|
|
31
|
+
subagent: z14.enum(names).describe("The type of subagent to launch"),
|
|
32
|
+
description: z14.string().describe("A short (3-5 word) description of the task"),
|
|
33
|
+
prompt: z14.string().describe("The task for the agent to perform")
|
|
46
34
|
})
|
|
47
35
|
};
|
|
48
36
|
}
|
|
@@ -66,23 +54,77 @@ function createSubagentHandler(subagents) {
|
|
|
66
54
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
67
55
|
};
|
|
68
56
|
const { toolResponse, data, usage } = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
|
|
69
|
-
|
|
57
|
+
if (!toolResponse) {
|
|
58
|
+
return {
|
|
59
|
+
toolResponse: "Subagent workflow returned no response",
|
|
60
|
+
data: null,
|
|
61
|
+
...usage && { usage }
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
const validated = config.resultSchema ? config.resultSchema.safeParse(data) : null;
|
|
65
|
+
if (validated && !validated.success) {
|
|
66
|
+
return {
|
|
67
|
+
toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
|
|
68
|
+
data: null,
|
|
69
|
+
...usage && { usage }
|
|
70
|
+
};
|
|
71
|
+
}
|
|
70
72
|
return {
|
|
71
73
|
toolResponse,
|
|
72
|
-
data: validated,
|
|
74
|
+
data: validated ? validated.data : data,
|
|
73
75
|
...usage && { usage }
|
|
74
76
|
};
|
|
75
77
|
};
|
|
76
78
|
}
|
|
79
|
+
var READ_SKILL_TOOL_NAME = "ReadSkill";
|
|
80
|
+
function buildReadSkillDescription(skills) {
|
|
81
|
+
const skillList = skills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
|
|
82
|
+
return `Load the full instructions for a skill. Read the skill before following its instructions.
|
|
77
83
|
|
|
78
|
-
|
|
84
|
+
# Available skills:
|
|
85
|
+
${skillList}
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
function createReadSkillTool(skills) {
|
|
89
|
+
if (skills.length === 0) {
|
|
90
|
+
throw new Error("createReadSkillTool requires at least one skill");
|
|
91
|
+
}
|
|
92
|
+
const names = skills.map((s) => s.name);
|
|
93
|
+
return {
|
|
94
|
+
name: READ_SKILL_TOOL_NAME,
|
|
95
|
+
description: buildReadSkillDescription(skills),
|
|
96
|
+
schema: z14.object({
|
|
97
|
+
skill_name: z14.enum(names).describe("The name of the skill to load")
|
|
98
|
+
})
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/tools/read-skill/handler.ts
|
|
103
|
+
function createReadSkillHandler(skills) {
|
|
104
|
+
const skillMap = new Map(skills.map((s) => [s.name, s]));
|
|
105
|
+
return (args) => {
|
|
106
|
+
const skill = skillMap.get(args.skill_name);
|
|
107
|
+
if (!skill) {
|
|
108
|
+
return {
|
|
109
|
+
toolResponse: JSON.stringify({
|
|
110
|
+
error: `Skill "${args.skill_name}" not found`
|
|
111
|
+
}),
|
|
112
|
+
data: null
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
toolResponse: skill.instructions,
|
|
117
|
+
data: null
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
}
|
|
79
121
|
function createToolRouter(options) {
|
|
80
122
|
const { appendToolResult } = options;
|
|
81
123
|
const toolMap = /* @__PURE__ */ new Map();
|
|
82
124
|
for (const [_key, tool] of Object.entries(options.tools)) {
|
|
83
125
|
toolMap.set(tool.name, tool);
|
|
84
126
|
}
|
|
85
|
-
const isEnabled = (tool) => tool.enabled
|
|
127
|
+
const isEnabled = (tool) => tool.enabled ?? true;
|
|
86
128
|
if (options.subagents) {
|
|
87
129
|
if (options.subagents.length > 0) {
|
|
88
130
|
const subagentHooksMap = /* @__PURE__ */ new Map();
|
|
@@ -112,6 +154,12 @@ function createToolRouter(options) {
|
|
|
112
154
|
});
|
|
113
155
|
}
|
|
114
156
|
}
|
|
157
|
+
if (options.skills && options.skills.length > 0) {
|
|
158
|
+
toolMap.set(READ_SKILL_TOOL_NAME, {
|
|
159
|
+
...createReadSkillTool(options.skills),
|
|
160
|
+
handler: createReadSkillHandler(options.skills)
|
|
161
|
+
});
|
|
162
|
+
}
|
|
115
163
|
async function processToolCall(toolCall, turn, handlerContext) {
|
|
116
164
|
const startTime = Date.now();
|
|
117
165
|
const tool = toolMap.get(toolCall.name);
|
|
@@ -221,7 +269,9 @@ function createToolRouter(options) {
|
|
|
221
269
|
}
|
|
222
270
|
}
|
|
223
271
|
if (!recovered) {
|
|
224
|
-
throw error
|
|
272
|
+
throw ApplicationFailure.fromError(error, {
|
|
273
|
+
nonRetryable: true
|
|
274
|
+
});
|
|
225
275
|
}
|
|
226
276
|
}
|
|
227
277
|
if (!resultAppended) {
|
|
@@ -284,9 +334,10 @@ function createToolRouter(options) {
|
|
|
284
334
|
},
|
|
285
335
|
getToolDefinitions() {
|
|
286
336
|
const activeSubagents = options.subagents?.filter((subagent) => isEnabled(subagent)) ?? [];
|
|
337
|
+
const activeSkills = options.skills ?? [];
|
|
287
338
|
return [
|
|
288
339
|
...Array.from(toolMap).filter(
|
|
289
|
-
([, tool]) => isEnabled(tool) && tool.name !== SUBAGENT_TOOL_NAME
|
|
340
|
+
([, tool]) => isEnabled(tool) && tool.name !== SUBAGENT_TOOL_NAME && tool.name !== READ_SKILL_TOOL_NAME
|
|
290
341
|
).map(([name, tool]) => ({
|
|
291
342
|
name,
|
|
292
343
|
description: tool.description,
|
|
@@ -294,7 +345,8 @@ function createToolRouter(options) {
|
|
|
294
345
|
strict: tool.strict,
|
|
295
346
|
max_uses: tool.max_uses
|
|
296
347
|
})),
|
|
297
|
-
...activeSubagents.length > 0 ? [createSubagentTool(activeSubagents)] : []
|
|
348
|
+
...activeSubagents.length > 0 ? [createSubagentTool(activeSubagents)] : [],
|
|
349
|
+
...activeSkills.length > 0 ? [createReadSkillTool(activeSkills)] : []
|
|
298
350
|
];
|
|
299
351
|
},
|
|
300
352
|
// --- Methods for processing tool calls ---
|
|
@@ -408,18 +460,17 @@ function hasNoOtherToolCalls(toolCalls, excludeName) {
|
|
|
408
460
|
var createSession = async ({
|
|
409
461
|
threadId,
|
|
410
462
|
agentName,
|
|
411
|
-
description,
|
|
412
463
|
maxTurns = 50,
|
|
413
464
|
metadata = {},
|
|
414
465
|
runAgent,
|
|
415
466
|
threadOps,
|
|
416
467
|
buildContextMessage,
|
|
417
468
|
subagents,
|
|
469
|
+
skills,
|
|
418
470
|
tools = {},
|
|
419
471
|
processToolsInParallel = true,
|
|
420
472
|
hooks = {},
|
|
421
473
|
appendSystemPrompt = true,
|
|
422
|
-
systemPrompt,
|
|
423
474
|
waitForInputTimeout = "48h"
|
|
424
475
|
}) => {
|
|
425
476
|
const {
|
|
@@ -434,6 +485,7 @@ var createSession = async ({
|
|
|
434
485
|
threadId,
|
|
435
486
|
hooks,
|
|
436
487
|
subagents,
|
|
488
|
+
skills,
|
|
437
489
|
parallel: processToolsInParallel
|
|
438
490
|
});
|
|
439
491
|
const callSessionEnd = async (exitReason, turns) => {
|
|
@@ -477,8 +529,15 @@ var createSession = async ({
|
|
|
477
529
|
metadata
|
|
478
530
|
});
|
|
479
531
|
}
|
|
532
|
+
const systemPrompt = stateManager.getSystemPrompt();
|
|
480
533
|
await initializeThread(threadId);
|
|
481
|
-
if (appendSystemPrompt
|
|
534
|
+
if (appendSystemPrompt) {
|
|
535
|
+
if (!systemPrompt || systemPrompt.trim() === "") {
|
|
536
|
+
throw ApplicationFailure.create({
|
|
537
|
+
message: "No system prompt in state",
|
|
538
|
+
nonRetryable: true
|
|
539
|
+
});
|
|
540
|
+
}
|
|
482
541
|
await appendSystemMessage(threadId, systemPrompt);
|
|
483
542
|
}
|
|
484
543
|
await appendHumanMessage(threadId, await buildContextMessage());
|
|
@@ -491,9 +550,7 @@ var createSession = async ({
|
|
|
491
550
|
const { message, rawToolCalls, usage } = await runAgent({
|
|
492
551
|
threadId,
|
|
493
552
|
agentName,
|
|
494
|
-
metadata
|
|
495
|
-
systemPrompt,
|
|
496
|
-
description
|
|
553
|
+
metadata
|
|
497
554
|
});
|
|
498
555
|
if (usage) {
|
|
499
556
|
stateManager.updateUsage(usage);
|
|
@@ -550,7 +607,7 @@ var createSession = async ({
|
|
|
550
607
|
}
|
|
551
608
|
} catch (error) {
|
|
552
609
|
exitReason = "failed";
|
|
553
|
-
throw error;
|
|
610
|
+
throw ApplicationFailure.fromError(error);
|
|
554
611
|
} finally {
|
|
555
612
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
556
613
|
}
|
|
@@ -565,14 +622,13 @@ var createSession = async ({
|
|
|
565
622
|
function proxyDefaultThreadOps(options) {
|
|
566
623
|
const activities = proxyActivities(
|
|
567
624
|
options ?? {
|
|
568
|
-
startToCloseTimeout: "
|
|
625
|
+
startToCloseTimeout: "10s",
|
|
569
626
|
retry: {
|
|
570
627
|
maximumAttempts: 6,
|
|
571
628
|
initialInterval: "5s",
|
|
572
629
|
maximumInterval: "15m",
|
|
573
630
|
backoffCoefficient: 4
|
|
574
|
-
}
|
|
575
|
-
heartbeatTimeout: "5m"
|
|
631
|
+
}
|
|
576
632
|
}
|
|
577
633
|
);
|
|
578
634
|
return {
|
|
@@ -584,12 +640,14 @@ function proxyDefaultThreadOps(options) {
|
|
|
584
640
|
}
|
|
585
641
|
|
|
586
642
|
// src/lib/types.ts
|
|
643
|
+
var agentQueryName = (agentName) => `get${agentName}State`;
|
|
644
|
+
var agentStateChangeUpdateName = (agentName) => `waitFor${agentName}StateChange`;
|
|
587
645
|
function isTerminalStatus(status) {
|
|
588
646
|
return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
|
|
589
647
|
}
|
|
590
648
|
function createAgentStateManager({
|
|
591
649
|
initialState,
|
|
592
|
-
|
|
650
|
+
agentName
|
|
593
651
|
}) {
|
|
594
652
|
let status = initialState?.status ?? "RUNNING";
|
|
595
653
|
let version = initialState?.version ?? 0;
|
|
@@ -600,6 +658,7 @@ function createAgentStateManager({
|
|
|
600
658
|
let totalCachedWriteTokens = 0;
|
|
601
659
|
let totalCachedReadTokens = 0;
|
|
602
660
|
let totalReasonTokens = 0;
|
|
661
|
+
let systemPrompt = initialState?.systemPrompt;
|
|
603
662
|
const tasks = new Map(initialState?.tasks);
|
|
604
663
|
const {
|
|
605
664
|
status: _,
|
|
@@ -619,28 +678,32 @@ function createAgentStateManager({
|
|
|
619
678
|
...customState
|
|
620
679
|
};
|
|
621
680
|
}
|
|
622
|
-
|
|
681
|
+
const stateQuery = defineQuery(
|
|
682
|
+
agentQueryName(agentName)
|
|
683
|
+
);
|
|
684
|
+
const stateChangeUpdate = defineUpdate(
|
|
685
|
+
agentStateChangeUpdateName(agentName)
|
|
686
|
+
);
|
|
687
|
+
setHandler(stateQuery, () => buildState());
|
|
688
|
+
setHandler(stateChangeUpdate, async (lastKnownVersion) => {
|
|
689
|
+
await condition(
|
|
690
|
+
() => version > lastKnownVersion || isTerminalStatus(status),
|
|
691
|
+
"55s"
|
|
692
|
+
);
|
|
623
693
|
return buildState();
|
|
624
694
|
});
|
|
625
|
-
setHandler(
|
|
626
|
-
defineUpdate(
|
|
627
|
-
`waitFor${agentConfig.agentName}StateChange`
|
|
628
|
-
),
|
|
629
|
-
async (lastKnownVersion) => {
|
|
630
|
-
await condition(
|
|
631
|
-
() => version > lastKnownVersion || isTerminalStatus(status),
|
|
632
|
-
"55s"
|
|
633
|
-
);
|
|
634
|
-
return buildState();
|
|
635
|
-
}
|
|
636
|
-
);
|
|
637
695
|
return {
|
|
696
|
+
stateQuery,
|
|
697
|
+
stateChangeUpdate,
|
|
638
698
|
getStatus() {
|
|
639
699
|
return status;
|
|
640
700
|
},
|
|
641
701
|
isRunning() {
|
|
642
702
|
return status === "RUNNING";
|
|
643
703
|
},
|
|
704
|
+
getSystemPrompt() {
|
|
705
|
+
return systemPrompt;
|
|
706
|
+
},
|
|
644
707
|
isTerminal() {
|
|
645
708
|
return isTerminalStatus(status);
|
|
646
709
|
},
|
|
@@ -708,6 +771,9 @@ function createAgentStateManager({
|
|
|
708
771
|
max_uses: tool.max_uses
|
|
709
772
|
}));
|
|
710
773
|
},
|
|
774
|
+
setSystemPrompt(newSystemPrompt) {
|
|
775
|
+
systemPrompt = newSystemPrompt;
|
|
776
|
+
},
|
|
711
777
|
deleteTask(id) {
|
|
712
778
|
const deleted = tasks.delete(id);
|
|
713
779
|
if (deleted) {
|
|
@@ -734,11 +800,79 @@ function createAgentStateManager({
|
|
|
734
800
|
}
|
|
735
801
|
};
|
|
736
802
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
803
|
+
|
|
804
|
+
// src/lib/skills/parse.ts
|
|
805
|
+
function parseSkillFile(raw) {
|
|
806
|
+
const trimmed = raw.replace(/^\uFEFF/, "");
|
|
807
|
+
const match = trimmed.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/);
|
|
808
|
+
if (!match) {
|
|
809
|
+
throw new Error(
|
|
810
|
+
"SKILL.md must start with YAML frontmatter delimited by ---"
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
const [, yamlBlock, body] = match;
|
|
814
|
+
const frontmatter = parseSimpleYaml(yamlBlock);
|
|
815
|
+
if (!frontmatter.name || typeof frontmatter.name !== "string") {
|
|
816
|
+
throw new Error("SKILL.md frontmatter must include a 'name' field");
|
|
817
|
+
}
|
|
818
|
+
if (!frontmatter.description || typeof frontmatter.description !== "string") {
|
|
819
|
+
throw new Error("SKILL.md frontmatter must include a 'description' field");
|
|
820
|
+
}
|
|
821
|
+
const result = {
|
|
822
|
+
name: frontmatter.name,
|
|
823
|
+
description: frontmatter.description
|
|
824
|
+
};
|
|
825
|
+
if (frontmatter.license) result.license = String(frontmatter.license);
|
|
826
|
+
if (frontmatter.compatibility)
|
|
827
|
+
result.compatibility = String(frontmatter.compatibility);
|
|
828
|
+
if (frontmatter["allowed-tools"]) {
|
|
829
|
+
result.allowedTools = String(frontmatter["allowed-tools"]).split(/\s+/).filter(Boolean);
|
|
830
|
+
}
|
|
831
|
+
if (frontmatter.metadata && typeof frontmatter.metadata === "object" && !Array.isArray(frontmatter.metadata)) {
|
|
832
|
+
result.metadata = frontmatter.metadata;
|
|
833
|
+
}
|
|
834
|
+
return { frontmatter: result, body: body.trim() };
|
|
835
|
+
}
|
|
836
|
+
function parseSimpleYaml(yaml) {
|
|
837
|
+
const result = {};
|
|
838
|
+
const lines = yaml.split(/\r?\n/);
|
|
839
|
+
let currentMapKey = null;
|
|
840
|
+
let currentMap = null;
|
|
841
|
+
for (const line of lines) {
|
|
842
|
+
if (line.trim() === "" || line.trim().startsWith("#")) continue;
|
|
843
|
+
const nestedMatch = line.match(/^(\s{2,}|\t+)(\S+)\s*:\s*(.*)$/);
|
|
844
|
+
if (nestedMatch && currentMapKey && currentMap) {
|
|
845
|
+
const [, , key2, rawVal2] = nestedMatch;
|
|
846
|
+
currentMap[key2] = unquote(rawVal2.trim());
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
if (currentMapKey && currentMap) {
|
|
850
|
+
result[currentMapKey] = currentMap;
|
|
851
|
+
currentMapKey = null;
|
|
852
|
+
currentMap = null;
|
|
853
|
+
}
|
|
854
|
+
const topMatch = line.match(/^(\S+)\s*:\s*(.*)$/);
|
|
855
|
+
if (!topMatch) continue;
|
|
856
|
+
const [, key, rawVal] = topMatch;
|
|
857
|
+
const val = rawVal.trim();
|
|
858
|
+
if (val === "" || val === "|" || val === ">") {
|
|
859
|
+
currentMapKey = key;
|
|
860
|
+
currentMap = {};
|
|
861
|
+
} else {
|
|
862
|
+
result[key] = unquote(val);
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
if (currentMapKey && currentMap) {
|
|
866
|
+
result[currentMapKey] = currentMap;
|
|
867
|
+
}
|
|
868
|
+
return result;
|
|
869
|
+
}
|
|
870
|
+
function unquote(s) {
|
|
871
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
872
|
+
return s.slice(1, -1);
|
|
873
|
+
}
|
|
874
|
+
return s;
|
|
875
|
+
}
|
|
742
876
|
var globTool = {
|
|
743
877
|
name: "Glob",
|
|
744
878
|
description: `Search for files matching a glob pattern within the available file system.
|
|
@@ -855,7 +989,7 @@ IMPORTANT:
|
|
|
855
989
|
};
|
|
856
990
|
var taskCreateTool = {
|
|
857
991
|
name: "TaskCreate",
|
|
858
|
-
description: `Use this tool to create a structured task list
|
|
992
|
+
description: `Use this tool to create a structured task list. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
859
993
|
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
860
994
|
|
|
861
995
|
## When to Use This Tool
|
|
@@ -894,17 +1028,17 @@ var taskCreateTool = {
|
|
|
894
1028
|
- Include enough detail in the description for another agent to understand and complete the task
|
|
895
1029
|
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
896
1030
|
- Check TaskList first to avoid creating duplicate tasks`,
|
|
897
|
-
schema:
|
|
898
|
-
subject:
|
|
1031
|
+
schema: z14.object({
|
|
1032
|
+
subject: z14.string().describe(
|
|
899
1033
|
'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
|
|
900
1034
|
),
|
|
901
|
-
description:
|
|
1035
|
+
description: z14.string().describe(
|
|
902
1036
|
"Detailed description of what needs to be done, including context and acceptance criteria"
|
|
903
1037
|
),
|
|
904
|
-
activeForm:
|
|
1038
|
+
activeForm: z14.string().describe(
|
|
905
1039
|
'Present continuous form shown in spinner when task is in_progress (e.g., "Fixing authentication bug"). This is displayed to the user while you work on the task.'
|
|
906
1040
|
),
|
|
907
|
-
metadata:
|
|
1041
|
+
metadata: z14.record(z14.string(), z14.string()).describe("Arbitrary key-value pairs for tracking")
|
|
908
1042
|
})
|
|
909
1043
|
};
|
|
910
1044
|
function createTaskCreateHandler(stateManager) {
|
|
@@ -929,8 +1063,8 @@ function createTaskCreateHandler(stateManager) {
|
|
|
929
1063
|
var taskGetTool = {
|
|
930
1064
|
name: "TaskGet",
|
|
931
1065
|
description: `Retrieve full task details including dependencies.`,
|
|
932
|
-
schema:
|
|
933
|
-
taskId:
|
|
1066
|
+
schema: z14.object({
|
|
1067
|
+
taskId: z14.string().describe("The ID of the task to get")
|
|
934
1068
|
})
|
|
935
1069
|
};
|
|
936
1070
|
|
|
@@ -953,7 +1087,7 @@ function createTaskGetHandler(stateManager) {
|
|
|
953
1087
|
var taskListTool = {
|
|
954
1088
|
name: "TaskList",
|
|
955
1089
|
description: `List all tasks with current state.`,
|
|
956
|
-
schema:
|
|
1090
|
+
schema: z14.object({})
|
|
957
1091
|
};
|
|
958
1092
|
|
|
959
1093
|
// src/tools/task-list/handler.ts
|
|
@@ -969,11 +1103,11 @@ function createTaskListHandler(stateManager) {
|
|
|
969
1103
|
var taskUpdateTool = {
|
|
970
1104
|
name: "TaskUpdate",
|
|
971
1105
|
description: `Update status, add blockers, modify details.`,
|
|
972
|
-
schema:
|
|
973
|
-
taskId:
|
|
974
|
-
status:
|
|
975
|
-
addBlockedBy:
|
|
976
|
-
addBlocks:
|
|
1106
|
+
schema: z14.object({
|
|
1107
|
+
taskId: z14.string().describe("The ID of the task to get"),
|
|
1108
|
+
status: z14.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
|
|
1109
|
+
addBlockedBy: z14.array(z14.string()).describe("The IDs of the tasks that are blocking this task"),
|
|
1110
|
+
addBlocks: z14.array(z14.string()).describe("The IDs of the tasks that this task is blocking")
|
|
977
1111
|
})
|
|
978
1112
|
};
|
|
979
1113
|
|
|
@@ -1041,8 +1175,8 @@ Use this tool to:
|
|
|
1041
1175
|
- Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
|
|
1042
1176
|
- Inspect files and directories
|
|
1043
1177
|
`,
|
|
1044
|
-
schema:
|
|
1045
|
-
command:
|
|
1178
|
+
schema: z14.object({
|
|
1179
|
+
command: z14.string().describe(
|
|
1046
1180
|
"The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
|
|
1047
1181
|
)
|
|
1048
1182
|
}),
|
|
@@ -1063,18 +1197,18 @@ Usage notes:
|
|
|
1063
1197
|
* Use multiSelect: true to allow multiple answers to be selected for a question
|
|
1064
1198
|
* If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
1065
1199
|
`,
|
|
1066
|
-
schema:
|
|
1067
|
-
questions:
|
|
1068
|
-
|
|
1069
|
-
question:
|
|
1070
|
-
header:
|
|
1071
|
-
options:
|
|
1072
|
-
|
|
1073
|
-
label:
|
|
1074
|
-
description:
|
|
1200
|
+
schema: z14.object({
|
|
1201
|
+
questions: z14.array(
|
|
1202
|
+
z14.object({
|
|
1203
|
+
question: z14.string().describe("The full question text to display"),
|
|
1204
|
+
header: z14.string().describe("Short label for the question (max 12 characters)"),
|
|
1205
|
+
options: z14.array(
|
|
1206
|
+
z14.object({
|
|
1207
|
+
label: z14.string(),
|
|
1208
|
+
description: z14.string()
|
|
1075
1209
|
})
|
|
1076
1210
|
).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
|
|
1077
|
-
multiSelect:
|
|
1211
|
+
multiSelect: z14.boolean().describe("If true, users can select multiple options")
|
|
1078
1212
|
})
|
|
1079
1213
|
)
|
|
1080
1214
|
}),
|
|
@@ -1089,7 +1223,7 @@ var createAskUserQuestionHandler = () => async (args) => {
|
|
|
1089
1223
|
};
|
|
1090
1224
|
};
|
|
1091
1225
|
|
|
1092
|
-
// node_modules/uuid/dist/esm
|
|
1226
|
+
// node_modules/uuid/dist/esm/stringify.js
|
|
1093
1227
|
var byteToHex = [];
|
|
1094
1228
|
for (let i = 0; i < 256; ++i) {
|
|
1095
1229
|
byteToHex.push((i + 256).toString(16).slice(1));
|
|
@@ -1101,26 +1235,30 @@ var rnds8Pool = new Uint8Array(256);
|
|
|
1101
1235
|
var poolPtr = rnds8Pool.length;
|
|
1102
1236
|
function rng() {
|
|
1103
1237
|
if (poolPtr > rnds8Pool.length - 16) {
|
|
1104
|
-
|
|
1238
|
+
randomFillSync(rnds8Pool);
|
|
1105
1239
|
poolPtr = 0;
|
|
1106
1240
|
}
|
|
1107
1241
|
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
1108
1242
|
}
|
|
1109
|
-
var native_default = {
|
|
1110
|
-
randomUUID: crypto.randomUUID
|
|
1111
|
-
};
|
|
1243
|
+
var native_default = { randomUUID };
|
|
1112
1244
|
|
|
1113
|
-
// node_modules/uuid/dist/esm
|
|
1245
|
+
// node_modules/uuid/dist/esm/v4.js
|
|
1114
1246
|
function v4(options, buf, offset) {
|
|
1115
1247
|
if (native_default.randomUUID && !buf && !options) {
|
|
1116
1248
|
return native_default.randomUUID();
|
|
1117
1249
|
}
|
|
1118
1250
|
options = options || {};
|
|
1119
|
-
const rnds = options.random
|
|
1251
|
+
const rnds = options.random ?? options.rng?.() ?? rng();
|
|
1252
|
+
if (rnds.length < 16) {
|
|
1253
|
+
throw new Error("Random bytes length must be >= 16");
|
|
1254
|
+
}
|
|
1120
1255
|
rnds[6] = rnds[6] & 15 | 64;
|
|
1121
1256
|
rnds[8] = rnds[8] & 63 | 128;
|
|
1122
1257
|
if (buf) {
|
|
1123
1258
|
offset = offset || 0;
|
|
1259
|
+
if (offset < 0 || offset + 16 > buf.length) {
|
|
1260
|
+
throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
|
|
1261
|
+
}
|
|
1124
1262
|
for (let i = 0; i < 16; ++i) {
|
|
1125
1263
|
buf[offset + i] = rnds[i];
|
|
1126
1264
|
}
|
|
@@ -1132,9 +1270,23 @@ var v4_default = v4;
|
|
|
1132
1270
|
|
|
1133
1271
|
// src/lib/thread-manager.ts
|
|
1134
1272
|
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
1273
|
+
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
1274
|
+
if redis.call('EXISTS', KEYS[1]) == 1 then
|
|
1275
|
+
return 0
|
|
1276
|
+
end
|
|
1277
|
+
for i = 2, #ARGV do
|
|
1278
|
+
redis.call('RPUSH', KEYS[2], ARGV[i])
|
|
1279
|
+
end
|
|
1280
|
+
redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
1281
|
+
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
1282
|
+
return 1
|
|
1283
|
+
`;
|
|
1135
1284
|
function getThreadKey(threadId, key) {
|
|
1136
1285
|
return `thread:${threadId}:${key}`;
|
|
1137
1286
|
}
|
|
1287
|
+
function storedMessageId(msg) {
|
|
1288
|
+
return msg.data.id ?? "";
|
|
1289
|
+
}
|
|
1138
1290
|
function createThreadManager(config) {
|
|
1139
1291
|
const {
|
|
1140
1292
|
redis,
|
|
@@ -1144,6 +1296,7 @@ function createThreadManager(config) {
|
|
|
1144
1296
|
deserialize = (raw) => JSON.parse(raw)
|
|
1145
1297
|
} = config;
|
|
1146
1298
|
const redisKey = getThreadKey(threadId, key);
|
|
1299
|
+
const idOf = config.idOf ?? (!config.serialize ? storedMessageId : void 0);
|
|
1147
1300
|
const base = {
|
|
1148
1301
|
async initialize() {
|
|
1149
1302
|
await redis.del(redisKey);
|
|
@@ -1153,7 +1306,19 @@ function createThreadManager(config) {
|
|
|
1153
1306
|
return data.map(deserialize);
|
|
1154
1307
|
},
|
|
1155
1308
|
async append(messages) {
|
|
1156
|
-
if (messages.length
|
|
1309
|
+
if (messages.length === 0) return;
|
|
1310
|
+
if (idOf) {
|
|
1311
|
+
const dedupId = messages.map(idOf).join(":");
|
|
1312
|
+
const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
|
|
1313
|
+
await redis.eval(
|
|
1314
|
+
APPEND_IDEMPOTENT_SCRIPT,
|
|
1315
|
+
2,
|
|
1316
|
+
dedupKey,
|
|
1317
|
+
redisKey,
|
|
1318
|
+
String(THREAD_TTL_SECONDS),
|
|
1319
|
+
...messages.map(serialize)
|
|
1320
|
+
);
|
|
1321
|
+
} else {
|
|
1157
1322
|
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
1158
1323
|
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
1159
1324
|
}
|
|
@@ -1188,6 +1353,7 @@ function createThreadManager(config) {
|
|
|
1188
1353
|
},
|
|
1189
1354
|
createToolMessage(content, toolCallId) {
|
|
1190
1355
|
return new ToolMessage({
|
|
1356
|
+
id: v4_default(),
|
|
1191
1357
|
content,
|
|
1192
1358
|
tool_call_id: toolCallId
|
|
1193
1359
|
}).toDict();
|
|
@@ -1260,7 +1426,7 @@ async function invokeModel({
|
|
|
1260
1426
|
const parentWorkflowId = info.workflowExecution.workflowId;
|
|
1261
1427
|
const parentRunId = info.workflowExecution.runId;
|
|
1262
1428
|
const handle = client.getHandle(parentWorkflowId, parentRunId);
|
|
1263
|
-
const { tools } = await handle.query(
|
|
1429
|
+
const { tools } = await handle.query(agentQueryName(agentName));
|
|
1264
1430
|
const messages = await thread.load();
|
|
1265
1431
|
const response = await model.invoke(
|
|
1266
1432
|
[...mapStoredMessagesToChatMessages(messages)],
|
|
@@ -1457,7 +1623,62 @@ var toTree = async (fs, opts = {}) => {
|
|
|
1457
1623
|
const base = basename(dir, separator) + separator;
|
|
1458
1624
|
return base + subtree;
|
|
1459
1625
|
};
|
|
1626
|
+
var FileSystemSkillProvider = class {
|
|
1627
|
+
constructor(baseDir) {
|
|
1628
|
+
this.baseDir = baseDir;
|
|
1629
|
+
}
|
|
1630
|
+
async listSkills() {
|
|
1631
|
+
const dirs = await this.discoverSkillDirs();
|
|
1632
|
+
const skills = [];
|
|
1633
|
+
for (const dir of dirs) {
|
|
1634
|
+
const raw = await readFile(join(this.baseDir, dir, "SKILL.md"), "utf-8");
|
|
1635
|
+
const { frontmatter } = parseSkillFile(raw);
|
|
1636
|
+
skills.push(frontmatter);
|
|
1637
|
+
}
|
|
1638
|
+
return skills;
|
|
1639
|
+
}
|
|
1640
|
+
async getSkill(name) {
|
|
1641
|
+
const raw = await readFile(
|
|
1642
|
+
join(this.baseDir, name, "SKILL.md"),
|
|
1643
|
+
"utf-8"
|
|
1644
|
+
);
|
|
1645
|
+
const { frontmatter, body } = parseSkillFile(raw);
|
|
1646
|
+
if (frontmatter.name !== name) {
|
|
1647
|
+
throw new Error(
|
|
1648
|
+
`Skill directory "${name}" contains SKILL.md with mismatched name "${frontmatter.name}"`
|
|
1649
|
+
);
|
|
1650
|
+
}
|
|
1651
|
+
return { ...frontmatter, instructions: body };
|
|
1652
|
+
}
|
|
1653
|
+
/**
|
|
1654
|
+
* Convenience method to load all skills with full instructions.
|
|
1655
|
+
* Returns `Skill[]` ready to pass into a workflow.
|
|
1656
|
+
*/
|
|
1657
|
+
async loadAll() {
|
|
1658
|
+
const dirs = await this.discoverSkillDirs();
|
|
1659
|
+
const skills = [];
|
|
1660
|
+
for (const dir of dirs) {
|
|
1661
|
+
const raw = await readFile(join(this.baseDir, dir, "SKILL.md"), "utf-8");
|
|
1662
|
+
const { frontmatter, body } = parseSkillFile(raw);
|
|
1663
|
+
skills.push({ ...frontmatter, instructions: body });
|
|
1664
|
+
}
|
|
1665
|
+
return skills;
|
|
1666
|
+
}
|
|
1667
|
+
async discoverSkillDirs() {
|
|
1668
|
+
const entries = await readdir(this.baseDir, { withFileTypes: true });
|
|
1669
|
+
const dirs = [];
|
|
1670
|
+
for (const entry of entries) {
|
|
1671
|
+
if (!entry.isDirectory()) continue;
|
|
1672
|
+
try {
|
|
1673
|
+
await readFile(join(this.baseDir, entry.name, "SKILL.md"), "utf-8");
|
|
1674
|
+
dirs.push(entry.name);
|
|
1675
|
+
} catch {
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
return dirs;
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1460
1681
|
|
|
1461
|
-
export {
|
|
1682
|
+
export { FileSystemSkillProvider, ZeitlichPlugin, agentQueryName, agentStateChangeUpdateName, askUserQuestionTool, bashTool, createAgentStateManager, createAskUserQuestionHandler, createBashHandler, createBashToolDescription, createEditHandler, createGlobHandler, createReadSkillHandler, createReadSkillTool, createSession, createSharedActivities, createSubagentTool, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, defineSubagent, defineTool, editTool, globTool, grepTool, hasNoOtherToolCalls, invokeModel, isTerminalStatus, parseSkillFile, proxyDefaultThreadOps, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, writeFileTool };
|
|
1462
1683
|
//# sourceMappingURL=index.js.map
|
|
1463
1684
|
//# sourceMappingURL=index.js.map
|