zeitlich 0.2.6 → 0.2.8
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 +200 -119
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -11
- package/dist/index.d.ts +4 -11
- package/dist/index.js +179 -97
- package/dist/index.js.map +1 -1
- package/dist/{workflow-Dg5JMeOC.d.cts → workflow-BdAuMMjY.d.cts} +129 -37
- package/dist/{workflow-Dg5JMeOC.d.ts → workflow-BdAuMMjY.d.ts} +129 -37
- package/dist/workflow.cjs +195 -101
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +1 -1
- package/dist/workflow.d.ts +1 -1
- package/dist/workflow.js +172 -79
- package/dist/workflow.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +0 -2
- package/src/lib/model-invoker.ts +9 -6
- package/src/lib/session.ts +86 -15
- package/src/lib/state-manager.ts +84 -7
- package/src/lib/tool-router.ts +12 -10
- package/src/lib/types.ts +74 -11
- package/src/tools/ask-user-question/handler.ts +19 -20
- package/src/tools/subagent/handler.ts +2 -1
- package/src/workflow.ts +5 -3
package/src/lib/model-invoker.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type Redis from "ioredis";
|
|
2
2
|
import { createThreadManager } from "./thread-manager";
|
|
3
|
-
import type { AgentResponse } from "./types";
|
|
3
|
+
import type { AgentResponse, BaseAgentState } from "./types";
|
|
4
4
|
import { Context } from "@temporalio/activity";
|
|
5
5
|
import type { WorkflowClient } from "@temporalio/client";
|
|
6
6
|
import { mapStoredMessagesToChatMessages } from "@langchain/core/messages";
|
|
@@ -10,7 +10,6 @@ import type {
|
|
|
10
10
|
BaseChatModelCallOptions,
|
|
11
11
|
BindToolsInput,
|
|
12
12
|
} from "@langchain/core/language_models/chat_models";
|
|
13
|
-
import { getStateQuery } from "./state-manager";
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Configuration for invoking the model
|
|
@@ -49,7 +48,7 @@ export async function invokeModel({
|
|
|
49
48
|
const parentRunId = info.workflowExecution.runId;
|
|
50
49
|
|
|
51
50
|
const handle = client.getHandle(parentWorkflowId, parentRunId);
|
|
52
|
-
const { tools } = await handle.query(
|
|
51
|
+
const { tools } = await handle.query<BaseAgentState>(`get${agentName}State`);
|
|
53
52
|
|
|
54
53
|
const messages = await thread.load();
|
|
55
54
|
const response = await model.invoke(
|
|
@@ -74,9 +73,13 @@ export async function invokeModel({
|
|
|
74
73
|
args: tc.args,
|
|
75
74
|
})),
|
|
76
75
|
usage: {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
inputTokens: response.usage_metadata?.input_tokens,
|
|
77
|
+
outputTokens: response.usage_metadata?.output_tokens,
|
|
78
|
+
reasonTokens: response.usage_metadata?.output_token_details?.reasoning,
|
|
79
|
+
cachedWriteTokens:
|
|
80
|
+
response.usage_metadata?.input_token_details?.cache_creation,
|
|
81
|
+
cachedReadTokens:
|
|
82
|
+
response.usage_metadata?.input_token_details?.cache_read,
|
|
80
83
|
},
|
|
81
84
|
};
|
|
82
85
|
}
|
package/src/lib/session.ts
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
proxyActivities,
|
|
3
|
+
condition,
|
|
4
|
+
defineUpdate,
|
|
5
|
+
setHandler,
|
|
6
|
+
} from "@temporalio/workflow";
|
|
2
7
|
import type { ZeitlichSharedActivities } from "../activities";
|
|
3
8
|
import type {
|
|
4
9
|
ThreadOps,
|
|
5
|
-
|
|
10
|
+
AgentConfig,
|
|
6
11
|
SessionStartHook,
|
|
7
12
|
SessionEndHook,
|
|
8
13
|
SessionExitReason,
|
|
14
|
+
SessionConfig,
|
|
9
15
|
} from "./types";
|
|
10
16
|
import { type AgentStateManager, type JsonSerializable } from "./state-manager";
|
|
11
17
|
import {
|
|
@@ -13,11 +19,16 @@ import {
|
|
|
13
19
|
type ParsedToolCallUnion,
|
|
14
20
|
type ToolMap,
|
|
15
21
|
} from "./tool-router";
|
|
22
|
+
import type { MessageContent } from "@langchain/core/messages";
|
|
16
23
|
|
|
17
24
|
export interface ZeitlichSession<M = unknown> {
|
|
18
25
|
runSession<T extends JsonSerializable<T>>(args: {
|
|
19
26
|
stateManager: AgentStateManager<T>;
|
|
20
|
-
}): Promise<
|
|
27
|
+
}): Promise<{
|
|
28
|
+
finalMessage: M | null;
|
|
29
|
+
exitReason: SessionExitReason;
|
|
30
|
+
usage: ReturnType<AgentStateManager<T>["getTotalUsage"]>;
|
|
31
|
+
}>;
|
|
21
32
|
}
|
|
22
33
|
|
|
23
34
|
/**
|
|
@@ -33,6 +44,7 @@ export interface SessionLifecycleHooks {
|
|
|
33
44
|
export const createSession = async <T extends ToolMap, M = unknown>({
|
|
34
45
|
threadId,
|
|
35
46
|
agentName,
|
|
47
|
+
description,
|
|
36
48
|
maxTurns = 50,
|
|
37
49
|
metadata = {},
|
|
38
50
|
runAgent,
|
|
@@ -44,13 +56,15 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
44
56
|
hooks = {},
|
|
45
57
|
appendSystemPrompt = true,
|
|
46
58
|
systemPrompt,
|
|
47
|
-
|
|
59
|
+
waitForInputTimeout = "48h",
|
|
60
|
+
}: SessionConfig<T, M> & AgentConfig): Promise<ZeitlichSession<M>> => {
|
|
48
61
|
const {
|
|
49
62
|
appendToolResult,
|
|
50
63
|
appendHumanMessage,
|
|
51
64
|
initializeThread,
|
|
52
65
|
appendSystemMessage,
|
|
53
66
|
} = threadOps ?? proxyDefaultThreadOps();
|
|
67
|
+
|
|
54
68
|
const toolRouter = createToolRouter({
|
|
55
69
|
tools,
|
|
56
70
|
appendToolResult,
|
|
@@ -77,7 +91,33 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
77
91
|
};
|
|
78
92
|
|
|
79
93
|
return {
|
|
80
|
-
runSession: async ({
|
|
94
|
+
runSession: async ({
|
|
95
|
+
stateManager,
|
|
96
|
+
}): Promise<{
|
|
97
|
+
finalMessage: M | null;
|
|
98
|
+
exitReason: SessionExitReason;
|
|
99
|
+
usage: ReturnType<typeof stateManager.getTotalUsage>;
|
|
100
|
+
}> => {
|
|
101
|
+
setHandler(
|
|
102
|
+
defineUpdate<unknown, [MessageContent]>(`add${agentName}Message`),
|
|
103
|
+
async (message: MessageContent) => {
|
|
104
|
+
if (hooks.onPreHumanMessageAppend) {
|
|
105
|
+
await hooks.onPreHumanMessageAppend({
|
|
106
|
+
message,
|
|
107
|
+
threadId,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
await appendHumanMessage(threadId, message);
|
|
111
|
+
if (hooks.onPostHumanMessageAppend) {
|
|
112
|
+
await hooks.onPostHumanMessageAppend({
|
|
113
|
+
message,
|
|
114
|
+
threadId,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
stateManager.run();
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
81
121
|
if (hooks.onSessionStart) {
|
|
82
122
|
await hooks.onSessionStart({
|
|
83
123
|
threadId,
|
|
@@ -86,8 +126,6 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
86
126
|
});
|
|
87
127
|
}
|
|
88
128
|
|
|
89
|
-
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
90
|
-
|
|
91
129
|
await initializeThread(threadId);
|
|
92
130
|
if (appendSystemPrompt && systemPrompt && systemPrompt.trim() !== "") {
|
|
93
131
|
await appendSystemMessage(threadId, systemPrompt);
|
|
@@ -105,17 +143,29 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
105
143
|
stateManager.incrementTurns();
|
|
106
144
|
const currentTurn = stateManager.getTurns();
|
|
107
145
|
|
|
108
|
-
|
|
146
|
+
stateManager.setTools(toolRouter.getToolDefinitions());
|
|
147
|
+
|
|
148
|
+
const { message, rawToolCalls, usage } = await runAgent({
|
|
109
149
|
threadId,
|
|
110
150
|
agentName,
|
|
111
151
|
metadata,
|
|
152
|
+
systemPrompt,
|
|
153
|
+
description,
|
|
112
154
|
});
|
|
113
155
|
|
|
156
|
+
if (usage) {
|
|
157
|
+
stateManager.updateUsage(usage);
|
|
158
|
+
}
|
|
159
|
+
|
|
114
160
|
// No tools configured - treat any non-end_turn as completed
|
|
115
161
|
if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
|
|
116
162
|
stateManager.complete();
|
|
117
163
|
exitReason = "completed";
|
|
118
|
-
return
|
|
164
|
+
return {
|
|
165
|
+
finalMessage: message,
|
|
166
|
+
exitReason,
|
|
167
|
+
usage: stateManager.getTotalUsage(),
|
|
168
|
+
};
|
|
119
169
|
}
|
|
120
170
|
|
|
121
171
|
// Parse all tool calls uniformly through the router
|
|
@@ -136,13 +186,30 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
136
186
|
}
|
|
137
187
|
|
|
138
188
|
// Hooks can call stateManager.waitForInput() to pause the session
|
|
139
|
-
await toolRouter.processToolCalls(
|
|
140
|
-
|
|
141
|
-
|
|
189
|
+
const toolCallResults = await toolRouter.processToolCalls(
|
|
190
|
+
parsedToolCalls,
|
|
191
|
+
{
|
|
192
|
+
turn: currentTurn,
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
for (const result of toolCallResults) {
|
|
197
|
+
if (result.usage) {
|
|
198
|
+
stateManager.updateUsage(result.usage);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
142
201
|
|
|
143
202
|
if (stateManager.getStatus() === "WAITING_FOR_INPUT") {
|
|
144
|
-
|
|
145
|
-
|
|
203
|
+
const conditionMet = await condition(
|
|
204
|
+
() => stateManager.getStatus() === "RUNNING",
|
|
205
|
+
waitForInputTimeout
|
|
206
|
+
);
|
|
207
|
+
if (!conditionMet) {
|
|
208
|
+
stateManager.cancel();
|
|
209
|
+
// Wait briefly to allow pending waitForStateChange handlers to complete
|
|
210
|
+
await condition(() => false, "2s");
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
146
213
|
}
|
|
147
214
|
}
|
|
148
215
|
|
|
@@ -158,7 +225,11 @@ export const createSession = async <T extends ToolMap, M = unknown>({
|
|
|
158
225
|
await callSessionEnd(exitReason, stateManager.getTurns());
|
|
159
226
|
}
|
|
160
227
|
|
|
161
|
-
return
|
|
228
|
+
return {
|
|
229
|
+
finalMessage: null,
|
|
230
|
+
exitReason,
|
|
231
|
+
usage: stateManager.getTotalUsage(),
|
|
232
|
+
};
|
|
162
233
|
},
|
|
163
234
|
};
|
|
164
235
|
};
|
package/src/lib/state-manager.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { defineQuery, setHandler } from "@temporalio/workflow";
|
|
2
1
|
import {
|
|
2
|
+
condition,
|
|
3
|
+
defineQuery,
|
|
4
|
+
defineUpdate,
|
|
5
|
+
setHandler,
|
|
6
|
+
} from "@temporalio/workflow";
|
|
7
|
+
import {
|
|
8
|
+
type AgentConfig,
|
|
3
9
|
type AgentStatus,
|
|
4
10
|
type BaseAgentState,
|
|
5
11
|
type WorkflowTask,
|
|
@@ -108,9 +114,26 @@ export interface AgentStateManager<TCustom extends JsonSerializable<TCustom>> {
|
|
|
108
114
|
|
|
109
115
|
/** Set the tools (converts Zod schemas to JSON Schema for serialization) */
|
|
110
116
|
setTools(newTools: ToolDefinition[]): void;
|
|
111
|
-
}
|
|
112
117
|
|
|
113
|
-
|
|
118
|
+
/** Update the usage */
|
|
119
|
+
updateUsage(usage: {
|
|
120
|
+
inputTokens?: number;
|
|
121
|
+
outputTokens?: number;
|
|
122
|
+
cachedWriteTokens?: number;
|
|
123
|
+
cachedReadTokens?: number;
|
|
124
|
+
reasonTokens?: number;
|
|
125
|
+
}): void;
|
|
126
|
+
|
|
127
|
+
/** Get the total usage */
|
|
128
|
+
getTotalUsage(): {
|
|
129
|
+
totalInputTokens: number;
|
|
130
|
+
totalOutputTokens: number;
|
|
131
|
+
totalCachedWriteTokens: number;
|
|
132
|
+
totalCachedReadTokens: number;
|
|
133
|
+
totalReasonTokens: number;
|
|
134
|
+
turns: number;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
114
137
|
|
|
115
138
|
/**
|
|
116
139
|
* Creates an agent state manager for tracking workflow state.
|
|
@@ -124,14 +147,23 @@ export const getStateQuery = defineQuery<BaseAgentState>("getState");
|
|
|
124
147
|
*/
|
|
125
148
|
export function createAgentStateManager<
|
|
126
149
|
TCustom extends JsonSerializable<TCustom> = Record<string, never>,
|
|
127
|
-
>(
|
|
128
|
-
initialState
|
|
129
|
-
|
|
150
|
+
>({
|
|
151
|
+
initialState,
|
|
152
|
+
agentConfig,
|
|
153
|
+
}: {
|
|
154
|
+
initialState?: Partial<BaseAgentState> & TCustom;
|
|
155
|
+
agentConfig: AgentConfig;
|
|
156
|
+
}): AgentStateManager<TCustom> {
|
|
130
157
|
// Default state (BaseAgentState fields)
|
|
131
158
|
let status: AgentStatus = initialState?.status ?? "RUNNING";
|
|
132
159
|
let version = initialState?.version ?? 0;
|
|
133
160
|
let turns = initialState?.turns ?? 0;
|
|
134
161
|
let tools = initialState?.tools ?? [];
|
|
162
|
+
let totalInputTokens = 0;
|
|
163
|
+
let totalOutputTokens = 0;
|
|
164
|
+
let totalCachedWriteTokens = 0;
|
|
165
|
+
let totalCachedReadTokens = 0;
|
|
166
|
+
let totalReasonTokens = 0;
|
|
135
167
|
|
|
136
168
|
// Tasks state
|
|
137
169
|
const tasks = new Map<string, WorkflowTask>(initialState?.tasks);
|
|
@@ -157,10 +189,23 @@ export function createAgentStateManager<
|
|
|
157
189
|
} as AgentState<TCustom>;
|
|
158
190
|
}
|
|
159
191
|
|
|
160
|
-
setHandler(
|
|
192
|
+
setHandler(defineQuery(`get${agentConfig.agentName}State`), () => {
|
|
161
193
|
return buildState();
|
|
162
194
|
});
|
|
163
195
|
|
|
196
|
+
setHandler(
|
|
197
|
+
defineUpdate<AgentState<TCustom>, [number]>(
|
|
198
|
+
`waitFor${agentConfig.agentName}StateChange`
|
|
199
|
+
),
|
|
200
|
+
async (lastKnownVersion: number) => {
|
|
201
|
+
await condition(
|
|
202
|
+
() => version > lastKnownVersion || isTerminalStatus(status),
|
|
203
|
+
"55s"
|
|
204
|
+
);
|
|
205
|
+
return buildState();
|
|
206
|
+
}
|
|
207
|
+
);
|
|
208
|
+
|
|
164
209
|
return {
|
|
165
210
|
getStatus(): AgentStatus {
|
|
166
211
|
return status;
|
|
@@ -262,6 +307,38 @@ export function createAgentStateManager<
|
|
|
262
307
|
}
|
|
263
308
|
return deleted;
|
|
264
309
|
},
|
|
310
|
+
|
|
311
|
+
updateUsage(usage: {
|
|
312
|
+
inputTokens?: number;
|
|
313
|
+
outputTokens?: number;
|
|
314
|
+
cachedWriteTokens?: number;
|
|
315
|
+
cachedReadTokens?: number;
|
|
316
|
+
reasonTokens?: number;
|
|
317
|
+
}): void {
|
|
318
|
+
totalInputTokens += usage.inputTokens ?? 0;
|
|
319
|
+
totalOutputTokens += usage.outputTokens ?? 0;
|
|
320
|
+
totalCachedWriteTokens += usage.cachedWriteTokens ?? 0;
|
|
321
|
+
totalCachedReadTokens += usage.cachedReadTokens ?? 0;
|
|
322
|
+
totalReasonTokens += usage.reasonTokens ?? 0;
|
|
323
|
+
},
|
|
324
|
+
|
|
325
|
+
getTotalUsage(): {
|
|
326
|
+
totalInputTokens: number;
|
|
327
|
+
totalOutputTokens: number;
|
|
328
|
+
totalCachedWriteTokens: number;
|
|
329
|
+
totalCachedReadTokens: number;
|
|
330
|
+
totalReasonTokens: number;
|
|
331
|
+
turns: number;
|
|
332
|
+
} {
|
|
333
|
+
return {
|
|
334
|
+
totalInputTokens,
|
|
335
|
+
totalOutputTokens,
|
|
336
|
+
totalCachedWriteTokens,
|
|
337
|
+
totalCachedReadTokens,
|
|
338
|
+
totalReasonTokens,
|
|
339
|
+
turns,
|
|
340
|
+
};
|
|
341
|
+
},
|
|
265
342
|
};
|
|
266
343
|
}
|
|
267
344
|
|
package/src/lib/tool-router.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
PreToolUseHookResult,
|
|
7
7
|
SubagentConfig,
|
|
8
8
|
SubagentHooks,
|
|
9
|
+
TokenUsage,
|
|
9
10
|
ToolHooks,
|
|
10
11
|
ToolResultConfig,
|
|
11
12
|
} from "./types";
|
|
@@ -53,7 +54,7 @@ export interface ToolWithHandler<
|
|
|
53
54
|
strict?: boolean;
|
|
54
55
|
max_uses?: number;
|
|
55
56
|
/** Whether this tool is available to the agent (default: true). Disabled tools are excluded from definitions and rejected at parse time. */
|
|
56
|
-
enabled?: boolean;
|
|
57
|
+
enabled?: () => boolean;
|
|
57
58
|
/** Per-tool lifecycle hooks (run in addition to global hooks) */
|
|
58
59
|
hooks?: ToolHooks<z.infer<TSchema>, TResult>;
|
|
59
60
|
}
|
|
@@ -76,7 +77,7 @@ export type ToolMap = Record<
|
|
|
76
77
|
handler: ToolHandler<any, any, any>;
|
|
77
78
|
strict?: boolean;
|
|
78
79
|
max_uses?: number;
|
|
79
|
-
enabled?: boolean;
|
|
80
|
+
enabled?: () => boolean;
|
|
80
81
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
81
82
|
hooks?: ToolHooks<any, any>;
|
|
82
83
|
}
|
|
@@ -153,6 +154,8 @@ export interface ToolHandlerResponse<TResult = null> {
|
|
|
153
154
|
* payloads through Temporal's activity payload limit.
|
|
154
155
|
*/
|
|
155
156
|
resultAppended?: boolean;
|
|
157
|
+
/** Token usage from the tool execution (e.g. child agent invocations) */
|
|
158
|
+
usage?: TokenUsage;
|
|
156
159
|
}
|
|
157
160
|
|
|
158
161
|
/**
|
|
@@ -228,6 +231,7 @@ export interface ToolCallResult<
|
|
|
228
231
|
toolCallId: string;
|
|
229
232
|
name: TName;
|
|
230
233
|
data: TResult;
|
|
234
|
+
usage?: TokenUsage;
|
|
231
235
|
}
|
|
232
236
|
|
|
233
237
|
/**
|
|
@@ -412,16 +416,14 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
412
416
|
}
|
|
413
417
|
|
|
414
418
|
/** Check if a tool is enabled (defaults to true when not specified) */
|
|
415
|
-
const isEnabled = (tool: ToolMap[string]): boolean =>
|
|
419
|
+
const isEnabled = (tool: ToolMap[string]): boolean =>
|
|
420
|
+
tool.enabled?.() ?? true;
|
|
416
421
|
|
|
417
422
|
if (options.subagents) {
|
|
418
|
-
|
|
419
|
-
(s) => s.enabled !== false
|
|
420
|
-
);
|
|
421
|
-
if (enabledSubagents.length > 0) {
|
|
423
|
+
if (options.subagents.length > 0) {
|
|
422
424
|
// Build per-subagent hook dispatcher keyed by subagent name
|
|
423
425
|
const subagentHooksMap = new Map<string, SubagentHooks>();
|
|
424
|
-
for (const s of
|
|
426
|
+
for (const s of options.subagents) {
|
|
425
427
|
if (s.hooks) subagentHooksMap.set(s.agentName, s.hooks);
|
|
426
428
|
}
|
|
427
429
|
|
|
@@ -429,8 +431,8 @@ export function createToolRouter<T extends ToolMap>(
|
|
|
429
431
|
(args as SubagentArgs).subagent;
|
|
430
432
|
|
|
431
433
|
toolMap.set("Subagent", {
|
|
432
|
-
...createSubagentTool(
|
|
433
|
-
handler: createSubagentHandler(
|
|
434
|
+
...createSubagentTool(options.subagents),
|
|
435
|
+
handler: createSubagentHandler(options.subagents),
|
|
434
436
|
...(subagentHooksMap.size > 0 && {
|
|
435
437
|
hooks: {
|
|
436
438
|
onPreToolUse: async (ctx): Promise<PreToolUseHookResult> => {
|
package/src/lib/types.ts
CHANGED
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
} from "./tool-router";
|
|
9
9
|
|
|
10
10
|
import type { MessageContent, StoredMessage } from "@langchain/core/messages";
|
|
11
|
+
import type { Duration } from "@temporalio/common";
|
|
11
12
|
import type { Workflow } from "@temporalio/workflow";
|
|
12
13
|
import type { z } from "zod";
|
|
13
14
|
|
|
@@ -31,6 +32,10 @@ export interface BaseAgentState {
|
|
|
31
32
|
turns: number;
|
|
32
33
|
tasks: Map<string, WorkflowTask>;
|
|
33
34
|
systemPrompt: string;
|
|
35
|
+
totalInputTokens: number;
|
|
36
|
+
totalOutputTokens: number;
|
|
37
|
+
cachedWriteTokens: number;
|
|
38
|
+
cachedReadtTokens: number;
|
|
34
39
|
}
|
|
35
40
|
|
|
36
41
|
/**
|
|
@@ -49,17 +54,21 @@ export interface AgentFile {
|
|
|
49
54
|
mimeType?: string;
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
export interface TokenUsage {
|
|
58
|
+
inputTokens?: number;
|
|
59
|
+
outputTokens?: number;
|
|
60
|
+
cachedWriteTokens?: number;
|
|
61
|
+
cachedReadTokens?: number;
|
|
62
|
+
reasonTokens?: number;
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
/**
|
|
53
66
|
* Agent response from LLM invocation
|
|
54
67
|
*/
|
|
55
68
|
export interface AgentResponse<M = StoredMessage> {
|
|
56
69
|
message: M;
|
|
57
70
|
rawToolCalls: RawToolCall[];
|
|
58
|
-
usage?:
|
|
59
|
-
input_tokens?: number;
|
|
60
|
-
output_tokens?: number;
|
|
61
|
-
total_tokens?: number;
|
|
62
|
-
};
|
|
71
|
+
usage?: TokenUsage;
|
|
63
72
|
}
|
|
64
73
|
|
|
65
74
|
/**
|
|
@@ -82,16 +91,28 @@ export interface ThreadOps {
|
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
/**
|
|
85
|
-
* Configuration for a Zeitlich agent
|
|
94
|
+
* Configuration for a Zeitlich agent
|
|
86
95
|
*/
|
|
87
|
-
export interface
|
|
88
|
-
|
|
96
|
+
export interface AgentConfig {
|
|
97
|
+
/** The name of the agent, should be unique within the workflows, ideally Pascal Case */
|
|
89
98
|
agentName: string;
|
|
90
99
|
/** Description, used for sub agents */
|
|
91
100
|
description?: string;
|
|
101
|
+
/** The system prompt to append to the thread */
|
|
92
102
|
systemPrompt?: string;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Configuration for a Zeitlich agent session
|
|
107
|
+
*/
|
|
108
|
+
export interface SessionConfig<T extends ToolMap, M = StoredMessage> {
|
|
109
|
+
/** The thread ID to use for the session */
|
|
110
|
+
threadId: string;
|
|
111
|
+
/** Metadata for the session */
|
|
93
112
|
metadata?: Record<string, unknown>;
|
|
113
|
+
/** Whether to append the system prompt as message to the thread */
|
|
94
114
|
appendSystemPrompt?: boolean;
|
|
115
|
+
/** How many turns to run the session for */
|
|
95
116
|
maxTurns?: number;
|
|
96
117
|
/** Workflow-specific runAgent activity (with tools pre-bound) */
|
|
97
118
|
runAgent: RunAgentActivity<M>;
|
|
@@ -110,6 +131,8 @@ export interface ZeitlichAgentConfig<T extends ToolMap, M = StoredMessage> {
|
|
|
110
131
|
* Returns MessageContent array for the initial HumanMessage.
|
|
111
132
|
*/
|
|
112
133
|
buildContextMessage: () => MessageContent | Promise<MessageContent>;
|
|
134
|
+
/** How long to wait for input before cancelling the workflow */
|
|
135
|
+
waitForInputTimeout?: Duration;
|
|
113
136
|
}
|
|
114
137
|
|
|
115
138
|
/**
|
|
@@ -128,9 +151,10 @@ export interface SerializableToolDefinition {
|
|
|
128
151
|
/**
|
|
129
152
|
* Configuration passed to runAgent activity
|
|
130
153
|
*/
|
|
131
|
-
export interface RunAgentConfig {
|
|
154
|
+
export interface RunAgentConfig extends AgentConfig {
|
|
155
|
+
/** The thread ID to use for the session */
|
|
132
156
|
threadId: string;
|
|
133
|
-
|
|
157
|
+
/** Metadata for the session */
|
|
134
158
|
metadata?: Record<string, unknown>;
|
|
135
159
|
}
|
|
136
160
|
|
|
@@ -140,6 +164,7 @@ export interface RunAgentConfig {
|
|
|
140
164
|
export type RunAgentActivity<M = StoredMessage> = (
|
|
141
165
|
config: RunAgentConfig
|
|
142
166
|
) => Promise<AgentResponse<M>>;
|
|
167
|
+
|
|
143
168
|
/**
|
|
144
169
|
* Configuration for appending a tool result
|
|
145
170
|
*/
|
|
@@ -171,7 +196,7 @@ export interface SubagentConfig<TResult extends z.ZodType = z.ZodType> {
|
|
|
171
196
|
/** Description shown to the parent agent explaining what this subagent does */
|
|
172
197
|
description: string;
|
|
173
198
|
/** Whether this subagent is available (default: true). Disabled subagents are excluded from the Subagent tool. */
|
|
174
|
-
enabled?: boolean;
|
|
199
|
+
enabled?: () => boolean;
|
|
175
200
|
/** Temporal workflow function or type name (used with executeChild) */
|
|
176
201
|
workflow: string | Workflow;
|
|
177
202
|
/** Optional task queue - defaults to parent's queue if not specified */
|
|
@@ -369,6 +394,40 @@ export type SessionStartHook = (
|
|
|
369
394
|
ctx: SessionStartHookContext
|
|
370
395
|
) => void | Promise<void>;
|
|
371
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Context for PreHumanMessageAppend hook - called before each human message is appended to the thread
|
|
399
|
+
*/
|
|
400
|
+
export interface PreHumanMessageAppendHookContext {
|
|
401
|
+
/** The message about to be appended */
|
|
402
|
+
message: MessageContent;
|
|
403
|
+
/** Thread identifier */
|
|
404
|
+
threadId: string;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* PreHumanMessageAppend hook - called before each human message is appended to the thread
|
|
409
|
+
*/
|
|
410
|
+
export type PreHumanMessageAppendHook = (
|
|
411
|
+
ctx: PreHumanMessageAppendHookContext
|
|
412
|
+
) => void | Promise<void>;
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* PostHumanMessageAppend hook - called after each human message is appended to the thread
|
|
416
|
+
*/
|
|
417
|
+
export type PostHumanMessageAppendHook = (
|
|
418
|
+
ctx: PostHumanMessageAppendHookContext
|
|
419
|
+
) => void | Promise<void>;
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Context for PostHumanMessageAppend hook - called after each human message is appended to the thread
|
|
423
|
+
*/
|
|
424
|
+
export interface PostHumanMessageAppendHookContext {
|
|
425
|
+
/** The message that was appended */
|
|
426
|
+
message: MessageContent;
|
|
427
|
+
/** Thread identifier */
|
|
428
|
+
threadId: string;
|
|
429
|
+
}
|
|
430
|
+
|
|
372
431
|
/**
|
|
373
432
|
* Context for SessionEnd hook - called when session ends
|
|
374
433
|
*/
|
|
@@ -424,6 +483,10 @@ export interface ToolHooks<TArgs = unknown, TResult = unknown> {
|
|
|
424
483
|
* Combined hooks interface for session lifecycle
|
|
425
484
|
*/
|
|
426
485
|
export interface Hooks<T extends ToolMap, TResult = unknown> {
|
|
486
|
+
/** Called before each human message is appended to the thread */
|
|
487
|
+
onPreHumanMessageAppend?: PreHumanMessageAppendHook;
|
|
488
|
+
/** Called after each human message is appended to the thread */
|
|
489
|
+
onPostHumanMessageAppend?: PostHumanMessageAppendHook;
|
|
427
490
|
/** Called before each tool execution - can block or modify */
|
|
428
491
|
onPreToolUse?: PreToolUseHook<T>;
|
|
429
492
|
/** Called after each successful tool execution */
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { ActivityToolHandler } from "../../lib/tool-router";
|
|
1
|
+
import type { ToolHandler } from "../../lib/tool-router";
|
|
3
2
|
import type { AskUserQuestionArgs } from "./tool";
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
5
|
* Creates handler for user interaction tool - creates AI messages for display.
|
|
7
6
|
*/
|
|
8
|
-
export const createAskUserQuestionHandler =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
7
|
+
export const createAskUserQuestionHandler =
|
|
8
|
+
(): ToolHandler<
|
|
9
|
+
AskUserQuestionArgs,
|
|
10
|
+
{
|
|
11
|
+
questions: {
|
|
12
|
+
question: string;
|
|
13
|
+
header: string;
|
|
14
|
+
options: { label: string; description: string }[];
|
|
15
|
+
multiSelect: boolean;
|
|
16
|
+
}[];
|
|
17
|
+
}
|
|
18
|
+
> =>
|
|
19
|
+
(args) => {
|
|
20
|
+
return {
|
|
21
|
+
toolResponse: "Question submitted",
|
|
22
|
+
data: { questions: args.questions },
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -53,7 +53,7 @@ export function createSubagentHandler<
|
|
|
53
53
|
taskQueue: config.taskQueue ?? parentTaskQueue,
|
|
54
54
|
};
|
|
55
55
|
|
|
56
|
-
const { toolResponse, data } =
|
|
56
|
+
const { toolResponse, data, usage } =
|
|
57
57
|
typeof config.workflow === "string"
|
|
58
58
|
? await executeChild(config.workflow, childOpts)
|
|
59
59
|
: await executeChild(config.workflow, childOpts);
|
|
@@ -66,6 +66,7 @@ export function createSubagentHandler<
|
|
|
66
66
|
return {
|
|
67
67
|
toolResponse,
|
|
68
68
|
data: validated,
|
|
69
|
+
...(usage && { usage }),
|
|
69
70
|
};
|
|
70
71
|
};
|
|
71
72
|
}
|
package/src/workflow.ts
CHANGED
|
@@ -74,7 +74,7 @@ export type {
|
|
|
74
74
|
AgentFile,
|
|
75
75
|
AgentResponse,
|
|
76
76
|
ThreadOps,
|
|
77
|
-
|
|
77
|
+
AgentConfig,
|
|
78
78
|
RunAgentConfig,
|
|
79
79
|
RunAgentActivity,
|
|
80
80
|
ToolResultConfig,
|
|
@@ -109,8 +109,6 @@ export type { SubagentArgs } from "./tools/subagent/tool";
|
|
|
109
109
|
export type { ZeitlichSharedActivities } from "./activities";
|
|
110
110
|
|
|
111
111
|
// Tool definitions (schemas only - no handlers)
|
|
112
|
-
export { askUserQuestionTool } from "./tools/ask-user-question/tool";
|
|
113
|
-
export type { AskUserQuestionArgs } from "./tools/ask-user-question/tool";
|
|
114
112
|
export { globTool } from "./tools/glob/tool";
|
|
115
113
|
export type { GlobArgs } from "./tools/glob/tool";
|
|
116
114
|
export { grepTool } from "./tools/grep/tool";
|
|
@@ -141,3 +139,7 @@ export { createTaskUpdateHandler } from "./tools/task-update/handler";
|
|
|
141
139
|
|
|
142
140
|
export { bashTool, createBashToolDescription } from "./tools/bash/tool";
|
|
143
141
|
export type { BashArgs } from "./tools/bash/tool";
|
|
142
|
+
|
|
143
|
+
export { askUserQuestionTool } from "./tools/ask-user-question/tool";
|
|
144
|
+
export type { AskUserQuestionArgs } from "./tools/ask-user-question/tool";
|
|
145
|
+
export { createAskUserQuestionHandler } from "./tools/ask-user-question/handler";
|