zeitlich 0.2.9 → 0.2.12
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 +313 -126
- package/dist/adapters/langchain/index.cjs +270 -0
- package/dist/adapters/langchain/index.cjs.map +1 -0
- package/dist/adapters/langchain/index.d.cts +132 -0
- package/dist/adapters/langchain/index.d.ts +132 -0
- package/dist/adapters/langchain/index.js +265 -0
- package/dist/adapters/langchain/index.js.map +1 -0
- package/dist/index.cjs +406 -301
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +88 -45
- package/dist/index.d.ts +88 -45
- package/dist/index.js +375 -274
- package/dist/index.js.map +1 -1
- package/dist/{workflow-C2ShwjC7.d.cts → model-invoker-C5-N-5TC.d.cts} +92 -435
- package/dist/{workflow-C2ShwjC7.d.ts → model-invoker-C5-N-5TC.d.ts} +92 -435
- package/dist/thread-manager-qc0g5Rvd.d.cts +39 -0
- package/dist/thread-manager-qc0g5Rvd.d.ts +39 -0
- package/dist/workflow.cjs +294 -126
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +459 -5
- package/dist/workflow.d.ts +459 -5
- package/dist/workflow.js +266 -103
- package/dist/workflow.js.map +1 -1
- package/package.json +30 -15
- package/src/adapters/langchain/activities.ts +120 -0
- package/src/adapters/langchain/index.ts +38 -0
- package/src/adapters/langchain/model-invoker.ts +102 -0
- package/src/adapters/langchain/thread-manager.ts +142 -0
- package/src/index.ts +26 -22
- package/src/lib/fs.ts +25 -0
- package/src/lib/model-invoker.ts +14 -74
- package/src/lib/session.ts +60 -23
- 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 +65 -31
- package/src/lib/thread-id.ts +25 -0
- package/src/lib/thread-manager.ts +63 -128
- package/src/lib/tool-router.ts +33 -23
- package/src/lib/types.ts +48 -15
- package/src/lib/workflow-helpers.ts +50 -0
- package/src/tools/ask-user-question/handler.ts +25 -1
- package/src/tools/bash/handler.ts +13 -0
- package/src/tools/read-skill/handler.ts +31 -0
- package/src/tools/read-skill/tool.ts +47 -0
- package/src/tools/subagent/handler.ts +37 -9
- package/src/tools/subagent/tool.ts +38 -34
- package/src/tools/task-create/tool.ts +1 -1
- package/src/workflow.ts +39 -11
- package/tsup.config.ts +1 -0
- package/src/activities.ts +0 -91
- package/src/plugin.ts +0 -28
package/dist/index.cjs
CHANGED
|
@@ -1,58 +1,67 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var workflow = require('@temporalio/workflow');
|
|
4
|
-
var
|
|
5
|
-
var plugin = require('@temporalio/plugin');
|
|
6
|
-
var messages = require('@langchain/core/messages');
|
|
7
|
-
var crypto = require('crypto');
|
|
4
|
+
var z14 = require('zod');
|
|
8
5
|
var activity = require('@temporalio/activity');
|
|
9
6
|
var justBash = require('just-bash');
|
|
7
|
+
var promises = require('fs/promises');
|
|
8
|
+
var path = require('path');
|
|
10
9
|
|
|
11
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
11
|
|
|
13
|
-
var
|
|
14
|
-
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
12
|
+
var z14__default = /*#__PURE__*/_interopDefault(z14);
|
|
15
13
|
|
|
16
14
|
// src/lib/session.ts
|
|
17
15
|
var SUBAGENT_TOOL_NAME = "Subagent";
|
|
18
16
|
function buildSubagentDescription(subagents) {
|
|
19
|
-
const subagentList = subagents.map((s) =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
const subagentList = subagents.map((s) => {
|
|
18
|
+
const continuation = s.allowThreadContinuation ? "\n*(Supports thread continuation \u2014 pass a threadId to resume a previous conversation)*" : "";
|
|
19
|
+
return `## ${s.agentName}
|
|
20
|
+
${s.description}${continuation}`;
|
|
21
|
+
}).join("\n\n");
|
|
22
|
+
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.
|
|
25
23
|
|
|
24
|
+
# Available subagents:
|
|
26
25
|
${subagentList}
|
|
27
|
-
|
|
28
|
-
When using the ${SUBAGENT_TOOL_NAME} tool, you must specify a subagent parameter to select which agent type to use.
|
|
29
|
-
|
|
30
|
-
Usage notes:
|
|
31
|
-
|
|
32
|
-
- Always include a short description (3-5 words) summarizing what the agent will do
|
|
33
|
-
- Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
|
|
34
|
-
- When the agent is done, it will return a single message back to you.
|
|
35
|
-
- Each invocation starts fresh - provide a detailed task description with all necessary context.
|
|
36
|
-
- Provide clear, detailed prompts so the agent can work autonomously and return exactly the information you need.
|
|
37
|
-
- The agent's outputs should generally be trusted
|
|
38
|
-
- Clearly tell the agent what type of work you expect since it is not aware of the user's intent
|
|
39
|
-
- 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.`;
|
|
26
|
+
`;
|
|
40
27
|
}
|
|
41
28
|
function createSubagentTool(subagents) {
|
|
42
29
|
if (subagents.length === 0) {
|
|
43
30
|
throw new Error("createTaskTool requires at least one subagent");
|
|
44
31
|
}
|
|
45
32
|
const names = subagents.map((s) => s.agentName);
|
|
33
|
+
const hasThreadContinuation = subagents.some(
|
|
34
|
+
(s) => s.allowThreadContinuation
|
|
35
|
+
);
|
|
36
|
+
const baseFields = {
|
|
37
|
+
subagent: z14__default.default.enum(names).describe("The type of subagent to launch"),
|
|
38
|
+
description: z14__default.default.string().describe("A short (3-5 word) description of the task"),
|
|
39
|
+
prompt: z14__default.default.string().describe("The task for the agent to perform")
|
|
40
|
+
};
|
|
41
|
+
const schema = hasThreadContinuation ? z14__default.default.object({
|
|
42
|
+
...baseFields,
|
|
43
|
+
threadId: z14__default.default.string().nullable().describe(
|
|
44
|
+
"Thread ID to continue an existing conversation, or null to start a new one"
|
|
45
|
+
)
|
|
46
|
+
}) : z14__default.default.object(baseFields);
|
|
46
47
|
return {
|
|
47
48
|
name: SUBAGENT_TOOL_NAME,
|
|
48
49
|
description: buildSubagentDescription(subagents),
|
|
49
|
-
schema
|
|
50
|
-
subagent: z13__default.default.enum(names).describe("The type of subagent to launch"),
|
|
51
|
-
description: z13__default.default.string().describe("A short (3-5 word) description of the task"),
|
|
52
|
-
prompt: z13__default.default.string().describe("The task for the agent to perform")
|
|
53
|
-
})
|
|
50
|
+
schema
|
|
54
51
|
};
|
|
55
52
|
}
|
|
53
|
+
var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
54
|
+
function getShortId(length = 12) {
|
|
55
|
+
const hex = workflow.uuid4().replace(/-/g, "");
|
|
56
|
+
let result = "";
|
|
57
|
+
for (let i = 0; i < length; i++) {
|
|
58
|
+
const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
59
|
+
result += BASE62[byte % BASE62.length];
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/tools/subagent/handler.ts
|
|
56
65
|
function createSubagentHandler(subagents) {
|
|
57
66
|
const { taskQueue: parentTaskQueue } = workflow.workflowInfo();
|
|
58
67
|
return async (args) => {
|
|
@@ -62,34 +71,95 @@ function createSubagentHandler(subagents) {
|
|
|
62
71
|
`Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
|
|
63
72
|
);
|
|
64
73
|
}
|
|
65
|
-
const childWorkflowId = `${args.subagent}-${
|
|
74
|
+
const childWorkflowId = `${args.subagent}-${getShortId()}`;
|
|
66
75
|
const input = {
|
|
67
76
|
prompt: args.prompt,
|
|
68
|
-
...config.context && { context: config.context }
|
|
77
|
+
...config.context && { context: config.context },
|
|
78
|
+
...args.threadId && config.allowThreadContinuation && { threadId: args.threadId }
|
|
69
79
|
};
|
|
70
80
|
const childOpts = {
|
|
71
81
|
workflowId: childWorkflowId,
|
|
72
82
|
args: [input],
|
|
73
83
|
taskQueue: config.taskQueue ?? parentTaskQueue
|
|
74
84
|
};
|
|
75
|
-
const { toolResponse, data, usage } = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
|
|
76
|
-
|
|
85
|
+
const { toolResponse, data, usage, threadId: childThreadId } = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
|
|
86
|
+
if (!toolResponse) {
|
|
87
|
+
return {
|
|
88
|
+
toolResponse: "Subagent workflow returned no response",
|
|
89
|
+
data: null,
|
|
90
|
+
...usage && { usage }
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
const validated = config.resultSchema ? config.resultSchema.safeParse(data) : null;
|
|
94
|
+
if (validated && !validated.success) {
|
|
95
|
+
return {
|
|
96
|
+
toolResponse: `Subagent workflow returned invalid data: ${validated.error.message}`,
|
|
97
|
+
data: null,
|
|
98
|
+
...usage && { usage }
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
let finalToolResponse = toolResponse;
|
|
102
|
+
if (config.allowThreadContinuation && childThreadId) {
|
|
103
|
+
finalToolResponse = typeof toolResponse === "string" ? `${toolResponse}
|
|
104
|
+
|
|
105
|
+
[Thread ID: ${childThreadId}]` : toolResponse;
|
|
106
|
+
}
|
|
77
107
|
return {
|
|
78
|
-
toolResponse,
|
|
79
|
-
data: validated,
|
|
108
|
+
toolResponse: finalToolResponse,
|
|
109
|
+
data: validated ? validated.data : data,
|
|
80
110
|
...usage && { usage }
|
|
81
111
|
};
|
|
82
112
|
};
|
|
83
113
|
}
|
|
114
|
+
var READ_SKILL_TOOL_NAME = "ReadSkill";
|
|
115
|
+
function buildReadSkillDescription(skills) {
|
|
116
|
+
const skillList = skills.map((s) => `- **${s.name}**: ${s.description}`).join("\n");
|
|
117
|
+
return `Load the full instructions for a skill. Read the skill before following its instructions.
|
|
84
118
|
|
|
85
|
-
|
|
119
|
+
# Available skills:
|
|
120
|
+
${skillList}
|
|
121
|
+
`;
|
|
122
|
+
}
|
|
123
|
+
function createReadSkillTool(skills) {
|
|
124
|
+
if (skills.length === 0) {
|
|
125
|
+
throw new Error("createReadSkillTool requires at least one skill");
|
|
126
|
+
}
|
|
127
|
+
const names = skills.map((s) => s.name);
|
|
128
|
+
return {
|
|
129
|
+
name: READ_SKILL_TOOL_NAME,
|
|
130
|
+
description: buildReadSkillDescription(skills),
|
|
131
|
+
schema: z14__default.default.object({
|
|
132
|
+
skill_name: z14__default.default.enum(names).describe("The name of the skill to load")
|
|
133
|
+
})
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// src/tools/read-skill/handler.ts
|
|
138
|
+
function createReadSkillHandler(skills) {
|
|
139
|
+
const skillMap = new Map(skills.map((s) => [s.name, s]));
|
|
140
|
+
return (args) => {
|
|
141
|
+
const skill = skillMap.get(args.skill_name);
|
|
142
|
+
if (!skill) {
|
|
143
|
+
return {
|
|
144
|
+
toolResponse: JSON.stringify({
|
|
145
|
+
error: `Skill "${args.skill_name}" not found`
|
|
146
|
+
}),
|
|
147
|
+
data: null
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
toolResponse: skill.instructions,
|
|
152
|
+
data: null
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
}
|
|
86
156
|
function createToolRouter(options) {
|
|
87
157
|
const { appendToolResult } = options;
|
|
88
158
|
const toolMap = /* @__PURE__ */ new Map();
|
|
89
159
|
for (const [_key, tool] of Object.entries(options.tools)) {
|
|
90
160
|
toolMap.set(tool.name, tool);
|
|
91
161
|
}
|
|
92
|
-
const isEnabled = (tool) => tool.enabled
|
|
162
|
+
const isEnabled = (tool) => tool.enabled ?? true;
|
|
93
163
|
if (options.subagents) {
|
|
94
164
|
if (options.subagents.length > 0) {
|
|
95
165
|
const subagentHooksMap = /* @__PURE__ */ new Map();
|
|
@@ -119,6 +189,12 @@ function createToolRouter(options) {
|
|
|
119
189
|
});
|
|
120
190
|
}
|
|
121
191
|
}
|
|
192
|
+
if (options.skills && options.skills.length > 0) {
|
|
193
|
+
toolMap.set(READ_SKILL_TOOL_NAME, {
|
|
194
|
+
...createReadSkillTool(options.skills),
|
|
195
|
+
handler: createReadSkillHandler(options.skills)
|
|
196
|
+
});
|
|
197
|
+
}
|
|
122
198
|
async function processToolCall(toolCall, turn, handlerContext) {
|
|
123
199
|
const startTime = Date.now();
|
|
124
200
|
const tool = toolMap.get(toolCall.name);
|
|
@@ -228,7 +304,9 @@ function createToolRouter(options) {
|
|
|
228
304
|
}
|
|
229
305
|
}
|
|
230
306
|
if (!recovered) {
|
|
231
|
-
throw error
|
|
307
|
+
throw workflow.ApplicationFailure.fromError(error, {
|
|
308
|
+
nonRetryable: true
|
|
309
|
+
});
|
|
232
310
|
}
|
|
233
311
|
}
|
|
234
312
|
if (!resultAppended) {
|
|
@@ -291,9 +369,10 @@ function createToolRouter(options) {
|
|
|
291
369
|
},
|
|
292
370
|
getToolDefinitions() {
|
|
293
371
|
const activeSubagents = options.subagents?.filter((subagent) => isEnabled(subagent)) ?? [];
|
|
372
|
+
const activeSkills = options.skills ?? [];
|
|
294
373
|
return [
|
|
295
374
|
...Array.from(toolMap).filter(
|
|
296
|
-
([, tool]) => isEnabled(tool) && tool.name !== SUBAGENT_TOOL_NAME
|
|
375
|
+
([, tool]) => isEnabled(tool) && tool.name !== SUBAGENT_TOOL_NAME && tool.name !== READ_SKILL_TOOL_NAME
|
|
297
376
|
).map(([name, tool]) => ({
|
|
298
377
|
name,
|
|
299
378
|
description: tool.description,
|
|
@@ -301,7 +380,8 @@ function createToolRouter(options) {
|
|
|
301
380
|
strict: tool.strict,
|
|
302
381
|
max_uses: tool.max_uses
|
|
303
382
|
})),
|
|
304
|
-
...activeSubagents.length > 0 ? [createSubagentTool(activeSubagents)] : []
|
|
383
|
+
...activeSubagents.length > 0 ? [createSubagentTool(activeSubagents)] : [],
|
|
384
|
+
...activeSkills.length > 0 ? [createReadSkillTool(activeSkills)] : []
|
|
305
385
|
];
|
|
306
386
|
},
|
|
307
387
|
// --- Methods for processing tool calls ---
|
|
@@ -413,22 +493,23 @@ function hasNoOtherToolCalls(toolCalls, excludeName) {
|
|
|
413
493
|
|
|
414
494
|
// src/lib/session.ts
|
|
415
495
|
var createSession = async ({
|
|
416
|
-
threadId,
|
|
496
|
+
threadId: providedThreadId,
|
|
417
497
|
agentName,
|
|
418
|
-
description,
|
|
419
498
|
maxTurns = 50,
|
|
420
499
|
metadata = {},
|
|
421
500
|
runAgent,
|
|
422
501
|
threadOps,
|
|
423
502
|
buildContextMessage,
|
|
424
503
|
subagents,
|
|
504
|
+
skills,
|
|
425
505
|
tools = {},
|
|
426
506
|
processToolsInParallel = true,
|
|
427
507
|
hooks = {},
|
|
428
508
|
appendSystemPrompt = true,
|
|
429
|
-
|
|
509
|
+
continueThread = false,
|
|
430
510
|
waitForInputTimeout = "48h"
|
|
431
511
|
}) => {
|
|
512
|
+
const threadId = providedThreadId ?? getShortId();
|
|
432
513
|
const {
|
|
433
514
|
appendToolResult,
|
|
434
515
|
appendHumanMessage,
|
|
@@ -441,6 +522,7 @@ var createSession = async ({
|
|
|
441
522
|
threadId,
|
|
442
523
|
hooks,
|
|
443
524
|
subagents,
|
|
525
|
+
skills,
|
|
444
526
|
parallel: processToolsInParallel
|
|
445
527
|
});
|
|
446
528
|
const callSessionEnd = async (exitReason, turns) => {
|
|
@@ -484,9 +566,19 @@ var createSession = async ({
|
|
|
484
566
|
metadata
|
|
485
567
|
});
|
|
486
568
|
}
|
|
487
|
-
|
|
488
|
-
if (
|
|
489
|
-
|
|
569
|
+
const systemPrompt = stateManager.getSystemPrompt();
|
|
570
|
+
if (!continueThread) {
|
|
571
|
+
if (appendSystemPrompt) {
|
|
572
|
+
if (!systemPrompt || systemPrompt.trim() === "") {
|
|
573
|
+
throw workflow.ApplicationFailure.create({
|
|
574
|
+
message: "No system prompt in state",
|
|
575
|
+
nonRetryable: true
|
|
576
|
+
});
|
|
577
|
+
}
|
|
578
|
+
await appendSystemMessage(threadId, systemPrompt);
|
|
579
|
+
} else {
|
|
580
|
+
await initializeThread(threadId);
|
|
581
|
+
}
|
|
490
582
|
}
|
|
491
583
|
await appendHumanMessage(threadId, await buildContextMessage());
|
|
492
584
|
let exitReason = "completed";
|
|
@@ -498,9 +590,7 @@ var createSession = async ({
|
|
|
498
590
|
const { message, rawToolCalls, usage } = await runAgent({
|
|
499
591
|
threadId,
|
|
500
592
|
agentName,
|
|
501
|
-
metadata
|
|
502
|
-
systemPrompt,
|
|
503
|
-
description
|
|
593
|
+
metadata
|
|
504
594
|
});
|
|
505
595
|
if (usage) {
|
|
506
596
|
stateManager.updateUsage(usage);
|
|
@@ -557,7 +647,7 @@ var createSession = async ({
|
|
|
557
647
|
}
|
|
558
648
|
} catch (error) {
|
|
559
649
|
exitReason = "failed";
|
|
560
|
-
throw error;
|
|
650
|
+
throw workflow.ApplicationFailure.fromError(error);
|
|
561
651
|
} finally {
|
|
562
652
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
563
653
|
}
|
|
@@ -570,33 +660,28 @@ var createSession = async ({
|
|
|
570
660
|
};
|
|
571
661
|
};
|
|
572
662
|
function proxyDefaultThreadOps(options) {
|
|
573
|
-
|
|
663
|
+
return workflow.proxyActivities(
|
|
574
664
|
options ?? {
|
|
575
|
-
startToCloseTimeout: "
|
|
665
|
+
startToCloseTimeout: "10s",
|
|
576
666
|
retry: {
|
|
577
667
|
maximumAttempts: 6,
|
|
578
668
|
initialInterval: "5s",
|
|
579
669
|
maximumInterval: "15m",
|
|
580
670
|
backoffCoefficient: 4
|
|
581
|
-
}
|
|
582
|
-
heartbeatTimeout: "5m"
|
|
671
|
+
}
|
|
583
672
|
}
|
|
584
673
|
);
|
|
585
|
-
return {
|
|
586
|
-
initializeThread: activities.initializeThread,
|
|
587
|
-
appendHumanMessage: activities.appendHumanMessage,
|
|
588
|
-
appendToolResult: activities.appendToolResult,
|
|
589
|
-
appendSystemMessage: activities.appendSystemMessage
|
|
590
|
-
};
|
|
591
674
|
}
|
|
592
675
|
|
|
593
676
|
// src/lib/types.ts
|
|
677
|
+
var agentQueryName = (agentName) => `get${agentName}State`;
|
|
678
|
+
var agentStateChangeUpdateName = (agentName) => `waitFor${agentName}StateChange`;
|
|
594
679
|
function isTerminalStatus(status) {
|
|
595
680
|
return status === "COMPLETED" || status === "FAILED" || status === "CANCELLED";
|
|
596
681
|
}
|
|
597
682
|
function createAgentStateManager({
|
|
598
683
|
initialState,
|
|
599
|
-
|
|
684
|
+
agentName
|
|
600
685
|
}) {
|
|
601
686
|
let status = initialState?.status ?? "RUNNING";
|
|
602
687
|
let version = initialState?.version ?? 0;
|
|
@@ -607,6 +692,7 @@ function createAgentStateManager({
|
|
|
607
692
|
let totalCachedWriteTokens = 0;
|
|
608
693
|
let totalCachedReadTokens = 0;
|
|
609
694
|
let totalReasonTokens = 0;
|
|
695
|
+
let systemPrompt = initialState?.systemPrompt;
|
|
610
696
|
const tasks = new Map(initialState?.tasks);
|
|
611
697
|
const {
|
|
612
698
|
status: _,
|
|
@@ -626,28 +712,32 @@ function createAgentStateManager({
|
|
|
626
712
|
...customState
|
|
627
713
|
};
|
|
628
714
|
}
|
|
629
|
-
workflow.
|
|
715
|
+
const stateQuery = workflow.defineQuery(
|
|
716
|
+
agentQueryName(agentName)
|
|
717
|
+
);
|
|
718
|
+
const stateChangeUpdate = workflow.defineUpdate(
|
|
719
|
+
agentStateChangeUpdateName(agentName)
|
|
720
|
+
);
|
|
721
|
+
workflow.setHandler(stateQuery, () => buildState());
|
|
722
|
+
workflow.setHandler(stateChangeUpdate, async (lastKnownVersion) => {
|
|
723
|
+
await workflow.condition(
|
|
724
|
+
() => version > lastKnownVersion || isTerminalStatus(status),
|
|
725
|
+
"55s"
|
|
726
|
+
);
|
|
630
727
|
return buildState();
|
|
631
728
|
});
|
|
632
|
-
workflow.setHandler(
|
|
633
|
-
workflow.defineUpdate(
|
|
634
|
-
`waitFor${agentConfig.agentName}StateChange`
|
|
635
|
-
),
|
|
636
|
-
async (lastKnownVersion) => {
|
|
637
|
-
await workflow.condition(
|
|
638
|
-
() => version > lastKnownVersion || isTerminalStatus(status),
|
|
639
|
-
"55s"
|
|
640
|
-
);
|
|
641
|
-
return buildState();
|
|
642
|
-
}
|
|
643
|
-
);
|
|
644
729
|
return {
|
|
730
|
+
stateQuery,
|
|
731
|
+
stateChangeUpdate,
|
|
645
732
|
getStatus() {
|
|
646
733
|
return status;
|
|
647
734
|
},
|
|
648
735
|
isRunning() {
|
|
649
736
|
return status === "RUNNING";
|
|
650
737
|
},
|
|
738
|
+
getSystemPrompt() {
|
|
739
|
+
return systemPrompt;
|
|
740
|
+
},
|
|
651
741
|
isTerminal() {
|
|
652
742
|
return isTerminalStatus(status);
|
|
653
743
|
},
|
|
@@ -710,11 +800,14 @@ function createAgentStateManager({
|
|
|
710
800
|
tools = newTools.map((tool) => ({
|
|
711
801
|
name: tool.name,
|
|
712
802
|
description: tool.description,
|
|
713
|
-
schema:
|
|
803
|
+
schema: z14.z.toJSONSchema(tool.schema),
|
|
714
804
|
strict: tool.strict,
|
|
715
805
|
max_uses: tool.max_uses
|
|
716
806
|
}));
|
|
717
807
|
},
|
|
808
|
+
setSystemPrompt(newSystemPrompt) {
|
|
809
|
+
systemPrompt = newSystemPrompt;
|
|
810
|
+
},
|
|
718
811
|
deleteTask(id) {
|
|
719
812
|
const deleted = tasks.delete(id);
|
|
720
813
|
if (deleted) {
|
|
@@ -741,11 +834,79 @@ function createAgentStateManager({
|
|
|
741
834
|
}
|
|
742
835
|
};
|
|
743
836
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
837
|
+
|
|
838
|
+
// src/lib/skills/parse.ts
|
|
839
|
+
function parseSkillFile(raw) {
|
|
840
|
+
const trimmed = raw.replace(/^\uFEFF/, "");
|
|
841
|
+
const match = trimmed.match(/^---[ \t]*\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/);
|
|
842
|
+
if (!match) {
|
|
843
|
+
throw new Error(
|
|
844
|
+
"SKILL.md must start with YAML frontmatter delimited by ---"
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
const [, yamlBlock, body] = match;
|
|
848
|
+
const frontmatter = parseSimpleYaml(yamlBlock);
|
|
849
|
+
if (!frontmatter.name || typeof frontmatter.name !== "string") {
|
|
850
|
+
throw new Error("SKILL.md frontmatter must include a 'name' field");
|
|
851
|
+
}
|
|
852
|
+
if (!frontmatter.description || typeof frontmatter.description !== "string") {
|
|
853
|
+
throw new Error("SKILL.md frontmatter must include a 'description' field");
|
|
854
|
+
}
|
|
855
|
+
const result = {
|
|
856
|
+
name: frontmatter.name,
|
|
857
|
+
description: frontmatter.description
|
|
858
|
+
};
|
|
859
|
+
if (frontmatter.license) result.license = String(frontmatter.license);
|
|
860
|
+
if (frontmatter.compatibility)
|
|
861
|
+
result.compatibility = String(frontmatter.compatibility);
|
|
862
|
+
if (frontmatter["allowed-tools"]) {
|
|
863
|
+
result.allowedTools = String(frontmatter["allowed-tools"]).split(/\s+/).filter(Boolean);
|
|
864
|
+
}
|
|
865
|
+
if (frontmatter.metadata && typeof frontmatter.metadata === "object" && !Array.isArray(frontmatter.metadata)) {
|
|
866
|
+
result.metadata = frontmatter.metadata;
|
|
867
|
+
}
|
|
868
|
+
return { frontmatter: result, body: body.trim() };
|
|
869
|
+
}
|
|
870
|
+
function parseSimpleYaml(yaml) {
|
|
871
|
+
const result = {};
|
|
872
|
+
const lines = yaml.split(/\r?\n/);
|
|
873
|
+
let currentMapKey = null;
|
|
874
|
+
let currentMap = null;
|
|
875
|
+
for (const line of lines) {
|
|
876
|
+
if (line.trim() === "" || line.trim().startsWith("#")) continue;
|
|
877
|
+
const nestedMatch = line.match(/^(\s{2,}|\t+)(\S+)\s*:\s*(.*)$/);
|
|
878
|
+
if (nestedMatch && currentMapKey && currentMap) {
|
|
879
|
+
const [, , key2, rawVal2] = nestedMatch;
|
|
880
|
+
currentMap[key2] = unquote(rawVal2.trim());
|
|
881
|
+
continue;
|
|
882
|
+
}
|
|
883
|
+
if (currentMapKey && currentMap) {
|
|
884
|
+
result[currentMapKey] = currentMap;
|
|
885
|
+
currentMapKey = null;
|
|
886
|
+
currentMap = null;
|
|
887
|
+
}
|
|
888
|
+
const topMatch = line.match(/^(\S+)\s*:\s*(.*)$/);
|
|
889
|
+
if (!topMatch) continue;
|
|
890
|
+
const [, key, rawVal] = topMatch;
|
|
891
|
+
const val = rawVal.trim();
|
|
892
|
+
if (val === "" || val === "|" || val === ">") {
|
|
893
|
+
currentMapKey = key;
|
|
894
|
+
currentMap = {};
|
|
895
|
+
} else {
|
|
896
|
+
result[key] = unquote(val);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if (currentMapKey && currentMap) {
|
|
900
|
+
result[currentMapKey] = currentMap;
|
|
901
|
+
}
|
|
902
|
+
return result;
|
|
903
|
+
}
|
|
904
|
+
function unquote(s) {
|
|
905
|
+
if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
|
|
906
|
+
return s.slice(1, -1);
|
|
907
|
+
}
|
|
908
|
+
return s;
|
|
909
|
+
}
|
|
749
910
|
var globTool = {
|
|
750
911
|
name: "Glob",
|
|
751
912
|
description: `Search for files matching a glob pattern within the available file system.
|
|
@@ -760,9 +921,9 @@ Examples:
|
|
|
760
921
|
- "**/*.test.ts" - Find all test files recursively
|
|
761
922
|
- "src/**/*.ts" - Find all TypeScript files in src directory
|
|
762
923
|
`,
|
|
763
|
-
schema:
|
|
764
|
-
pattern:
|
|
765
|
-
root:
|
|
924
|
+
schema: z14.z.object({
|
|
925
|
+
pattern: z14.z.string().describe("Glob pattern to match files against"),
|
|
926
|
+
root: z14.z.string().optional().describe("Optional root directory to search from")
|
|
766
927
|
}),
|
|
767
928
|
strict: true
|
|
768
929
|
};
|
|
@@ -780,13 +941,13 @@ Examples:
|
|
|
780
941
|
- Search for function definitions with "function.*handleClick"
|
|
781
942
|
- Search case-insensitively with ignoreCase: true
|
|
782
943
|
`,
|
|
783
|
-
schema:
|
|
784
|
-
pattern:
|
|
785
|
-
ignoreCase:
|
|
786
|
-
maxMatches:
|
|
787
|
-
includePatterns:
|
|
788
|
-
excludePatterns:
|
|
789
|
-
contextLines:
|
|
944
|
+
schema: z14.z.object({
|
|
945
|
+
pattern: z14.z.string().describe("Regex pattern to search for in file contents"),
|
|
946
|
+
ignoreCase: z14.z.boolean().optional().describe("Case-insensitive search (default: false)"),
|
|
947
|
+
maxMatches: z14.z.number().optional().describe("Maximum number of matches to return (default: 50)"),
|
|
948
|
+
includePatterns: z14.z.array(z14.z.string()).optional().describe("Glob patterns to include (e.g., ['*.ts', '*.js'])"),
|
|
949
|
+
excludePatterns: z14.z.array(z14.z.string()).optional().describe("Glob patterns to exclude (e.g., ['*.test.ts'])"),
|
|
950
|
+
contextLines: z14.z.number().optional().describe("Number of context lines to show around matches")
|
|
790
951
|
}),
|
|
791
952
|
strict: true
|
|
792
953
|
};
|
|
@@ -804,12 +965,12 @@ The tool returns the file content in an appropriate format:
|
|
|
804
965
|
- Images: Base64-encoded image data
|
|
805
966
|
- PDFs: Extracted text content
|
|
806
967
|
`,
|
|
807
|
-
schema:
|
|
808
|
-
path:
|
|
809
|
-
offset:
|
|
968
|
+
schema: z14.z.object({
|
|
969
|
+
path: z14.z.string().describe("Virtual path to the file to read"),
|
|
970
|
+
offset: z14.z.number().optional().describe(
|
|
810
971
|
"Line number to start reading from (1-indexed, for text files)"
|
|
811
972
|
),
|
|
812
|
-
limit:
|
|
973
|
+
limit: z14.z.number().optional().describe("Maximum number of lines to read (for text files)")
|
|
813
974
|
}),
|
|
814
975
|
strict: true
|
|
815
976
|
};
|
|
@@ -826,9 +987,9 @@ IMPORTANT:
|
|
|
826
987
|
- This is an atomic write operation - the entire file is replaced
|
|
827
988
|
- Path must be relative to the root of the file system (e.g., "docs/readme.md", not "/docs/readme.md")
|
|
828
989
|
`,
|
|
829
|
-
schema:
|
|
830
|
-
file_path:
|
|
831
|
-
content:
|
|
990
|
+
schema: z14.z.object({
|
|
991
|
+
file_path: z14.z.string().describe("The path to the file to write"),
|
|
992
|
+
content: z14.z.string().describe("The content to write to the file")
|
|
832
993
|
}),
|
|
833
994
|
strict: true
|
|
834
995
|
};
|
|
@@ -848,13 +1009,13 @@ IMPORTANT:
|
|
|
848
1009
|
- The operation fails if old_string is not found
|
|
849
1010
|
- old_string and new_string must be different
|
|
850
1011
|
`,
|
|
851
|
-
schema:
|
|
852
|
-
file_path:
|
|
853
|
-
old_string:
|
|
854
|
-
new_string:
|
|
1012
|
+
schema: z14.z.object({
|
|
1013
|
+
file_path: z14.z.string().describe("The absolute virtual path to the file to modify"),
|
|
1014
|
+
old_string: z14.z.string().describe("The exact text to replace"),
|
|
1015
|
+
new_string: z14.z.string().describe(
|
|
855
1016
|
"The text to replace it with (must be different from old_string)"
|
|
856
1017
|
),
|
|
857
|
-
replace_all:
|
|
1018
|
+
replace_all: z14.z.boolean().optional().describe(
|
|
858
1019
|
"If true, replace all occurrences of old_string (default: false)"
|
|
859
1020
|
)
|
|
860
1021
|
}),
|
|
@@ -862,7 +1023,7 @@ IMPORTANT:
|
|
|
862
1023
|
};
|
|
863
1024
|
var taskCreateTool = {
|
|
864
1025
|
name: "TaskCreate",
|
|
865
|
-
description: `Use this tool to create a structured task list
|
|
1026
|
+
description: `Use this tool to create a structured task list. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
|
|
866
1027
|
It also helps the user understand the progress of the task and overall progress of their requests.
|
|
867
1028
|
|
|
868
1029
|
## When to Use This Tool
|
|
@@ -901,17 +1062,17 @@ var taskCreateTool = {
|
|
|
901
1062
|
- Include enough detail in the description for another agent to understand and complete the task
|
|
902
1063
|
- After creating tasks, use TaskUpdate to set up dependencies (blocks/blockedBy) if needed
|
|
903
1064
|
- Check TaskList first to avoid creating duplicate tasks`,
|
|
904
|
-
schema:
|
|
905
|
-
subject:
|
|
1065
|
+
schema: z14__default.default.object({
|
|
1066
|
+
subject: z14__default.default.string().describe(
|
|
906
1067
|
'A brief, actionable title in imperative form (e.g., "Fix authentication bug in login flow")'
|
|
907
1068
|
),
|
|
908
|
-
description:
|
|
1069
|
+
description: z14__default.default.string().describe(
|
|
909
1070
|
"Detailed description of what needs to be done, including context and acceptance criteria"
|
|
910
1071
|
),
|
|
911
|
-
activeForm:
|
|
1072
|
+
activeForm: z14__default.default.string().describe(
|
|
912
1073
|
'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.'
|
|
913
1074
|
),
|
|
914
|
-
metadata:
|
|
1075
|
+
metadata: z14__default.default.record(z14__default.default.string(), z14__default.default.string()).describe("Arbitrary key-value pairs for tracking")
|
|
915
1076
|
})
|
|
916
1077
|
};
|
|
917
1078
|
function createTaskCreateHandler(stateManager) {
|
|
@@ -936,8 +1097,8 @@ function createTaskCreateHandler(stateManager) {
|
|
|
936
1097
|
var taskGetTool = {
|
|
937
1098
|
name: "TaskGet",
|
|
938
1099
|
description: `Retrieve full task details including dependencies.`,
|
|
939
|
-
schema:
|
|
940
|
-
taskId:
|
|
1100
|
+
schema: z14__default.default.object({
|
|
1101
|
+
taskId: z14__default.default.string().describe("The ID of the task to get")
|
|
941
1102
|
})
|
|
942
1103
|
};
|
|
943
1104
|
|
|
@@ -960,7 +1121,7 @@ function createTaskGetHandler(stateManager) {
|
|
|
960
1121
|
var taskListTool = {
|
|
961
1122
|
name: "TaskList",
|
|
962
1123
|
description: `List all tasks with current state.`,
|
|
963
|
-
schema:
|
|
1124
|
+
schema: z14__default.default.object({})
|
|
964
1125
|
};
|
|
965
1126
|
|
|
966
1127
|
// src/tools/task-list/handler.ts
|
|
@@ -976,11 +1137,11 @@ function createTaskListHandler(stateManager) {
|
|
|
976
1137
|
var taskUpdateTool = {
|
|
977
1138
|
name: "TaskUpdate",
|
|
978
1139
|
description: `Update status, add blockers, modify details.`,
|
|
979
|
-
schema:
|
|
980
|
-
taskId:
|
|
981
|
-
status:
|
|
982
|
-
addBlockedBy:
|
|
983
|
-
addBlocks:
|
|
1140
|
+
schema: z14__default.default.object({
|
|
1141
|
+
taskId: z14__default.default.string().describe("The ID of the task to get"),
|
|
1142
|
+
status: z14__default.default.enum(["pending", "in_progress", "completed"]).describe("The status of the task"),
|
|
1143
|
+
addBlockedBy: z14__default.default.array(z14__default.default.string()).describe("The IDs of the tasks that are blocking this task"),
|
|
1144
|
+
addBlocks: z14__default.default.array(z14__default.default.string()).describe("The IDs of the tasks that this task is blocking")
|
|
984
1145
|
})
|
|
985
1146
|
};
|
|
986
1147
|
|
|
@@ -1048,8 +1209,8 @@ Use this tool to:
|
|
|
1048
1209
|
- Execute scripts and chain commands with pipes (|) or logical operators (&&, ||)
|
|
1049
1210
|
- Inspect files and directories
|
|
1050
1211
|
`,
|
|
1051
|
-
schema:
|
|
1052
|
-
command:
|
|
1212
|
+
schema: z14__default.default.object({
|
|
1213
|
+
command: z14__default.default.string().describe(
|
|
1053
1214
|
"The bash command to execute. Can include pipes (|), redirects (>, >>), logical operators (&&, ||), and shell features like command substitution $(...)."
|
|
1054
1215
|
)
|
|
1055
1216
|
}),
|
|
@@ -1070,18 +1231,18 @@ Usage notes:
|
|
|
1070
1231
|
* Use multiSelect: true to allow multiple answers to be selected for a question
|
|
1071
1232
|
* If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label
|
|
1072
1233
|
`,
|
|
1073
|
-
schema:
|
|
1074
|
-
questions:
|
|
1075
|
-
|
|
1076
|
-
question:
|
|
1077
|
-
header:
|
|
1078
|
-
options:
|
|
1079
|
-
|
|
1080
|
-
label:
|
|
1081
|
-
description:
|
|
1234
|
+
schema: z14__default.default.object({
|
|
1235
|
+
questions: z14__default.default.array(
|
|
1236
|
+
z14__default.default.object({
|
|
1237
|
+
question: z14__default.default.string().describe("The full question text to display"),
|
|
1238
|
+
header: z14__default.default.string().describe("Short label for the question (max 12 characters)"),
|
|
1239
|
+
options: z14__default.default.array(
|
|
1240
|
+
z14__default.default.object({
|
|
1241
|
+
label: z14__default.default.string(),
|
|
1242
|
+
description: z14__default.default.string()
|
|
1082
1243
|
})
|
|
1083
1244
|
).min(0).max(4).describe("Array of 0-4 choices, each with label and description"),
|
|
1084
|
-
multiSelect:
|
|
1245
|
+
multiSelect: z14__default.default.boolean().describe("If true, users can select multiple options")
|
|
1085
1246
|
})
|
|
1086
1247
|
)
|
|
1087
1248
|
}),
|
|
@@ -1096,49 +1257,19 @@ var createAskUserQuestionHandler = () => async (args) => {
|
|
|
1096
1257
|
};
|
|
1097
1258
|
};
|
|
1098
1259
|
|
|
1099
|
-
// node_modules/uuid/dist/esm-node/stringify.js
|
|
1100
|
-
var byteToHex = [];
|
|
1101
|
-
for (let i = 0; i < 256; ++i) {
|
|
1102
|
-
byteToHex.push((i + 256).toString(16).slice(1));
|
|
1103
|
-
}
|
|
1104
|
-
function unsafeStringify(arr, offset = 0) {
|
|
1105
|
-
return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
|
|
1106
|
-
}
|
|
1107
|
-
var rnds8Pool = new Uint8Array(256);
|
|
1108
|
-
var poolPtr = rnds8Pool.length;
|
|
1109
|
-
function rng() {
|
|
1110
|
-
if (poolPtr > rnds8Pool.length - 16) {
|
|
1111
|
-
crypto__default.default.randomFillSync(rnds8Pool);
|
|
1112
|
-
poolPtr = 0;
|
|
1113
|
-
}
|
|
1114
|
-
return rnds8Pool.slice(poolPtr, poolPtr += 16);
|
|
1115
|
-
}
|
|
1116
|
-
var native_default = {
|
|
1117
|
-
randomUUID: crypto__default.default.randomUUID
|
|
1118
|
-
};
|
|
1119
|
-
|
|
1120
|
-
// node_modules/uuid/dist/esm-node/v4.js
|
|
1121
|
-
function v4(options, buf, offset) {
|
|
1122
|
-
if (native_default.randomUUID && !buf && !options) {
|
|
1123
|
-
return native_default.randomUUID();
|
|
1124
|
-
}
|
|
1125
|
-
options = options || {};
|
|
1126
|
-
const rnds = options.random || (options.rng || rng)();
|
|
1127
|
-
rnds[6] = rnds[6] & 15 | 64;
|
|
1128
|
-
rnds[8] = rnds[8] & 63 | 128;
|
|
1129
|
-
if (buf) {
|
|
1130
|
-
offset = offset || 0;
|
|
1131
|
-
for (let i = 0; i < 16; ++i) {
|
|
1132
|
-
buf[offset + i] = rnds[i];
|
|
1133
|
-
}
|
|
1134
|
-
return buf;
|
|
1135
|
-
}
|
|
1136
|
-
return unsafeStringify(rnds);
|
|
1137
|
-
}
|
|
1138
|
-
var v4_default = v4;
|
|
1139
|
-
|
|
1140
1260
|
// src/lib/thread-manager.ts
|
|
1141
1261
|
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
1262
|
+
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
1263
|
+
if redis.call('EXISTS', KEYS[1]) == 1 then
|
|
1264
|
+
return 0
|
|
1265
|
+
end
|
|
1266
|
+
for i = 2, #ARGV do
|
|
1267
|
+
redis.call('RPUSH', KEYS[2], ARGV[i])
|
|
1268
|
+
end
|
|
1269
|
+
redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
1270
|
+
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
1271
|
+
return 1
|
|
1272
|
+
`;
|
|
1142
1273
|
function getThreadKey(threadId, key) {
|
|
1143
1274
|
return `thread:${threadId}:${key}`;
|
|
1144
1275
|
}
|
|
@@ -1148,152 +1279,66 @@ function createThreadManager(config) {
|
|
|
1148
1279
|
threadId,
|
|
1149
1280
|
key = "messages",
|
|
1150
1281
|
serialize = (m) => JSON.stringify(m),
|
|
1151
|
-
deserialize = (raw) => JSON.parse(raw)
|
|
1282
|
+
deserialize = (raw) => JSON.parse(raw),
|
|
1283
|
+
idOf
|
|
1152
1284
|
} = config;
|
|
1153
1285
|
const redisKey = getThreadKey(threadId, key);
|
|
1154
|
-
const
|
|
1286
|
+
const metaKey = getThreadKey(threadId, `${key}:meta`);
|
|
1287
|
+
async function assertThreadExists() {
|
|
1288
|
+
const exists = await redis.exists(metaKey);
|
|
1289
|
+
if (!exists) {
|
|
1290
|
+
throw new Error(`Thread "${threadId}" (key: ${key}) does not exist`);
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
return {
|
|
1155
1294
|
async initialize() {
|
|
1156
1295
|
await redis.del(redisKey);
|
|
1296
|
+
await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
|
|
1157
1297
|
},
|
|
1158
1298
|
async load() {
|
|
1299
|
+
await assertThreadExists();
|
|
1159
1300
|
const data = await redis.lrange(redisKey, 0, -1);
|
|
1160
1301
|
return data.map(deserialize);
|
|
1161
1302
|
},
|
|
1162
1303
|
async append(messages) {
|
|
1163
|
-
if (messages.length
|
|
1304
|
+
if (messages.length === 0) return;
|
|
1305
|
+
await assertThreadExists();
|
|
1306
|
+
if (idOf) {
|
|
1307
|
+
const dedupId = messages.map(idOf).join(":");
|
|
1308
|
+
const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
|
|
1309
|
+
await redis.eval(
|
|
1310
|
+
APPEND_IDEMPOTENT_SCRIPT,
|
|
1311
|
+
2,
|
|
1312
|
+
dedupKey,
|
|
1313
|
+
redisKey,
|
|
1314
|
+
String(THREAD_TTL_SECONDS),
|
|
1315
|
+
...messages.map(serialize)
|
|
1316
|
+
);
|
|
1317
|
+
} else {
|
|
1164
1318
|
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
1165
1319
|
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
1166
1320
|
}
|
|
1167
1321
|
},
|
|
1168
1322
|
async delete() {
|
|
1169
|
-
await redis.del(redisKey);
|
|
1170
|
-
}
|
|
1171
|
-
};
|
|
1172
|
-
const helpers = {
|
|
1173
|
-
createHumanMessage(content) {
|
|
1174
|
-
return new messages.HumanMessage({
|
|
1175
|
-
id: v4_default(),
|
|
1176
|
-
content
|
|
1177
|
-
}).toDict();
|
|
1178
|
-
},
|
|
1179
|
-
createSystemMessage(content) {
|
|
1180
|
-
return new messages.SystemMessage({
|
|
1181
|
-
id: v4_default(),
|
|
1182
|
-
content
|
|
1183
|
-
}).toDict();
|
|
1184
|
-
},
|
|
1185
|
-
createAIMessage(content, kwargs) {
|
|
1186
|
-
return new messages.AIMessage({
|
|
1187
|
-
id: v4_default(),
|
|
1188
|
-
content,
|
|
1189
|
-
additional_kwargs: kwargs ? {
|
|
1190
|
-
header: kwargs.header,
|
|
1191
|
-
options: kwargs.options,
|
|
1192
|
-
multiSelect: kwargs.multiSelect
|
|
1193
|
-
} : void 0
|
|
1194
|
-
}).toDict();
|
|
1195
|
-
},
|
|
1196
|
-
createToolMessage(content, toolCallId) {
|
|
1197
|
-
return new messages.ToolMessage({
|
|
1198
|
-
content,
|
|
1199
|
-
tool_call_id: toolCallId
|
|
1200
|
-
}).toDict();
|
|
1201
|
-
},
|
|
1202
|
-
async appendHumanMessage(content) {
|
|
1203
|
-
const message = helpers.createHumanMessage(content);
|
|
1204
|
-
await base.append([message]);
|
|
1205
|
-
},
|
|
1206
|
-
async appendToolMessage(content, toolCallId) {
|
|
1207
|
-
const message = helpers.createToolMessage(content, toolCallId);
|
|
1208
|
-
await base.append([message]);
|
|
1209
|
-
},
|
|
1210
|
-
async appendAIMessage(content) {
|
|
1211
|
-
const message = helpers.createAIMessage(content);
|
|
1212
|
-
await base.append([message]);
|
|
1213
|
-
},
|
|
1214
|
-
async appendSystemMessage(content) {
|
|
1215
|
-
const message = helpers.createSystemMessage(content);
|
|
1216
|
-
await base.append([message]);
|
|
1323
|
+
await redis.del(redisKey, metaKey);
|
|
1217
1324
|
}
|
|
1218
1325
|
};
|
|
1219
|
-
return Object.assign(base, helpers);
|
|
1220
1326
|
}
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
const { threadId, toolCallId, content } = config;
|
|
1227
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1228
|
-
await thread.appendToolMessage(content, toolCallId);
|
|
1229
|
-
},
|
|
1230
|
-
async initializeThread(threadId) {
|
|
1231
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1232
|
-
await thread.initialize();
|
|
1233
|
-
},
|
|
1234
|
-
async appendThreadMessages(threadId, messages) {
|
|
1235
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1236
|
-
await thread.append(messages);
|
|
1237
|
-
},
|
|
1238
|
-
async appendHumanMessage(threadId, content) {
|
|
1239
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1240
|
-
await thread.appendHumanMessage(content);
|
|
1241
|
-
},
|
|
1242
|
-
async appendSystemMessage(threadId, content) {
|
|
1243
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1244
|
-
await thread.appendSystemMessage(content);
|
|
1245
|
-
}
|
|
1246
|
-
};
|
|
1247
|
-
}
|
|
1248
|
-
|
|
1249
|
-
// src/plugin.ts
|
|
1250
|
-
var ZeitlichPlugin = class extends plugin.SimplePlugin {
|
|
1251
|
-
constructor(options) {
|
|
1252
|
-
super({
|
|
1253
|
-
name: "ZeitlichPlugin",
|
|
1254
|
-
activities: createSharedActivities(options.redis)
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
};
|
|
1258
|
-
async function invokeModel({
|
|
1259
|
-
redis,
|
|
1260
|
-
model,
|
|
1261
|
-
client,
|
|
1262
|
-
config: { threadId, agentName }
|
|
1263
|
-
}) {
|
|
1264
|
-
const thread = createThreadManager({ redis, threadId });
|
|
1265
|
-
const runId = v4_default();
|
|
1266
|
-
const info = activity.Context.current().info;
|
|
1267
|
-
const parentWorkflowId = info.workflowExecution.workflowId;
|
|
1268
|
-
const parentRunId = info.workflowExecution.runId;
|
|
1269
|
-
const handle = client.getHandle(parentWorkflowId, parentRunId);
|
|
1270
|
-
const { tools } = await handle.query(`get${agentName}State`);
|
|
1271
|
-
const messages$1 = await thread.load();
|
|
1272
|
-
const response = await model.invoke(
|
|
1273
|
-
[...messages.mapStoredMessagesToChatMessages(messages$1)],
|
|
1274
|
-
{
|
|
1275
|
-
runName: agentName,
|
|
1276
|
-
runId,
|
|
1277
|
-
metadata: { thread_id: threadId },
|
|
1278
|
-
tools
|
|
1279
|
-
}
|
|
1327
|
+
async function queryParentWorkflowState(client, queryName) {
|
|
1328
|
+
const { workflowExecution } = activity.Context.current().info;
|
|
1329
|
+
const handle = client.getHandle(
|
|
1330
|
+
workflowExecution.workflowId,
|
|
1331
|
+
workflowExecution.runId
|
|
1280
1332
|
);
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
})
|
|
1290
|
-
usage: {
|
|
1291
|
-
inputTokens: response.usage_metadata?.input_tokens,
|
|
1292
|
-
outputTokens: response.usage_metadata?.output_tokens,
|
|
1293
|
-
reasonTokens: response.usage_metadata?.output_token_details?.reasoning,
|
|
1294
|
-
cachedWriteTokens: response.usage_metadata?.input_token_details?.cache_creation,
|
|
1295
|
-
cachedReadTokens: response.usage_metadata?.input_token_details?.cache_read
|
|
1296
|
-
}
|
|
1333
|
+
return handle.query(queryName);
|
|
1334
|
+
}
|
|
1335
|
+
function createRunAgentActivity(client, invoker) {
|
|
1336
|
+
return async (config) => {
|
|
1337
|
+
const state = await queryParentWorkflowState(
|
|
1338
|
+
client,
|
|
1339
|
+
agentQueryName(config.agentName)
|
|
1340
|
+
);
|
|
1341
|
+
return invoker({ ...config, state });
|
|
1297
1342
|
};
|
|
1298
1343
|
}
|
|
1299
1344
|
function createGlobHandler(fs) {
|
|
@@ -1464,9 +1509,65 @@ var toTree = async (fs, opts = {}) => {
|
|
|
1464
1509
|
const base = basename(dir, separator) + separator;
|
|
1465
1510
|
return base + subtree;
|
|
1466
1511
|
};
|
|
1512
|
+
var FileSystemSkillProvider = class {
|
|
1513
|
+
constructor(baseDir) {
|
|
1514
|
+
this.baseDir = baseDir;
|
|
1515
|
+
}
|
|
1516
|
+
async listSkills() {
|
|
1517
|
+
const dirs = await this.discoverSkillDirs();
|
|
1518
|
+
const skills = [];
|
|
1519
|
+
for (const dir of dirs) {
|
|
1520
|
+
const raw = await promises.readFile(path.join(this.baseDir, dir, "SKILL.md"), "utf-8");
|
|
1521
|
+
const { frontmatter } = parseSkillFile(raw);
|
|
1522
|
+
skills.push(frontmatter);
|
|
1523
|
+
}
|
|
1524
|
+
return skills;
|
|
1525
|
+
}
|
|
1526
|
+
async getSkill(name) {
|
|
1527
|
+
const raw = await promises.readFile(
|
|
1528
|
+
path.join(this.baseDir, name, "SKILL.md"),
|
|
1529
|
+
"utf-8"
|
|
1530
|
+
);
|
|
1531
|
+
const { frontmatter, body } = parseSkillFile(raw);
|
|
1532
|
+
if (frontmatter.name !== name) {
|
|
1533
|
+
throw new Error(
|
|
1534
|
+
`Skill directory "${name}" contains SKILL.md with mismatched name "${frontmatter.name}"`
|
|
1535
|
+
);
|
|
1536
|
+
}
|
|
1537
|
+
return { ...frontmatter, instructions: body };
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Convenience method to load all skills with full instructions.
|
|
1541
|
+
* Returns `Skill[]` ready to pass into a workflow.
|
|
1542
|
+
*/
|
|
1543
|
+
async loadAll() {
|
|
1544
|
+
const dirs = await this.discoverSkillDirs();
|
|
1545
|
+
const skills = [];
|
|
1546
|
+
for (const dir of dirs) {
|
|
1547
|
+
const raw = await promises.readFile(path.join(this.baseDir, dir, "SKILL.md"), "utf-8");
|
|
1548
|
+
const { frontmatter, body } = parseSkillFile(raw);
|
|
1549
|
+
skills.push({ ...frontmatter, instructions: body });
|
|
1550
|
+
}
|
|
1551
|
+
return skills;
|
|
1552
|
+
}
|
|
1553
|
+
async discoverSkillDirs() {
|
|
1554
|
+
const entries = await promises.readdir(this.baseDir, { withFileTypes: true });
|
|
1555
|
+
const dirs = [];
|
|
1556
|
+
for (const entry of entries) {
|
|
1557
|
+
if (!entry.isDirectory()) continue;
|
|
1558
|
+
try {
|
|
1559
|
+
await promises.readFile(path.join(this.baseDir, entry.name, "SKILL.md"), "utf-8");
|
|
1560
|
+
dirs.push(entry.name);
|
|
1561
|
+
} catch {
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
return dirs;
|
|
1565
|
+
}
|
|
1566
|
+
};
|
|
1467
1567
|
|
|
1468
|
-
exports.
|
|
1469
|
-
exports.
|
|
1568
|
+
exports.FileSystemSkillProvider = FileSystemSkillProvider;
|
|
1569
|
+
exports.agentQueryName = agentQueryName;
|
|
1570
|
+
exports.agentStateChangeUpdateName = agentStateChangeUpdateName;
|
|
1470
1571
|
exports.askUserQuestionTool = askUserQuestionTool;
|
|
1471
1572
|
exports.bashTool = bashTool;
|
|
1472
1573
|
exports.createAgentStateManager = createAgentStateManager;
|
|
@@ -1475,8 +1576,10 @@ exports.createBashHandler = createBashHandler;
|
|
|
1475
1576
|
exports.createBashToolDescription = createBashToolDescription;
|
|
1476
1577
|
exports.createEditHandler = createEditHandler;
|
|
1477
1578
|
exports.createGlobHandler = createGlobHandler;
|
|
1579
|
+
exports.createReadSkillHandler = createReadSkillHandler;
|
|
1580
|
+
exports.createReadSkillTool = createReadSkillTool;
|
|
1581
|
+
exports.createRunAgentActivity = createRunAgentActivity;
|
|
1478
1582
|
exports.createSession = createSession;
|
|
1479
|
-
exports.createSharedActivities = createSharedActivities;
|
|
1480
1583
|
exports.createSubagentTool = createSubagentTool;
|
|
1481
1584
|
exports.createTaskCreateHandler = createTaskCreateHandler;
|
|
1482
1585
|
exports.createTaskGetHandler = createTaskGetHandler;
|
|
@@ -1487,12 +1590,14 @@ exports.createToolRouter = createToolRouter;
|
|
|
1487
1590
|
exports.defineSubagent = defineSubagent;
|
|
1488
1591
|
exports.defineTool = defineTool;
|
|
1489
1592
|
exports.editTool = editTool;
|
|
1593
|
+
exports.getShortId = getShortId;
|
|
1490
1594
|
exports.globTool = globTool;
|
|
1491
1595
|
exports.grepTool = grepTool;
|
|
1492
1596
|
exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
|
|
1493
|
-
exports.invokeModel = invokeModel;
|
|
1494
1597
|
exports.isTerminalStatus = isTerminalStatus;
|
|
1598
|
+
exports.parseSkillFile = parseSkillFile;
|
|
1495
1599
|
exports.proxyDefaultThreadOps = proxyDefaultThreadOps;
|
|
1600
|
+
exports.queryParentWorkflowState = queryParentWorkflowState;
|
|
1496
1601
|
exports.readFileTool = readFileTool;
|
|
1497
1602
|
exports.taskCreateTool = taskCreateTool;
|
|
1498
1603
|
exports.taskGetTool = taskGetTool;
|