zeitlich 0.2.49 → 0.2.51
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 +26 -23
- package/dist/adapters/sandbox/daytona/index.cjs.map +1 -1
- package/dist/adapters/sandbox/daytona/index.d.cts +3 -3
- package/dist/adapters/sandbox/daytona/index.d.ts +3 -3
- package/dist/adapters/sandbox/daytona/index.js.map +1 -1
- package/dist/adapters/sandbox/daytona/workflow.d.cts +2 -2
- package/dist/adapters/sandbox/daytona/workflow.d.ts +2 -2
- package/dist/adapters/sandbox/e2b/index.cjs.map +1 -1
- package/dist/adapters/sandbox/e2b/index.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/index.d.ts +1 -1
- package/dist/adapters/sandbox/e2b/index.js.map +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/e2b/workflow.d.ts +1 -1
- package/dist/adapters/thread/anthropic/index.cjs +60 -55
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +20 -15
- package/dist/adapters/thread/anthropic/index.d.ts +20 -15
- package/dist/adapters/thread/anthropic/index.js +60 -55
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +7 -7
- package/dist/adapters/thread/anthropic/workflow.d.ts +7 -7
- package/dist/adapters/thread/google-genai/index.cjs +135 -66
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +200 -26
- package/dist/adapters/thread/google-genai/index.d.ts +200 -26
- package/dist/adapters/thread/google-genai/index.js +135 -66
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +8 -8
- package/dist/adapters/thread/google-genai/workflow.d.ts +8 -8
- package/dist/adapters/thread/langchain/index.cjs +67 -55
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +20 -15
- package/dist/adapters/thread/langchain/index.d.ts +20 -15
- package/dist/adapters/thread/langchain/index.js +67 -55
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +7 -7
- package/dist/adapters/thread/langchain/workflow.d.ts +7 -7
- package/dist/{cold-store-DKMAO1Dd.d.ts → cold-store-DyHodfAB.d.ts} +1 -1
- package/dist/{cold-store-CkWoNtMh.d.cts → cold-store-YOx9nmgR.d.cts} +1 -1
- package/dist/index.cjs +15050 -420
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +79 -83
- package/dist/index.d.ts +79 -83
- package/dist/index.js +15051 -417
- package/dist/index.js.map +1 -1
- package/dist/{proxy-B7CWEV-T.d.cts → proxy-2htgGQrc.d.cts} +1 -1
- package/dist/{proxy-ByFHMVRX.d.ts → proxy-CmiTP4pp.d.ts} +1 -1
- package/dist/{thread-manager-nK-WcFzM.d.ts → thread-manager-BJ5pz5Cx.d.cts} +6 -7
- package/dist/{thread-manager-7AW4rhfu.d.ts → thread-manager-BQAbrYXH.d.cts} +6 -7
- package/dist/{thread-manager-Cibe0X5m.d.cts → thread-manager-CcvltOuq.d.ts} +6 -7
- package/dist/{thread-manager-B9rtMEVn.d.cts → thread-manager-DHAbncHX.d.ts} +6 -7
- package/dist/{types-gVa5XCWD.d.ts → types-BQvXWcft.d.ts} +1 -1
- package/dist/{types-XUUFvrJ9.d.cts → types-BjdqxKYp.d.cts} +709 -709
- package/dist/{types-CJ7tCdl6.d.ts → types-D8W5TnSa.d.cts} +3 -3
- package/dist/{types-CJ7tCdl6.d.cts → types-D8W5TnSa.d.ts} +3 -3
- package/dist/{types-DO4Tkwxo.d.ts → types-DEbkLA06.d.ts} +3 -3
- package/dist/{types-DeVNWqlb.d.ts → types-DiI7mZhI.d.ts} +709 -709
- package/dist/{types-BR-k7h0e.d.cts → types-N_LTWe4b.d.cts} +3 -3
- package/dist/{types-CjY93AWZ.d.cts → types-OEN1xrFg.d.cts} +1 -1
- package/dist/{workflow-uhOIj9D-.d.ts → workflow-CcgD6EUB.d.cts} +34 -3
- package/dist/{workflow-KbGsxpfh.d.cts → workflow-DBjPOKBr.d.ts} +34 -3
- package/dist/workflow.cjs +15008 -377
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +3 -3
- package/dist/workflow.d.ts +3 -3
- package/dist/workflow.js +15009 -374
- package/dist/workflow.js.map +1 -1
- package/package.json +10 -37
- package/src/adapters/thread/anthropic/activities.test.ts +115 -0
- package/src/adapters/thread/anthropic/activities.ts +11 -19
- package/src/adapters/thread/anthropic/fork-transform.test.ts +17 -11
- package/src/adapters/thread/anthropic/model-invoker.test.ts +54 -3
- package/src/adapters/thread/anthropic/model-invoker.ts +11 -1
- package/src/adapters/thread/anthropic/thread-manager.test.ts +2 -2
- package/src/adapters/thread/anthropic/thread-manager.ts +3 -4
- package/src/adapters/thread/google-genai/activities.test.ts +162 -0
- package/src/adapters/thread/google-genai/activities.ts +38 -15
- package/src/adapters/thread/google-genai/fork-transform.test.ts +17 -11
- package/src/adapters/thread/google-genai/model-invoker.test.ts +386 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +118 -23
- package/src/adapters/thread/google-genai/thread-manager.test.ts +2 -2
- package/src/adapters/thread/google-genai/thread-manager.ts +3 -4
- package/src/adapters/thread/langchain/activities.test.ts +88 -0
- package/src/adapters/thread/langchain/activities.ts +15 -12
- package/src/adapters/thread/langchain/fork-transform.test.ts +17 -11
- package/src/adapters/thread/langchain/model-invoker.test.ts +74 -0
- package/src/adapters/thread/langchain/model-invoker.ts +16 -3
- package/src/adapters/thread/langchain/thread-manager.test.ts +2 -2
- package/src/adapters/thread/langchain/thread-manager.ts +3 -4
- package/src/index.ts +2 -2
- package/src/lib/sandbox/capability-types.test.ts +2 -2
- package/src/lib/sandbox/manager.ts +2 -6
- package/src/lib/sandbox/sandbox.test.ts +1 -1
- package/src/lib/sandbox/types.ts +2 -2
- package/src/lib/session/session.integration.test.ts +92 -0
- package/src/lib/session/session.ts +23 -11
- package/src/lib/thread/keys.test.ts +9 -9
- package/src/lib/thread/keys.ts +1 -1
- package/src/lib/thread/manager.test.ts +24 -14
- package/src/lib/thread/manager.ts +19 -23
- package/src/lib/thread/snapshot.test.ts +51 -43
- package/src/lib/thread/snapshot.ts +54 -32
- package/src/lib/thread/test-utils.ts +106 -59
- package/src/lib/thread/tiered.test.ts +1 -1
- package/src/lib/thread/types.ts +2 -2
- package/src/lib/tool-router/router.integration.test.ts +44 -0
- package/src/lib/tool-router/router.ts +140 -32
- package/src/lib/workflow.ts +49 -0
- package/src/{adapters/sandbox/inmemory/proxy.ts → test-utils/in-memory-sandbox-proxy.ts} +5 -16
- package/src/{adapters/sandbox/inmemory/index.ts → test-utils/in-memory-sandbox.ts} +11 -3
- package/src/tools/bash/bash.test.ts +1 -1
- package/src/tools/edit/handler.test.ts +1 -1
- package/tsup.config.ts +2 -4
- package/dist/activities-7OcT_vdR.d.cts +0 -162
- package/dist/activities-zG_FBoY2.d.ts +0 -162
- package/dist/adapters/sandbox/inmemory/index.cjs +0 -214
- package/dist/adapters/sandbox/inmemory/index.cjs.map +0 -1
- package/dist/adapters/sandbox/inmemory/index.d.cts +0 -40
- package/dist/adapters/sandbox/inmemory/index.d.ts +0 -40
- package/dist/adapters/sandbox/inmemory/index.js +0 -211
- package/dist/adapters/sandbox/inmemory/index.js.map +0 -1
- package/dist/adapters/sandbox/inmemory/workflow.cjs +0 -36
- package/dist/adapters/sandbox/inmemory/workflow.cjs.map +0 -1
- package/dist/adapters/sandbox/inmemory/workflow.d.cts +0 -27
- package/dist/adapters/sandbox/inmemory/workflow.d.ts +0 -27
- package/dist/adapters/sandbox/inmemory/workflow.js +0 -34
- package/dist/adapters/sandbox/inmemory/workflow.js.map +0 -1
|
@@ -1,31 +1,82 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import '../../../
|
|
8
|
-
import '@aws-sdk/client-s3';
|
|
9
|
-
import '../../../types-DO4Tkwxo.js';
|
|
1
|
+
import { A as ADAPTER_ID } from '../../../adapter-id-BB-mmrts.js';
|
|
2
|
+
export { a as AdapterId } from '../../../adapter-id-BB-mmrts.js';
|
|
3
|
+
import { RedisClientType } from 'redis';
|
|
4
|
+
import { Part, Content, GoogleGenAI, GenerateContentConfig } from '@google/genai';
|
|
5
|
+
import { c as ModelInvokerConfig, d as AgentResponse, M as ModelInvoker, a as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, b as ToolHandlerResponse, A as ActivityToolHandler } from '../../../types-DiI7mZhI.js';
|
|
6
|
+
import { C as ColdThreadStore } from '../../../cold-store-DyHodfAB.js';
|
|
7
|
+
import { T as ThreadManagerHooks, P as ProviderThreadManager } from '../../../types-DEbkLA06.js';
|
|
10
8
|
import '@temporalio/workflow';
|
|
11
9
|
import '@temporalio/common/lib/interfaces';
|
|
12
10
|
import 'zod';
|
|
13
|
-
import '../../../types-
|
|
11
|
+
import '../../../types-D8W5TnSa.js';
|
|
14
12
|
import '@temporalio/common';
|
|
13
|
+
import '@aws-sdk/client-s3';
|
|
14
|
+
|
|
15
|
+
/** SDK-native content type for Google GenAI human messages */
|
|
16
|
+
type GoogleGenAIContent = string | Part[];
|
|
17
|
+
/** SDK-native content type for Google GenAI system instructions */
|
|
18
|
+
type GoogleGenAISystemContent = string | Part[];
|
|
19
|
+
/** A Content with a unique ID for idempotent Redis storage */
|
|
20
|
+
interface StoredContent {
|
|
21
|
+
id: string;
|
|
22
|
+
content: Content;
|
|
23
|
+
}
|
|
24
|
+
type GoogleGenAIThreadManagerHooks = ThreadManagerHooks<StoredContent, Content>;
|
|
25
|
+
interface GoogleGenAIThreadManagerConfig {
|
|
26
|
+
redis: RedisClientType;
|
|
27
|
+
threadId: string;
|
|
28
|
+
/** Thread key, defaults to 'messages' */
|
|
29
|
+
key?: string;
|
|
30
|
+
hooks?: GoogleGenAIThreadManagerHooks;
|
|
31
|
+
/**
|
|
32
|
+
* Redis TTL for the thread's keys; defaults to 90 days. Use a shorter
|
|
33
|
+
* value (hours) with a cold tier.
|
|
34
|
+
*/
|
|
35
|
+
ttlSeconds?: number;
|
|
36
|
+
}
|
|
37
|
+
/** Prepared payload ready to send to the Google GenAI API */
|
|
38
|
+
interface GoogleGenAIInvocationPayload {
|
|
39
|
+
contents: Content[];
|
|
40
|
+
systemInstruction?: Part[];
|
|
41
|
+
}
|
|
42
|
+
/** Thread manager with Google GenAI Content convenience helpers */
|
|
43
|
+
interface GoogleGenAIThreadManager extends ProviderThreadManager<StoredContent, GoogleGenAIContent, GoogleGenAIToolResponse, GoogleGenAISystemContent> {
|
|
44
|
+
appendModelContent(id: string, parts: Part[]): Promise<void>;
|
|
45
|
+
prepareForInvocation(): Promise<GoogleGenAIInvocationPayload>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a Google GenAI-specific thread manager that stores StoredContent
|
|
49
|
+
* instances in Redis and provides convenience helpers for creating and
|
|
50
|
+
* appending typed Content messages.
|
|
51
|
+
*/
|
|
52
|
+
declare function createGoogleGenAIThreadManager(config: GoogleGenAIThreadManagerConfig): GoogleGenAIThreadManager;
|
|
15
53
|
|
|
16
54
|
interface GoogleGenAIModelInvokerConfig {
|
|
17
|
-
redis:
|
|
55
|
+
redis: RedisClientType;
|
|
18
56
|
client: GoogleGenAI;
|
|
19
57
|
model: string;
|
|
20
58
|
hooks?: GoogleGenAIThreadManagerHooks;
|
|
59
|
+
/**
|
|
60
|
+
* Redis TTL for the thread's keys; defaults to 90 days. Use a shorter
|
|
61
|
+
* value (hours) with a cold tier. Distinct from `cache.ttlSeconds`
|
|
62
|
+
* (server-side context caching).
|
|
63
|
+
*/
|
|
64
|
+
ttlSeconds?: number;
|
|
65
|
+
/** Passed through to `generateContentStream().config`.
|
|
66
|
+
* `systemInstruction`, `tools`, and `abortSignal` are managed by the
|
|
67
|
+
* invoker and will override any values set here. */
|
|
68
|
+
config?: GenerateContentConfig;
|
|
69
|
+
/** Caches the first `splitIndex` messages server-side (with
|
|
70
|
+
* `systemInstruction`, `tools`, and `toolConfig`). Skipped when
|
|
71
|
+
* `contents.length <= splitIndex`. */
|
|
72
|
+
cache?: {
|
|
73
|
+
splitIndex: number;
|
|
74
|
+
/** Default: 300. */
|
|
75
|
+
ttlSeconds?: number;
|
|
76
|
+
};
|
|
21
77
|
}
|
|
22
78
|
/**
|
|
23
|
-
*
|
|
24
|
-
* `ModelInvoker<Content>` contract.
|
|
25
|
-
*
|
|
26
|
-
* Internally streams the response and emits Temporal heartbeats on each
|
|
27
|
-
* chunk so that long-running LLM calls remain visible to the scheduler.
|
|
28
|
-
* The caller is responsible for appending the response to the thread.
|
|
79
|
+
* The caller is responsible for appending the returned response to the thread.
|
|
29
80
|
*
|
|
30
81
|
* @example
|
|
31
82
|
* ```typescript
|
|
@@ -43,18 +94,141 @@ interface GoogleGenAIModelInvokerConfig {
|
|
|
43
94
|
* return { ...createRunAgentActivity(client, invoker, "myAgent") };
|
|
44
95
|
* ```
|
|
45
96
|
*/
|
|
46
|
-
declare function createGoogleGenAIModelInvoker({ redis, client, model, hooks, }: GoogleGenAIModelInvokerConfig): (config: ModelInvokerConfig) => Promise<AgentResponse<Content>>;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
* Convenience wrapper around createGoogleGenAIModelInvoker for cases
|
|
50
|
-
* where you don't need to reuse the invoker.
|
|
51
|
-
*/
|
|
52
|
-
declare function invokeGoogleGenAIModel({ redis, client, model, hooks, config, }: {
|
|
53
|
-
redis: Redis;
|
|
97
|
+
declare function createGoogleGenAIModelInvoker({ redis, client, model, hooks, ttlSeconds, config: generationConfig, cache: cacheConfig, }: GoogleGenAIModelInvokerConfig): (config: ModelInvokerConfig) => Promise<AgentResponse<Content>>;
|
|
98
|
+
declare function invokeGoogleGenAIModel({ redis, client, model, hooks, ttlSeconds, config, generationConfig, cache, }: {
|
|
99
|
+
redis: RedisClientType;
|
|
54
100
|
client: GoogleGenAI;
|
|
55
101
|
model: string;
|
|
56
102
|
hooks?: GoogleGenAIThreadManagerHooks;
|
|
103
|
+
ttlSeconds?: number;
|
|
57
104
|
config: ModelInvokerConfig;
|
|
105
|
+
generationConfig?: GenerateContentConfig;
|
|
106
|
+
cache?: GoogleGenAIModelInvokerConfig["cache"];
|
|
58
107
|
}): Promise<AgentResponse<Content>>;
|
|
59
108
|
|
|
60
|
-
|
|
109
|
+
type GoogleGenAIThreadOps<TScope extends string = ""> = PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_ID>, GoogleGenAIContent>;
|
|
110
|
+
interface GoogleGenAIAdapterConfig {
|
|
111
|
+
redis: RedisClientType;
|
|
112
|
+
client?: GoogleGenAI;
|
|
113
|
+
/** Default model name (e.g. 'gemini-2.5-flash'). If omitted, use `createModelInvoker()` */
|
|
114
|
+
model?: string;
|
|
115
|
+
hooks?: GoogleGenAIThreadManagerHooks;
|
|
116
|
+
/**
|
|
117
|
+
* Optional durable cold tier (e.g. S3, R2, GCS). When provided,
|
|
118
|
+
* the session hydrates the thread on entry (`continue`/`fork`) and
|
|
119
|
+
* flushes it on every exit path. When omitted, the adapter is
|
|
120
|
+
* Redis-only and `hydrateThread`/`flushThread` activities are no-ops.
|
|
121
|
+
*/
|
|
122
|
+
coldStore?: ColdThreadStore;
|
|
123
|
+
/**
|
|
124
|
+
* Redis TTL for the thread's keys; defaults to 90 days. Use a shorter
|
|
125
|
+
* value (hours) with a cold tier.
|
|
126
|
+
*/
|
|
127
|
+
ttlSeconds?: number;
|
|
128
|
+
/**
|
|
129
|
+
* Default generation config forwarded to every invoker the adapter
|
|
130
|
+
* builds (`invoker` and `createModelInvoker`). `systemInstruction`,
|
|
131
|
+
* `tools`, and `abortSignal` are managed by the invoker and override
|
|
132
|
+
* any values set here.
|
|
133
|
+
*/
|
|
134
|
+
generationConfig?: GenerateContentConfig;
|
|
135
|
+
/**
|
|
136
|
+
* Default server-side context caching config forwarded to every
|
|
137
|
+
* invoker the adapter builds. See {@link createGoogleGenAIModelInvoker}.
|
|
138
|
+
*/
|
|
139
|
+
cache?: GoogleGenAIModelInvokerConfig["cache"];
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Tool response type accepted by the Google GenAI adapter.
|
|
143
|
+
*
|
|
144
|
+
* Handlers can return:
|
|
145
|
+
* - **`string`** — plain text, wrapped in a `functionResponse` part.
|
|
146
|
+
* - **`Record<string, unknown>`** — structured object used as `functionResponse.response`.
|
|
147
|
+
* - **`Part[]`** — pre-built parts used directly as `Content.parts`.
|
|
148
|
+
* The handler is responsible for building correct Part objects (e.g. `functionResponse`,
|
|
149
|
+
* `inlineData`, `text`). Use `context.toolCallId` and `context.toolName` to construct
|
|
150
|
+
* `functionResponse` parts.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```typescript
|
|
154
|
+
* adapter.wrapHandler(async (args, ctx) => ({
|
|
155
|
+
* toolResponse: [
|
|
156
|
+
* { functionResponse: { id: ctx.toolCallId, name: ctx.toolName, response: { result: "done" } } },
|
|
157
|
+
* { inlineData: { data: base64, mimeType: "image/png" } },
|
|
158
|
+
* ],
|
|
159
|
+
* data: null,
|
|
160
|
+
* }));
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
type GoogleGenAIToolResponse = string | Record<string, unknown> | Part[];
|
|
164
|
+
interface GoogleGenAIAdapter {
|
|
165
|
+
/** Model invoker using the default model (only available when `model` was provided) */
|
|
166
|
+
invoker: ModelInvoker<Content>;
|
|
167
|
+
/** Create an invoker for a specific model name (for multi-model setups) */
|
|
168
|
+
createModelInvoker(model: string, client: GoogleGenAI): ModelInvoker<Content>;
|
|
169
|
+
/**
|
|
170
|
+
* Create prefixed thread activities for registration on the worker.
|
|
171
|
+
*
|
|
172
|
+
* @param scope - Workflow name appended to the adapter prefix.
|
|
173
|
+
* Use different scopes for the main agent vs subagents to avoid collisions.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* adapter.createActivities("codingAgent")
|
|
178
|
+
* // → { googleGenAICodingAgentInitializeThread, googleGenAICodingAgentAppendHumanMessage, … }
|
|
179
|
+
*
|
|
180
|
+
* adapter.createActivities("researchAgent")
|
|
181
|
+
* // → { googleGenAIResearchAgentInitializeThread, … }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
createActivities<S extends string = "">(scope?: S): GoogleGenAIThreadOps<S>;
|
|
185
|
+
/**
|
|
186
|
+
* Identity wrapper that types a tool handler for this adapter.
|
|
187
|
+
* Constrains `toolResponse` to {@link GoogleGenAIToolResponse}.
|
|
188
|
+
*/
|
|
189
|
+
wrapHandler<TArgs, TResult, TContext extends RouterContext = RouterContext>(handler: (args: TArgs, context: TContext) => Promise<ToolHandlerResponse<TResult, GoogleGenAIToolResponse>>): ActivityToolHandler<TArgs, TResult, TContext, GoogleGenAIToolResponse>;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Creates a Google GenAI adapter that bundles thread operations and model
|
|
193
|
+
* invocation using the `@google/genai` SDK.
|
|
194
|
+
*
|
|
195
|
+
* Use `createActivities(scope)` to register scoped thread operations as
|
|
196
|
+
* Temporal activities on the worker. The `invoker` (or invokers created via
|
|
197
|
+
* `createModelInvoker`) should be wrapped with `createRunAgentActivity`.
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* import { createGoogleGenAIAdapter } from 'zeitlich/adapters/thread/google-genai';
|
|
202
|
+
* import { createRunAgentActivity } from 'zeitlich';
|
|
203
|
+
* import { GoogleGenAI } from '@google/genai';
|
|
204
|
+
*
|
|
205
|
+
* const client = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
|
|
206
|
+
* const adapter = createGoogleGenAIAdapter({ redis, client, model: 'gemini-2.5-flash' });
|
|
207
|
+
*
|
|
208
|
+
* export function createActivities(temporalClient: WorkflowClient) {
|
|
209
|
+
* return {
|
|
210
|
+
* ...adapter.createActivities("codingAgent"),
|
|
211
|
+
* ...createRunAgentActivity(temporalClient, adapter.invoker, "codingAgent"),
|
|
212
|
+
* };
|
|
213
|
+
* }
|
|
214
|
+
* ```
|
|
215
|
+
*
|
|
216
|
+
* @example Multi-agent worker (main + subagent share the adapter)
|
|
217
|
+
* ```typescript
|
|
218
|
+
* export function createActivities(temporalClient: WorkflowClient) {
|
|
219
|
+
* return {
|
|
220
|
+
* ...adapter.createActivities("codingAgent"),
|
|
221
|
+
* ...adapter.createActivities("researchAgent"),
|
|
222
|
+
* ...createRunAgentActivity(temporalClient, adapter.invoker, "codingAgent"),
|
|
223
|
+
* ...createRunAgentActivity(
|
|
224
|
+
* temporalClient,
|
|
225
|
+
* adapter.createModelInvoker('gemini-2.5-pro', client),
|
|
226
|
+
* "researchAgent",
|
|
227
|
+
* ),
|
|
228
|
+
* };
|
|
229
|
+
* }
|
|
230
|
+
* ```
|
|
231
|
+
*/
|
|
232
|
+
declare function createGoogleGenAIAdapter(config: GoogleGenAIAdapterConfig): GoogleGenAIAdapter;
|
|
233
|
+
|
|
234
|
+
export { ADAPTER_ID, type GoogleGenAIAdapter, type GoogleGenAIAdapterConfig, type GoogleGenAIContent, type GoogleGenAIInvocationPayload, type GoogleGenAIModelInvokerConfig, type GoogleGenAIThreadManager, type GoogleGenAIThreadManagerConfig, type GoogleGenAIThreadOps, type GoogleGenAIToolResponse, type StoredContent, createGoogleGenAIAdapter, createGoogleGenAIModelInvoker, createGoogleGenAIThreadManager, invokeGoogleGenAIModel };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomBytes } from 'crypto';
|
|
1
2
|
import { Context } from '@temporalio/activity';
|
|
2
3
|
|
|
3
4
|
// src/adapters/thread/google-genai/adapter-id.ts
|
|
@@ -53,11 +54,11 @@ function createThreadManager(config) {
|
|
|
53
54
|
return {
|
|
54
55
|
async initialize() {
|
|
55
56
|
await redis.del(redisKey);
|
|
56
|
-
await redis.set(metaKey, "1",
|
|
57
|
+
await redis.set(metaKey, "1", { EX: ttlSeconds });
|
|
57
58
|
},
|
|
58
59
|
async load() {
|
|
59
60
|
await assertThreadExists();
|
|
60
|
-
const data = await redis.
|
|
61
|
+
const data = await redis.lRange(redisKey, 0, -1);
|
|
61
62
|
return data.map(deserialize);
|
|
62
63
|
},
|
|
63
64
|
async append(messages) {
|
|
@@ -65,22 +66,18 @@ function createThreadManager(config) {
|
|
|
65
66
|
await assertThreadExists();
|
|
66
67
|
if (idOf) {
|
|
67
68
|
const dedupId = messages.map(idOf).join(":");
|
|
68
|
-
await redis.eval(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
redisKey,
|
|
73
|
-
String(ttlSeconds),
|
|
74
|
-
...messages.map(serialize)
|
|
75
|
-
);
|
|
69
|
+
await redis.eval(APPEND_IDEMPOTENT_SCRIPT, {
|
|
70
|
+
keys: [dedupKey(dedupId), redisKey],
|
|
71
|
+
arguments: [String(ttlSeconds), ...messages.map(serialize)]
|
|
72
|
+
});
|
|
76
73
|
} else {
|
|
77
|
-
await redis.
|
|
74
|
+
await redis.rPush(redisKey, messages.map(serialize));
|
|
78
75
|
await redis.expire(redisKey, ttlSeconds);
|
|
79
76
|
}
|
|
80
77
|
},
|
|
81
78
|
async fork(newThreadId) {
|
|
82
79
|
await assertThreadExists();
|
|
83
|
-
const data = await redis.
|
|
80
|
+
const data = await redis.lRange(redisKey, 0, -1);
|
|
84
81
|
const stateRaw = await redis.get(stateKey);
|
|
85
82
|
const forked = createThreadManager({
|
|
86
83
|
...config,
|
|
@@ -89,12 +86,12 @@ function createThreadManager(config) {
|
|
|
89
86
|
await forked.initialize();
|
|
90
87
|
if (data.length > 0) {
|
|
91
88
|
const newKey = getThreadListKey(key, newThreadId);
|
|
92
|
-
await redis.
|
|
89
|
+
await redis.rPush(newKey, data);
|
|
93
90
|
await redis.expire(newKey, ttlSeconds);
|
|
94
91
|
}
|
|
95
92
|
if (stateRaw != null) {
|
|
96
93
|
const newStateKey = getThreadStateKey(key, newThreadId);
|
|
97
|
-
await redis.set(newStateKey, stateRaw,
|
|
94
|
+
await redis.set(newStateKey, stateRaw, { EX: ttlSeconds });
|
|
98
95
|
}
|
|
99
96
|
return forked;
|
|
100
97
|
},
|
|
@@ -105,20 +102,20 @@ function createThreadManager(config) {
|
|
|
105
102
|
"replaceAll requires the thread manager to be configured with `idOf`"
|
|
106
103
|
);
|
|
107
104
|
}
|
|
108
|
-
const existing = await redis.
|
|
105
|
+
const existing = await redis.lRange(redisKey, 0, -1);
|
|
109
106
|
const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
|
|
110
107
|
await redis.del(redisKey);
|
|
111
108
|
if (existingIds.length > 0) {
|
|
112
|
-
await redis.del(
|
|
109
|
+
await redis.del(existingIds.map(dedupKey));
|
|
113
110
|
}
|
|
114
111
|
if (messages.length > 0) {
|
|
115
|
-
await redis.
|
|
112
|
+
await redis.rPush(redisKey, messages.map(serialize));
|
|
116
113
|
await redis.expire(redisKey, ttlSeconds);
|
|
117
114
|
}
|
|
118
115
|
await redis.expire(metaKey, ttlSeconds);
|
|
119
116
|
},
|
|
120
117
|
async delete() {
|
|
121
|
-
await redis.del(redisKey, metaKey, stateKey);
|
|
118
|
+
await redis.del([redisKey, metaKey, stateKey]);
|
|
122
119
|
},
|
|
123
120
|
async loadState() {
|
|
124
121
|
const raw = await redis.get(stateKey);
|
|
@@ -127,14 +124,14 @@ function createThreadManager(config) {
|
|
|
127
124
|
},
|
|
128
125
|
async saveState(state) {
|
|
129
126
|
await assertThreadExists();
|
|
130
|
-
await redis.set(stateKey, JSON.stringify(state),
|
|
127
|
+
await redis.set(stateKey, JSON.stringify(state), { EX: ttlSeconds });
|
|
131
128
|
},
|
|
132
129
|
async deleteState() {
|
|
133
130
|
await redis.del(stateKey);
|
|
134
131
|
},
|
|
135
132
|
async length() {
|
|
136
133
|
await assertThreadExists();
|
|
137
|
-
return redis.
|
|
134
|
+
return redis.lLen(redisKey);
|
|
138
135
|
},
|
|
139
136
|
async truncateFromId(messageId) {
|
|
140
137
|
await assertThreadExists();
|
|
@@ -143,7 +140,7 @@ function createThreadManager(config) {
|
|
|
143
140
|
"truncateFromId requires the thread manager to be configured with `idOf`"
|
|
144
141
|
);
|
|
145
142
|
}
|
|
146
|
-
const data = await redis.
|
|
143
|
+
const data = await redis.lRange(redisKey, 0, -1);
|
|
147
144
|
let idx = -1;
|
|
148
145
|
const removedIds = [];
|
|
149
146
|
for (let i = 0; i < data.length; i++) {
|
|
@@ -158,11 +155,11 @@ function createThreadManager(config) {
|
|
|
158
155
|
await redis.del(redisKey);
|
|
159
156
|
await redis.expire(metaKey, ttlSeconds);
|
|
160
157
|
} else {
|
|
161
|
-
await redis.
|
|
158
|
+
await redis.lTrim(redisKey, 0, idx - 1);
|
|
162
159
|
await redis.expire(redisKey, ttlSeconds);
|
|
163
160
|
}
|
|
164
161
|
if (removedIds.length > 0) {
|
|
165
|
-
await redis.del(
|
|
162
|
+
await redis.del(removedIds.map(dedupKey));
|
|
166
163
|
}
|
|
167
164
|
}
|
|
168
165
|
};
|
|
@@ -177,7 +174,7 @@ async function encodeSnapshot(config) {
|
|
|
177
174
|
}
|
|
178
175
|
const listKey = getThreadListKey(threadKey, threadId);
|
|
179
176
|
const stateKey = getThreadStateKey(threadKey, threadId);
|
|
180
|
-
const messages = await redis.
|
|
177
|
+
const messages = await redis.lRange(listKey, 0, -1);
|
|
181
178
|
const stateRaw = await redis.get(stateKey);
|
|
182
179
|
const state = stateRaw == null ? null : JSON.parse(stateRaw);
|
|
183
180
|
const dedupIds = idOf ? messages.map(idOf) : [];
|
|
@@ -197,31 +194,38 @@ async function applySnapshot(config) {
|
|
|
197
194
|
}
|
|
198
195
|
const listKey = getThreadListKey(threadKey, threadId);
|
|
199
196
|
const stateKey = getThreadStateKey(threadKey, threadId);
|
|
200
|
-
await redis.del(listKey, stateKey);
|
|
201
|
-
const pipeline = redis.
|
|
197
|
+
await redis.del([listKey, stateKey]);
|
|
198
|
+
const pipeline = redis.multi();
|
|
202
199
|
if (snapshot.messages.length > 0) {
|
|
203
|
-
pipeline.
|
|
200
|
+
pipeline.rPush(listKey, snapshot.messages);
|
|
204
201
|
pipeline.expire(listKey, ttlSeconds);
|
|
205
202
|
}
|
|
206
203
|
if (snapshot.state != null) {
|
|
207
|
-
pipeline.set(stateKey, JSON.stringify(snapshot.state),
|
|
204
|
+
pipeline.set(stateKey, JSON.stringify(snapshot.state), { EX: ttlSeconds });
|
|
208
205
|
}
|
|
209
206
|
for (const id of snapshot.dedupIds) {
|
|
210
|
-
pipeline.set(getThreadDedupKey(threadId, id), "1",
|
|
207
|
+
pipeline.set(getThreadDedupKey(threadId, id), "1", { EX: ttlSeconds });
|
|
211
208
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
209
|
+
try {
|
|
210
|
+
await pipeline.execAsPipeline();
|
|
211
|
+
} catch (err) {
|
|
212
|
+
await redis.del([
|
|
213
|
+
listKey,
|
|
214
|
+
stateKey,
|
|
215
|
+
...snapshot.dedupIds.map((id) => getThreadDedupKey(threadId, id))
|
|
216
|
+
]).catch(() => void 0);
|
|
217
|
+
throw firstPipelineError(err);
|
|
218
|
+
}
|
|
219
|
+
await redis.set(metaKey, "1", { EX: ttlSeconds });
|
|
220
|
+
}
|
|
221
|
+
function firstPipelineError(err) {
|
|
222
|
+
if (err != null && typeof err === "object" && "replies" in err && Array.isArray(err.replies)) {
|
|
223
|
+
const firstErr = err.replies.find(
|
|
224
|
+
(r) => r instanceof Error
|
|
225
|
+
);
|
|
226
|
+
if (firstErr) return firstErr;
|
|
223
227
|
}
|
|
224
|
-
|
|
228
|
+
return err;
|
|
225
229
|
}
|
|
226
230
|
async function clearHotTier(config) {
|
|
227
231
|
const { redis, threadKey, threadId, dedupIds = [] } = config;
|
|
@@ -231,7 +235,7 @@ async function clearHotTier(config) {
|
|
|
231
235
|
getThreadStateKey(threadKey, threadId),
|
|
232
236
|
...dedupIds.map((id) => getThreadDedupKey(threadId, id))
|
|
233
237
|
];
|
|
234
|
-
await redis.del(
|
|
238
|
+
await redis.del(keys);
|
|
235
239
|
}
|
|
236
240
|
|
|
237
241
|
// src/lib/thread/tiered.ts
|
|
@@ -429,7 +433,10 @@ function createGoogleGenAIModelInvoker({
|
|
|
429
433
|
redis,
|
|
430
434
|
client,
|
|
431
435
|
model,
|
|
432
|
-
hooks
|
|
436
|
+
hooks,
|
|
437
|
+
ttlSeconds,
|
|
438
|
+
config: generationConfig,
|
|
439
|
+
cache: cacheConfig
|
|
433
440
|
}) {
|
|
434
441
|
return async function invokeGoogleGenAIModel2(config) {
|
|
435
442
|
const { threadId, threadKey, state, assistantMessageId } = config;
|
|
@@ -438,18 +445,64 @@ function createGoogleGenAIModelInvoker({
|
|
|
438
445
|
redis,
|
|
439
446
|
threadId,
|
|
440
447
|
key: threadKey,
|
|
441
|
-
hooks
|
|
448
|
+
hooks,
|
|
449
|
+
...ttlSeconds !== void 0 && { ttlSeconds }
|
|
442
450
|
});
|
|
443
451
|
await thread.truncateFromId(assistantMessageId);
|
|
444
452
|
const { contents, systemInstruction } = await thread.prepareForInvocation();
|
|
445
453
|
const functionDeclarations = toFunctionDeclarations(state.tools);
|
|
446
454
|
const tools = functionDeclarations.length > 0 ? [{ functionDeclarations }] : void 0;
|
|
455
|
+
const {
|
|
456
|
+
systemInstruction: _si,
|
|
457
|
+
tools: _t,
|
|
458
|
+
abortSignal: _as,
|
|
459
|
+
cachedContent: callerCachedContent,
|
|
460
|
+
toolConfig: callerToolConfig,
|
|
461
|
+
...callerConfig
|
|
462
|
+
} = generationConfig ?? {};
|
|
463
|
+
let liveContents = contents;
|
|
464
|
+
let cachedContentName;
|
|
465
|
+
let cachedWriteTokens;
|
|
466
|
+
if (cacheConfig && cacheConfig.splitIndex > 0 && contents.length > cacheConfig.splitIndex) {
|
|
467
|
+
liveContents = contents.slice(cacheConfig.splitIndex);
|
|
468
|
+
const ttl = cacheConfig.ttlSeconds ?? 300;
|
|
469
|
+
const cacheRedisKey = `${threadKey ?? "messages"}:gemini-cache:${model}:${cacheConfig.splitIndex}:thread:${threadId}`;
|
|
470
|
+
cachedContentName = await redis.get(cacheRedisKey) ?? void 0;
|
|
471
|
+
if (!cachedContentName) {
|
|
472
|
+
const cacheInstance = await client.caches.create({
|
|
473
|
+
model,
|
|
474
|
+
config: {
|
|
475
|
+
contents: contents.slice(0, cacheConfig.splitIndex),
|
|
476
|
+
...systemInstruction ? { systemInstruction } : {},
|
|
477
|
+
...tools ? { tools } : {},
|
|
478
|
+
...callerToolConfig ? { toolConfig: callerToolConfig } : {},
|
|
479
|
+
ttl: `${ttl}s`,
|
|
480
|
+
abortSignal: signal
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
if (!cacheInstance?.name) {
|
|
484
|
+
throw new Error("Gemini cache creation did not return a cache name");
|
|
485
|
+
}
|
|
486
|
+
cachedContentName = cacheInstance.name;
|
|
487
|
+
cachedWriteTokens = cacheInstance.usageMetadata?.totalTokenCount ?? void 0;
|
|
488
|
+
const redisTtl = ttl - 5;
|
|
489
|
+
if (redisTtl > 0) {
|
|
490
|
+
await redis.set(cacheRedisKey, cachedContentName, { EX: redisTtl });
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
}
|
|
447
494
|
const stream = await client.models.generateContentStream({
|
|
448
495
|
model,
|
|
449
|
-
contents,
|
|
496
|
+
contents: liveContents,
|
|
450
497
|
config: {
|
|
451
|
-
...
|
|
452
|
-
...
|
|
498
|
+
...callerConfig,
|
|
499
|
+
...cachedContentName ? { cachedContent: cachedContentName } : {
|
|
500
|
+
...callerCachedContent ? { cachedContent: callerCachedContent } : {
|
|
501
|
+
...systemInstruction ? { systemInstruction } : {},
|
|
502
|
+
...tools ? { tools } : {}
|
|
503
|
+
},
|
|
504
|
+
...callerToolConfig ? { toolConfig: callerToolConfig } : {}
|
|
505
|
+
},
|
|
453
506
|
abortSignal: signal
|
|
454
507
|
}
|
|
455
508
|
});
|
|
@@ -463,19 +516,27 @@ function createGoogleGenAIModelInvoker({
|
|
|
463
516
|
if (!lastChunk) {
|
|
464
517
|
throw new Error("Google GenAI stream ended without producing any chunks");
|
|
465
518
|
}
|
|
519
|
+
for (const part of allParts) {
|
|
520
|
+
if (part.functionCall && !part.functionCall.id) {
|
|
521
|
+
part.functionCall.id = randomBytes(8).toString("hex");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
466
524
|
const modelContent = { role: "model", parts: allParts };
|
|
467
|
-
const functionCalls = lastChunk.functionCalls ?? [];
|
|
468
525
|
return {
|
|
469
526
|
message: modelContent,
|
|
470
|
-
rawToolCalls:
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
527
|
+
rawToolCalls: allParts.filter(
|
|
528
|
+
(p) => !!p.functionCall
|
|
529
|
+
).map((p) => ({
|
|
530
|
+
id: p.functionCall.id,
|
|
531
|
+
name: p.functionCall.name ?? "",
|
|
532
|
+
args: p.functionCall.args ?? {}
|
|
474
533
|
})),
|
|
475
534
|
usage: {
|
|
476
535
|
inputTokens: lastChunk.usageMetadata?.promptTokenCount,
|
|
477
536
|
outputTokens: lastChunk.usageMetadata?.candidatesTokenCount,
|
|
478
|
-
|
|
537
|
+
cachedWriteTokens,
|
|
538
|
+
cachedReadTokens: lastChunk.usageMetadata?.cachedContentTokenCount,
|
|
539
|
+
reasonTokens: lastChunk.usageMetadata?.thoughtsTokenCount
|
|
479
540
|
}
|
|
480
541
|
};
|
|
481
542
|
};
|
|
@@ -485,13 +546,19 @@ async function invokeGoogleGenAIModel({
|
|
|
485
546
|
client,
|
|
486
547
|
model,
|
|
487
548
|
hooks,
|
|
488
|
-
|
|
549
|
+
ttlSeconds,
|
|
550
|
+
config,
|
|
551
|
+
generationConfig,
|
|
552
|
+
cache
|
|
489
553
|
}) {
|
|
490
554
|
const invoker = createGoogleGenAIModelInvoker({
|
|
491
555
|
redis,
|
|
492
556
|
client,
|
|
493
557
|
model,
|
|
494
|
-
hooks
|
|
558
|
+
hooks,
|
|
559
|
+
...ttlSeconds !== void 0 && { ttlSeconds },
|
|
560
|
+
config: generationConfig,
|
|
561
|
+
cache
|
|
495
562
|
});
|
|
496
563
|
return invoker(config);
|
|
497
564
|
}
|
|
@@ -499,21 +566,20 @@ async function invokeGoogleGenAIModel({
|
|
|
499
566
|
// src/adapters/thread/google-genai/activities.ts
|
|
500
567
|
function createGoogleGenAIAdapter(config) {
|
|
501
568
|
const { redis } = config;
|
|
502
|
-
const
|
|
569
|
+
const base = {
|
|
570
|
+
redis,
|
|
503
571
|
...config.ttlSeconds !== void 0 && { ttlSeconds: config.ttlSeconds }
|
|
504
572
|
};
|
|
505
573
|
const makeProviderThread = (threadId, threadKey) => createGoogleGenAIThreadManager({
|
|
506
|
-
|
|
574
|
+
...base,
|
|
507
575
|
threadId,
|
|
508
|
-
key: threadKey
|
|
509
|
-
...baseExtras
|
|
576
|
+
key: threadKey
|
|
510
577
|
});
|
|
511
578
|
const makeTieredBase = (threadId, threadKey) => createTieredThreadManager({
|
|
512
|
-
|
|
579
|
+
...base,
|
|
513
580
|
threadId,
|
|
514
581
|
key: threadKey,
|
|
515
582
|
idOf: storedContentId,
|
|
516
|
-
...baseExtras,
|
|
517
583
|
...config.coldStore && { coldStore: config.coldStore }
|
|
518
584
|
});
|
|
519
585
|
const threadOps = {
|
|
@@ -545,11 +611,10 @@ function createGoogleGenAIAdapter(config) {
|
|
|
545
611
|
},
|
|
546
612
|
async forkThread(sourceThreadId, targetThreadId, threadKey) {
|
|
547
613
|
const thread = createGoogleGenAIThreadManager({
|
|
548
|
-
|
|
614
|
+
...base,
|
|
549
615
|
threadId: sourceThreadId,
|
|
550
616
|
key: threadKey,
|
|
551
|
-
hooks: config.hooks
|
|
552
|
-
...baseExtras
|
|
617
|
+
hooks: config.hooks
|
|
553
618
|
});
|
|
554
619
|
await thread.fork(targetThreadId);
|
|
555
620
|
},
|
|
@@ -582,10 +647,14 @@ function createGoogleGenAIAdapter(config) {
|
|
|
582
647
|
);
|
|
583
648
|
}
|
|
584
649
|
const makeInvoker = (model, client) => createGoogleGenAIModelInvoker({
|
|
585
|
-
|
|
650
|
+
...base,
|
|
586
651
|
client,
|
|
587
652
|
model,
|
|
588
|
-
hooks: config.hooks
|
|
653
|
+
hooks: config.hooks,
|
|
654
|
+
...config.generationConfig !== void 0 && {
|
|
655
|
+
config: config.generationConfig
|
|
656
|
+
},
|
|
657
|
+
...config.cache !== void 0 && { cache: config.cache }
|
|
589
658
|
});
|
|
590
659
|
const invoker = config.model && config.client ? makeInvoker(config.model, config.client) : (() => {
|
|
591
660
|
throw new Error(
|