zeitlich 0.2.16 → 0.2.18
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 +75 -64
- package/dist/adapters/sandbox/virtual/index.cjs +45 -0
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/index.d.cts +3 -3
- package/dist/adapters/sandbox/virtual/index.d.ts +3 -3
- package/dist/adapters/sandbox/virtual/index.js +43 -1
- package/dist/adapters/sandbox/virtual/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +2 -2
- package/dist/adapters/thread/google-genai/index.d.ts +2 -2
- package/dist/adapters/thread/langchain/index.cjs +2 -2
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +2 -2
- package/dist/adapters/thread/langchain/index.d.ts +2 -2
- package/dist/adapters/thread/langchain/index.js +2 -2
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/index.cjs +104 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +100 -10
- package/dist/index.js.map +1 -1
- package/dist/{types-DCi2qXjN.d.cts → queries-DnX72m_Y.d.cts} +43 -2
- package/dist/{types-BSOte_8s.d.ts → queries-TwukRZ8b.d.ts} +43 -2
- package/dist/{types-XPtivmSJ.d.ts → types-CdB2D5Sq.d.ts} +32 -13
- package/dist/{types-BMXzv7TN.d.cts → types-CmOSypVk.d.cts} +2 -2
- package/dist/{types-BMXzv7TN.d.ts → types-CmOSypVk.d.ts} +2 -2
- package/dist/{types-Drli9aCK.d.cts → types-DRvq2miV.d.cts} +32 -13
- package/dist/workflow.cjs +104 -9
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +114 -40
- package/dist/workflow.d.ts +114 -40
- package/dist/workflow.js +100 -10
- package/dist/workflow.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/sandbox/virtual/index.ts +2 -0
- package/src/adapters/sandbox/virtual/queries.ts +97 -0
- package/src/adapters/thread/langchain/activities.ts +7 -5
- package/src/lib/session/session.integration.test.ts +1 -0
- package/src/lib/subagent/define.ts +34 -47
- package/src/lib/subagent/handler.ts +9 -6
- package/src/lib/subagent/index.ts +4 -1
- package/src/lib/subagent/register.ts +7 -4
- package/src/lib/subagent/subagent.integration.test.ts +206 -51
- package/src/lib/subagent/types.ts +41 -11
- package/src/lib/subagent/workflow.ts +114 -0
- package/src/lib/tool-router/router.ts +2 -1
- package/src/lib/tool-router/types.ts +2 -2
- package/src/lib/workflow.test.ts +131 -0
- package/src/lib/workflow.ts +45 -0
- package/src/workflow.ts +12 -2
package/package.json
CHANGED
|
@@ -77,6 +77,8 @@ export function createVirtualSandbox<
|
|
|
77
77
|
export { VirtualSandboxFileSystem } from "./filesystem";
|
|
78
78
|
export { VirtualSandboxProvider } from "./provider";
|
|
79
79
|
export { withVirtualSandbox } from "./with-virtual-sandbox";
|
|
80
|
+
export { hasFileWithMimeType, filesWithMimeType, hasDirectory } from "./queries";
|
|
81
|
+
export type { FileTreeAccessor } from "./queries";
|
|
80
82
|
export type {
|
|
81
83
|
FileEntry,
|
|
82
84
|
FileEntryMetadata,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { FileEntry } from "./types";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Structural constraint: accepts any `AgentStateManager<T>` whose custom
|
|
5
|
+
* state includes `fileTree: FileEntry<TMeta>[]`.
|
|
6
|
+
*/
|
|
7
|
+
export interface FileTreeAccessor<TMeta> {
|
|
8
|
+
get(key: "fileTree"): FileEntry<TMeta>[];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check whether any file in the tree has a `metadata.mimeType` that matches
|
|
13
|
+
* the given pattern.
|
|
14
|
+
*
|
|
15
|
+
* Patterns:
|
|
16
|
+
* - Exact: `"application/pdf"`
|
|
17
|
+
* - Wildcard type: `"image/*"`
|
|
18
|
+
*
|
|
19
|
+
* Useful for conditionally enabling tools:
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* { enabled: hasFileWithMimeType(stateManager, "image/*") }
|
|
23
|
+
* { enabled: hasFileWithMimeType(stateManager, ["image/*", "application/pdf"]) }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function hasFileWithMimeType<TMeta>(
|
|
27
|
+
stateManager: FileTreeAccessor<TMeta>,
|
|
28
|
+
pattern: string | string[],
|
|
29
|
+
): boolean {
|
|
30
|
+
const tree = stateManager.get("fileTree");
|
|
31
|
+
const matchers = (Array.isArray(pattern) ? pattern : [pattern]).map(buildMatcher);
|
|
32
|
+
return tree.some((entry) => {
|
|
33
|
+
const meta = entry.metadata as Record<string, unknown> | undefined;
|
|
34
|
+
const mime = meta?.mimeType;
|
|
35
|
+
return typeof mime === "string" && matchers.some((m) => m(mime));
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Return all entries whose `metadata.mimeType` matches the given pattern.
|
|
41
|
+
*/
|
|
42
|
+
export function filesWithMimeType<TMeta>(
|
|
43
|
+
stateManager: FileTreeAccessor<TMeta>,
|
|
44
|
+
pattern: string,
|
|
45
|
+
): FileEntry<TMeta>[] {
|
|
46
|
+
const tree = stateManager.get("fileTree");
|
|
47
|
+
const match = buildMatcher(pattern);
|
|
48
|
+
return tree.filter((entry) => {
|
|
49
|
+
const meta = entry.metadata as Record<string, unknown> | undefined;
|
|
50
|
+
const mime = meta?.mimeType;
|
|
51
|
+
return typeof mime === "string" && match(mime);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Check whether the tree contains a directory whose name matches the given
|
|
57
|
+
* pattern. Directories are inferred from file paths.
|
|
58
|
+
*
|
|
59
|
+
* Patterns:
|
|
60
|
+
* - Exact: `"src"`
|
|
61
|
+
* - Glob with `*` wildcard: `"test*"`, `"*.generated"`
|
|
62
|
+
*
|
|
63
|
+
* ```ts
|
|
64
|
+
* { enabled: hasDirectory(stateManager, "test*") }
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export function hasDirectory<TMeta>(
|
|
68
|
+
stateManager: FileTreeAccessor<TMeta>,
|
|
69
|
+
pattern: string,
|
|
70
|
+
): boolean {
|
|
71
|
+
const tree = stateManager.get("fileTree");
|
|
72
|
+
const match = buildGlobMatcher(pattern);
|
|
73
|
+
return tree.some((entry) => {
|
|
74
|
+
const segments = entry.path.split("/").filter(Boolean);
|
|
75
|
+
return segments.slice(0, -1).some(match);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Internal matchers
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
function buildMatcher(pattern: string): (value: string) => boolean {
|
|
84
|
+
if (pattern.endsWith("/*")) {
|
|
85
|
+
const prefix = pattern.slice(0, -1);
|
|
86
|
+
return (v) => v.startsWith(prefix);
|
|
87
|
+
}
|
|
88
|
+
return (v) => v === pattern;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function buildGlobMatcher(pattern: string): (value: string) => boolean {
|
|
92
|
+
if (!pattern.includes("*")) return (v) => v === pattern;
|
|
93
|
+
const re = new RegExp(
|
|
94
|
+
"^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$",
|
|
95
|
+
);
|
|
96
|
+
return (v) => re.test(v);
|
|
97
|
+
}
|
|
@@ -96,7 +96,7 @@ export function createLangChainAdapter(
|
|
|
96
96
|
|
|
97
97
|
async forkThread(
|
|
98
98
|
sourceThreadId: string,
|
|
99
|
-
targetThreadId: string
|
|
99
|
+
targetThreadId: string
|
|
100
100
|
): Promise<void> {
|
|
101
101
|
const thread = createLangChainThreadManager({
|
|
102
102
|
redis,
|
|
@@ -106,18 +106,20 @@ export function createLangChainAdapter(
|
|
|
106
106
|
},
|
|
107
107
|
};
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
const makeInvoker = (
|
|
110
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
111
|
+
model: BaseChatModel<any>
|
|
112
|
+
): ModelInvoker<StoredMessage> =>
|
|
111
113
|
createLangChainModelInvoker({ redis, model });
|
|
112
114
|
|
|
113
115
|
const invoker: ModelInvoker<StoredMessage> = config.model
|
|
114
116
|
? makeInvoker(config.model)
|
|
115
|
-
: (
|
|
117
|
+
: () => {
|
|
116
118
|
throw new Error(
|
|
117
119
|
"No default model provided to createLangChainAdapter. " +
|
|
118
120
|
"Either pass `model` in the config or use `createModelInvoker(model)` instead."
|
|
119
121
|
);
|
|
120
|
-
}
|
|
122
|
+
};
|
|
121
123
|
|
|
122
124
|
return {
|
|
123
125
|
threadOps,
|
|
@@ -1,71 +1,58 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
2
|
import type {
|
|
3
3
|
SubagentConfig,
|
|
4
|
-
|
|
4
|
+
SubagentDefinition,
|
|
5
5
|
SubagentHooks,
|
|
6
|
+
SubagentWorkflow,
|
|
6
7
|
} from "./types";
|
|
7
8
|
import type { SubagentArgs } from "./tool";
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Creates a `SubagentConfig` from a `SubagentDefinition` (returned by `defineSubagentWorkflow`).
|
|
12
|
+
* Metadata (name, description, resultSchema) is read from the definition — only configure
|
|
13
|
+
* what's specific to this usage in the parent workflow.
|
|
13
14
|
*
|
|
14
15
|
* @example
|
|
15
16
|
* ```ts
|
|
16
|
-
* //
|
|
17
|
-
* const researcher = defineSubagent(
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
17
|
+
* // Minimal — all metadata comes from the definition
|
|
18
|
+
* export const researcher = defineSubagent(researcherWorkflow);
|
|
19
|
+
*
|
|
20
|
+
* // With parent-specific overrides
|
|
21
|
+
* export const researcher = defineSubagent(researcherWorkflow, {
|
|
22
|
+
* allowThreadContinuation: true,
|
|
23
|
+
* sandbox: "own",
|
|
23
24
|
* hooks: {
|
|
24
|
-
* onPostExecution: ({ result }) =>
|
|
25
|
-
* // result is typed as { findings: string }
|
|
26
|
-
* },
|
|
25
|
+
* onPostExecution: ({ result }) => console.log(result),
|
|
27
26
|
* },
|
|
28
27
|
* });
|
|
29
28
|
*
|
|
30
|
-
* //
|
|
31
|
-
* const
|
|
32
|
-
*
|
|
33
|
-
* description: "Writes content",
|
|
34
|
-
* workflow: writerWorkflow, // (input: { prompt: string }) => Promise<...>
|
|
35
|
-
* resultSchema: z.object({ content: z.string() }),
|
|
29
|
+
* // With typed context
|
|
30
|
+
* export const researcher = defineSubagent(researcherWorkflow, {
|
|
31
|
+
* context: { apiKey: "..." },
|
|
36
32
|
* });
|
|
37
33
|
* ```
|
|
38
34
|
*/
|
|
39
|
-
// With context — verifies workflow accepts { prompt, context: TContext }
|
|
40
35
|
export function defineSubagent<
|
|
41
36
|
TResult extends z.ZodType = z.ZodType,
|
|
42
37
|
TContext extends Record<string, unknown> = Record<string, unknown>,
|
|
43
38
|
>(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
| ((input: {
|
|
48
|
-
prompt: string;
|
|
49
|
-
previousThreadId?: string;
|
|
50
|
-
context: TContext;
|
|
51
|
-
}) => Promise<SubagentHandlerResponse<z.infer<TResult> | null>>);
|
|
52
|
-
context: TContext;
|
|
53
|
-
hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
|
|
54
|
-
}
|
|
55
|
-
): SubagentConfig<TResult>;
|
|
56
|
-
// Without context — verifies workflow accepts { prompt }
|
|
57
|
-
export function defineSubagent<TResult extends z.ZodType = z.ZodType>(
|
|
58
|
-
config: Omit<SubagentConfig<TResult>, "hooks" | "workflow"> & {
|
|
59
|
-
workflow:
|
|
60
|
-
| string
|
|
61
|
-
| ((input: {
|
|
62
|
-
prompt: string;
|
|
63
|
-
previousThreadId?: string;
|
|
64
|
-
}) => Promise<SubagentHandlerResponse<z.infer<TResult> | null>>);
|
|
39
|
+
definition: SubagentDefinition<TResult, TContext>,
|
|
40
|
+
overrides?: {
|
|
41
|
+
context?: TContext;
|
|
65
42
|
hooks?: SubagentHooks<SubagentArgs, z.infer<TResult>>;
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
43
|
+
enabled?: boolean | (() => boolean);
|
|
44
|
+
taskQueue?: string;
|
|
45
|
+
allowThreadContinuation?: boolean;
|
|
46
|
+
sandbox?: "inherit" | "own";
|
|
47
|
+
},
|
|
48
|
+
): SubagentConfig<TResult> {
|
|
49
|
+
return {
|
|
50
|
+
agentName: definition.agentName,
|
|
51
|
+
description: definition.description,
|
|
52
|
+
workflow: definition as SubagentWorkflow<TResult>,
|
|
53
|
+
...(definition.resultSchema !== undefined && {
|
|
54
|
+
resultSchema: definition.resultSchema,
|
|
55
|
+
}),
|
|
56
|
+
...overrides,
|
|
57
|
+
} as SubagentConfig<TResult>;
|
|
71
58
|
}
|
|
@@ -5,7 +5,7 @@ import type { ToolMessageContent } from "../types";
|
|
|
5
5
|
import type {
|
|
6
6
|
InferSubagentResult,
|
|
7
7
|
SubagentConfig,
|
|
8
|
-
|
|
8
|
+
SubagentWorkflowInput,
|
|
9
9
|
} from "./types";
|
|
10
10
|
import type { SubagentArgs } from "./tool";
|
|
11
11
|
import type { z } from "zod";
|
|
@@ -38,18 +38,21 @@ export function createSubagentHandler<
|
|
|
38
38
|
const { sandboxId: parentSandboxId } = context;
|
|
39
39
|
const inheritSandbox = config.sandbox !== "own" && !!parentSandboxId;
|
|
40
40
|
|
|
41
|
-
const
|
|
42
|
-
prompt: args.prompt,
|
|
43
|
-
...(config.context && { context: config.context }),
|
|
41
|
+
const workflowInput: SubagentWorkflowInput = {
|
|
44
42
|
...(args.threadId &&
|
|
45
43
|
args.threadId !== null &&
|
|
46
|
-
config.allowThreadContinuation && {
|
|
44
|
+
config.allowThreadContinuation && {
|
|
45
|
+
previousThreadId: args.threadId,
|
|
46
|
+
}),
|
|
47
47
|
...(inheritSandbox && { sandboxId: parentSandboxId }),
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
const childOpts = {
|
|
51
51
|
workflowId: childWorkflowId,
|
|
52
|
-
args:
|
|
52
|
+
args:
|
|
53
|
+
config.context === undefined
|
|
54
|
+
? ([args.prompt, workflowInput] as const)
|
|
55
|
+
: ([args.prompt, workflowInput, config.context] as const),
|
|
53
56
|
taskQueue: config.taskQueue ?? parentTaskQueue,
|
|
54
57
|
};
|
|
55
58
|
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
export type {
|
|
2
2
|
SubagentConfig,
|
|
3
|
+
SubagentDefinition,
|
|
3
4
|
SubagentHooks,
|
|
4
|
-
SubagentInput,
|
|
5
5
|
SubagentHandlerResponse,
|
|
6
6
|
SubagentWorkflow,
|
|
7
|
+
SubagentWorkflowInput,
|
|
8
|
+
SubagentSessionInput,
|
|
7
9
|
InferSubagentResult,
|
|
8
10
|
} from "./types";
|
|
9
11
|
export { createSubagentTool, SUBAGENT_TOOL_NAME } from "./tool";
|
|
10
12
|
export type { SubagentArgs } from "./tool";
|
|
11
13
|
export { createSubagentHandler } from "./handler";
|
|
12
14
|
export { defineSubagent } from "./define";
|
|
15
|
+
export { defineSubagentWorkflow } from "./workflow";
|
|
13
16
|
export { buildSubagentRegistration } from "./register";
|
|
@@ -13,9 +13,9 @@ import { createSubagentHandler } from "./handler";
|
|
|
13
13
|
* Builds a fully wired tool entry for the Subagent tool,
|
|
14
14
|
* including per-subagent hook delegation.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* time getToolDefinitions() is called.
|
|
16
|
+
* Lazily evaluates `enabled` (supports `boolean | () => boolean`)
|
|
17
|
+
* so that `description` and `schema` reflect the current set of
|
|
18
|
+
* active subagents each time getToolDefinitions() is called.
|
|
19
19
|
*
|
|
20
20
|
* Returns null if no subagents are configured.
|
|
21
21
|
*/
|
|
@@ -24,7 +24,10 @@ export function buildSubagentRegistration(
|
|
|
24
24
|
): ToolMap[string] | null {
|
|
25
25
|
if (subagents.length === 0) return null;
|
|
26
26
|
|
|
27
|
-
const getEnabled = (): SubagentConfig[] =>
|
|
27
|
+
const getEnabled = (): SubagentConfig[] =>
|
|
28
|
+
subagents.filter((s) =>
|
|
29
|
+
typeof s.enabled === "function" ? s.enabled() : (s.enabled ?? true),
|
|
30
|
+
);
|
|
28
31
|
|
|
29
32
|
const subagentHooksMap = new Map<string, SubagentHooks>();
|
|
30
33
|
for (const s of subagents) {
|