zeitlich 0.2.3 → 0.2.4

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.
@@ -7,12 +7,10 @@ import type {
7
7
  SessionEndHook,
8
8
  SessionExitReason,
9
9
  } from "./types";
10
- import type { StoredMessage } from "@langchain/core/messages";
11
10
  import { type AgentStateManager, type JsonSerializable } from "./state-manager";
12
11
  import {
13
12
  createToolRouter,
14
13
  type ParsedToolCallUnion,
15
- type RawToolCall,
16
14
  type ToolMap,
17
15
  } from "./tool-router";
18
16
 
@@ -95,28 +93,19 @@ export const createSession = async <T extends ToolMap, M = unknown>({
95
93
  stateManager.incrementTurns();
96
94
  const currentTurn = stateManager.getTurns();
97
95
 
98
- const { message, stopReason } = await runAgent({
96
+ const { message, rawToolCalls } = await runAgent({
99
97
  threadId,
100
98
  agentName,
101
99
  metadata,
102
100
  });
103
101
 
104
- if (stopReason === "end_turn") {
105
- stateManager.complete();
106
- exitReason = "completed";
107
- return message;
108
- }
109
-
110
102
  // No tools configured - treat any non-end_turn as completed
111
- if (!toolRouter.hasTools()) {
103
+ if (!toolRouter.hasTools() || rawToolCalls.length === 0) {
112
104
  stateManager.complete();
113
105
  exitReason = "completed";
114
106
  return message;
115
107
  }
116
108
 
117
- const rawToolCalls: RawToolCall[] =
118
- await threadOps.parseToolCalls(message);
119
-
120
109
  // Parse all tool calls uniformly through the router
121
110
  const parsedToolCalls: ParsedToolCallUnion<T>[] = [];
122
111
  for (const tc of rawToolCalls) {
@@ -176,7 +165,7 @@ export const createSession = async <T extends ToolMap, M = unknown>({
176
165
  */
177
166
  export function proxyDefaultThreadOps(
178
167
  options?: Parameters<typeof proxyActivities>[0]
179
- ): ThreadOps<StoredMessage> {
168
+ ): ThreadOps {
180
169
  const activities = proxyActivities<ZeitlichSharedActivities>(
181
170
  options ?? {
182
171
  startToCloseTimeout: "30m",
@@ -194,6 +183,5 @@ export function proxyDefaultThreadOps(
194
183
  initializeThread: activities.initializeThread,
195
184
  appendHumanMessage: activities.appendHumanMessage,
196
185
  appendToolResult: activities.appendToolResult,
197
- parseToolCalls: activities.parseToolCalls,
198
186
  };
199
187
  }
@@ -9,11 +9,11 @@ import type {
9
9
  ToolHooks,
10
10
  ToolResultConfig,
11
11
  } from "./types";
12
- import type { TaskArgs } from "../tools/task/tool";
12
+ import type { SubagentArgs } from "../tools/subagent/tool";
13
13
 
14
14
  import type { z } from "zod";
15
- import { createTaskTool } from "../tools/task/tool";
16
- import { createTaskHandler } from "../tools/task/handler";
15
+ import { createSubagentTool } from "../tools/subagent/tool";
16
+ import { createSubagentHandler } from "../tools/subagent/handler";
17
17
 
18
18
  export type { ToolMessageContent };
19
19
 
@@ -422,11 +422,11 @@ export function createToolRouter<T extends ToolMap>(
422
422
  }
423
423
 
424
424
  const resolveSubagentName = (args: unknown): string =>
425
- (args as TaskArgs).subagent;
425
+ (args as SubagentArgs).subagent;
426
426
 
427
- toolMap.set("Task", {
428
- ...createTaskTool(options.subagents),
429
- handler: createTaskHandler(options.subagents),
427
+ toolMap.set("Subagent", {
428
+ ...createSubagentTool(options.subagents),
429
+ handler: createSubagentHandler(options.subagents),
430
430
  ...(subagentHooksMap.size > 0 && {
431
431
  hooks: {
432
432
  onPreToolUse: async (ctx): Promise<PreToolUseHookResult> => {
@@ -912,7 +912,7 @@ export function defineSubagent<
912
912
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
913
913
  | ((input: { prompt: string; context: TContext }) => Promise<any>);
914
914
  context: TContext;
915
- hooks?: SubagentHooks<TaskArgs, z.infer<TResult>>;
915
+ hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
916
916
  }
917
917
  ): SubagentConfig<TResult>;
918
918
  // Without context — verifies workflow accepts { prompt }
@@ -920,7 +920,7 @@ export function defineSubagent<TResult extends z.ZodType = z.ZodType>(
920
920
  config: Omit<SubagentConfig<TResult>, "hooks" | "workflow"> & {
921
921
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
922
922
  workflow: string | ((input: { prompt: string }) => Promise<any>);
923
- hooks?: SubagentHooks<TaskArgs, z.infer<TResult>>;
923
+ hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
924
924
  }
925
925
  ): SubagentConfig<TResult>;
926
926
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
package/src/lib/types.ts CHANGED
@@ -54,7 +54,7 @@ export interface AgentFile {
54
54
  */
55
55
  export interface AgentResponse<M = StoredMessage> {
56
56
  message: M;
57
- stopReason: string | null;
57
+ rawToolCalls: RawToolCall[];
58
58
  usage?: {
59
59
  input_tokens?: number;
60
60
  output_tokens?: number;
@@ -67,7 +67,7 @@ export interface AgentResponse<M = StoredMessage> {
67
67
  * Consumers provide these — typically by wrapping Temporal activities.
68
68
  * Use `proxyDefaultThreadOps()` for the default StoredMessage implementation.
69
69
  */
70
- export interface ThreadOps<M = StoredMessage> {
70
+ export interface ThreadOps {
71
71
  /** Initialize an empty thread */
72
72
  initializeThread(threadId: string): Promise<void>;
73
73
  /** Append a human message to the thread */
@@ -77,8 +77,6 @@ export interface ThreadOps<M = StoredMessage> {
77
77
  ): Promise<void>;
78
78
  /** Append a tool result to the thread */
79
79
  appendToolResult(config: ToolResultConfig): Promise<void>;
80
- /** Extract raw tool calls from a message */
81
- parseToolCalls(message: M): Promise<RawToolCall[]>;
82
80
  }
83
81
 
84
82
  /**
@@ -92,7 +90,7 @@ export interface ZeitlichAgentConfig<T extends ToolMap, M = StoredMessage> {
92
90
  /** Workflow-specific runAgent activity (with tools pre-bound) */
93
91
  runAgent: RunAgentActivity<M>;
94
92
  /** Thread operations (initialize, append messages, parse tool calls) */
95
- threadOps: ThreadOps<M>;
93
+ threadOps: ThreadOps;
96
94
  /** Tool router for processing tool calls (optional if agent has no tools) */
97
95
  tools?: T;
98
96
  /** Subagent configurations */
@@ -152,6 +150,10 @@ export interface ToolResultConfig {
152
150
  // Subagent Configuration
153
151
  // ============================================================================
154
152
 
153
+ /** Infer the z.infer'd result type from a SubagentConfig, or null if no schema */
154
+ export type InferSubagentResult<T extends SubagentConfig> =
155
+ T extends SubagentConfig<infer S> ? z.infer<S> : null;
156
+
155
157
  /**
156
158
  * Configuration for a subagent that can be spawned by the parent workflow.
157
159
  *
@@ -1,26 +1,20 @@
1
1
  import { executeChild, workflowInfo, uuid4 } from "@temporalio/workflow";
2
2
  import type { ToolHandlerResponse } from "../../lib/tool-router";
3
- import type { SubagentConfig, SubagentInput } from "../../lib/types";
4
- import type { TaskArgs } from "./tool";
3
+ import type {
4
+ InferSubagentResult,
5
+ SubagentConfig,
6
+ SubagentInput,
7
+ } from "../../lib/types";
8
+ import type { SubagentArgs } from "./tool";
5
9
 
6
10
  /**
7
- * Result from a task handler execution
8
- */
9
- export interface TaskHandlerResult<TResult = unknown> {
10
- /** The validated result from the child workflow */
11
- result: TResult;
12
- /** The child workflow ID (for reference/debugging) */
13
- childWorkflowId: string;
14
- }
15
-
16
- /**
17
- * Creates a Task tool handler that spawns child workflows for configured subagents.
11
+ * Creates a Subagent tool handler that spawns child workflows for configured subagents.
18
12
  *
19
13
  * @param subagents - Array of subagent configurations
20
14
  * @returns A tool handler function that can be used with the tool router
21
15
  *
22
16
  * @example
23
- * const taskHandler = taskHandler([
17
+ * const subagentHandler = subagentHandler([
24
18
  * {
25
19
  * name: "researcher",
26
20
  * description: "Researches topics",
@@ -29,13 +23,15 @@ export interface TaskHandlerResult<TResult = unknown> {
29
23
  * },
30
24
  * ]);
31
25
  */
32
- export function createTaskHandler(subagents: SubagentConfig[]) {
26
+ export function createSubagentHandler<
27
+ const T extends readonly SubagentConfig[],
28
+ >(subagents: [...T]) {
33
29
  const { workflowId: parentWorkflowId, taskQueue: parentTaskQueue } =
34
30
  workflowInfo();
35
31
 
36
32
  return async (
37
- args: TaskArgs
38
- ): Promise<ToolHandlerResponse<TaskHandlerResult>> => {
33
+ args: SubagentArgs
34
+ ): Promise<ToolHandlerResponse<InferSubagentResult<T[number]> | null>> => {
39
35
  const config = subagents.find((s) => s.name === args.subagent);
40
36
 
41
37
  if (!config) {
@@ -58,28 +54,19 @@ export function createTaskHandler(subagents: SubagentConfig[]) {
58
54
  taskQueue: config.taskQueue ?? parentTaskQueue,
59
55
  };
60
56
 
61
- const childResult =
57
+ const { toolResponse, data } =
62
58
  typeof config.workflow === "string"
63
59
  ? await executeChild(config.workflow, childOpts)
64
60
  : await executeChild(config.workflow, childOpts);
65
61
 
66
62
  // Validate result if schema provided, otherwise pass through as-is
67
- const validated = config.resultSchema
68
- ? config.resultSchema.parse(childResult)
69
- : childResult;
70
-
71
- // Format content - stringify objects, pass strings through
72
- const toolResponse =
73
- typeof validated === "string"
74
- ? validated
75
- : JSON.stringify(validated, null, 2);
63
+ const validated = (
64
+ config.resultSchema ? config.resultSchema.parse(data) : null
65
+ ) as InferSubagentResult<T[number]> | null;
76
66
 
77
67
  return {
78
68
  toolResponse,
79
- data: {
80
- result: validated,
81
- childWorkflowId,
82
- },
69
+ data: validated,
83
70
  };
84
71
  };
85
72
  }
@@ -1,31 +1,31 @@
1
1
  import z from "zod";
2
2
  import type { SubagentConfig } from "../../lib/types";
3
3
 
4
- const TASK_TOOL = "Task" as const;
4
+ const SUBAGENT_TOOL = "Subagent" as const;
5
5
 
6
6
  /**
7
7
  * Builds the tool description with available subagent information
8
8
  */
9
- function buildTaskDescription(subagents: SubagentConfig[]): string {
9
+ function buildSubagentDescription(subagents: SubagentConfig[]): string {
10
10
  const subagentList = subagents
11
11
  .map((s) => `- **${s.name}**: ${s.description}`)
12
12
  .join("\n");
13
13
 
14
- return `Launch a new agent to handle complex, multi-step tasks autonomously.
14
+ return `Launch a new agent to handle complex tasks autonomously.
15
15
 
16
- The ${TASK_TOOL} tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
16
+ The ${SUBAGENT_TOOL} tool launches specialized agents (subprocesses) that autonomously handle complex tasks. Each agent type has specific capabilities and tools available to it.
17
17
 
18
18
  Available agent types:
19
19
 
20
20
  ${subagentList}
21
21
 
22
- When using the ${TASK_TOOL} tool, you must specify a subagent parameter to select which agent type to use.
22
+ When using the ${SUBAGENT_TOOL} tool, you must specify a subagent parameter to select which agent type to use.
23
23
 
24
24
  Usage notes:
25
25
 
26
26
  - Always include a short description (3-5 words) summarizing what the agent will do
27
27
  - Launch multiple agents concurrently whenever possible, to maximize performance; to do that, use a single message with multiple tool uses
28
- - When the agent is done, it will return a single message back to you. The result returned by the agent is not visible to the user. To show the user the result, you should send a text message back to the user with a concise summary of the result.
28
+ - When the agent is done, it will return a single message back to you.
29
29
  - Each invocation starts fresh - provide a detailed task description with all necessary context.
30
30
  - Provide clear, detailed prompts so the agent can work autonomously and return exactly the information you need.
31
31
  - The agent's outputs should generally be trusted
@@ -34,13 +34,13 @@ Usage notes:
34
34
  }
35
35
 
36
36
  /**
37
- * Creates a Task tool configured with the available subagents.
37
+ * Creates a Subagent tool configured with the available subagents.
38
38
  *
39
39
  * @param subagents - Array of subagent configurations (must have at least one)
40
40
  * @returns A tool definition with dynamic schema based on available subagents
41
41
  *
42
42
  * @example
43
- * const taskTool = createTaskTool([
43
+ * const subagentTool = createSubagentTool([
44
44
  * {
45
45
  * name: "researcher",
46
46
  * description: "Researches topics and gathers information",
@@ -49,7 +49,7 @@ Usage notes:
49
49
  * },
50
50
  * ]);
51
51
  */
52
- export function createTaskTool<T extends SubagentConfig[]>(
52
+ export function createSubagentTool<T extends SubagentConfig[]>(
53
53
  subagents: T
54
54
  ): {
55
55
  name: string;
@@ -67,8 +67,8 @@ export function createTaskTool<T extends SubagentConfig[]>(
67
67
  const names = subagents.map((s) => s.name);
68
68
 
69
69
  return {
70
- name: TASK_TOOL,
71
- description: buildTaskDescription(subagents),
70
+ name: SUBAGENT_TOOL,
71
+ description: buildSubagentDescription(subagents),
72
72
  schema: z.object({
73
73
  subagent: z.enum(names).describe("The type of subagent to launch"),
74
74
  description: z
@@ -80,9 +80,9 @@ export function createTaskTool<T extends SubagentConfig[]>(
80
80
  }
81
81
 
82
82
  /**
83
- * Task tool args type (when subagent names are not known at compile time)
83
+ * Subagent tool args type (when subagent names are not known at compile time)
84
84
  */
85
- export type TaskArgs = {
85
+ export type SubagentArgs = {
86
86
  subagent: string;
87
87
  description: string;
88
88
  prompt: string;
package/src/workflow.ts CHANGED
@@ -101,9 +101,8 @@ export type {
101
101
  export { isTerminalStatus } from "./lib/types";
102
102
 
103
103
  // Subagent support
104
- export { createTaskTool } from "./tools/task/tool";
105
- export type { TaskArgs } from "./tools/task/tool";
106
- export type { TaskHandlerResult } from "./tools/task/handler";
104
+ export { createSubagentTool } from "./tools/subagent/tool";
105
+ export type { SubagentArgs } from "./tools/subagent/tool";
107
106
 
108
107
  // Activity type interfaces (types only, no runtime code)
109
108
  // These are safe to import in workflows for typing proxyActivities