zeitlich 0.2.24 → 0.2.26
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/activities-BEJRyDVU.d.cts +137 -0
- package/dist/activities-LVQdLF6I.d.ts +137 -0
- package/dist/adapters/sandbox/bedrock/index.cjs +35 -10
- package/dist/adapters/sandbox/bedrock/index.cjs.map +1 -1
- package/dist/adapters/sandbox/bedrock/index.d.cts +2 -2
- package/dist/adapters/sandbox/bedrock/index.d.ts +2 -2
- package/dist/adapters/sandbox/bedrock/index.js +35 -10
- package/dist/adapters/sandbox/bedrock/index.js.map +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.cts +1 -1
- package/dist/adapters/sandbox/bedrock/workflow.d.ts +1 -1
- package/dist/adapters/sandbox/virtual/index.cjs.map +1 -1
- package/dist/adapters/sandbox/virtual/index.d.cts +8 -7
- package/dist/adapters/sandbox/virtual/index.d.ts +8 -7
- package/dist/adapters/sandbox/virtual/index.js.map +1 -1
- package/dist/adapters/sandbox/virtual/workflow.d.cts +3 -2
- package/dist/adapters/sandbox/virtual/workflow.d.ts +3 -2
- package/dist/adapters/thread/anthropic/index.cjs +356 -0
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -0
- package/dist/adapters/thread/anthropic/index.d.cts +148 -0
- package/dist/adapters/thread/anthropic/index.d.ts +148 -0
- package/dist/adapters/thread/anthropic/index.js +351 -0
- package/dist/adapters/thread/anthropic/index.js.map +1 -0
- package/dist/adapters/thread/anthropic/workflow.cjs +38 -0
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -0
- package/dist/adapters/thread/anthropic/workflow.d.cts +37 -0
- package/dist/adapters/thread/anthropic/workflow.d.ts +37 -0
- package/dist/adapters/thread/anthropic/workflow.js +36 -0
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -0
- package/dist/adapters/thread/google-genai/index.cjs +95 -97
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +9 -111
- package/dist/adapters/thread/google-genai/index.d.ts +9 -111
- package/dist/adapters/thread/google-genai/index.js +96 -97
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +9 -4
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +10 -5
- package/dist/adapters/thread/google-genai/workflow.d.ts +10 -5
- package/dist/adapters/thread/google-genai/workflow.js +9 -4
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/langchain/index.cjs +43 -60
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +24 -38
- package/dist/adapters/thread/langchain/index.d.ts +24 -38
- package/dist/adapters/thread/langchain/index.js +43 -60
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +9 -4
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +10 -5
- package/dist/adapters/thread/langchain/workflow.d.ts +10 -5
- package/dist/adapters/thread/langchain/workflow.js +9 -4
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +30 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -12
- package/dist/index.d.ts +13 -12
- package/dist/index.js +31 -13
- package/dist/index.js.map +1 -1
- package/dist/proxy-BK1ydQt0.d.ts +24 -0
- package/dist/proxy-BMAsMHdp.d.cts +24 -0
- package/dist/{queries-DwBe2CAA.d.ts → queries-BCgJ9Sr5.d.ts} +1 -1
- package/dist/{queries-BYGBImeC.d.cts → queries-DwnE2bu3.d.cts} +1 -1
- package/dist/thread-manager-CH9krS3h.d.ts +37 -0
- package/dist/thread-manager-Czhpxbt6.d.ts +29 -0
- package/dist/thread-manager-DOnQzImf.d.cts +29 -0
- package/dist/thread-manager-b4DML-qu.d.cts +37 -0
- package/dist/{types-35POpVfa.d.ts → types-BDRDbm3h.d.cts} +22 -1
- package/dist/{types-d9NznUqd.d.ts → types-BdCdR41N.d.ts} +10 -0
- package/dist/{types-hmferhc2.d.ts → types-CvJyXDYt.d.ts} +44 -123
- package/dist/{types-LVKmCNds.d.ts → types-DFUNSYbj.d.ts} +1 -1
- package/dist/{types-Bf8KV0Ci.d.cts → types-DRnz-OZp.d.cts} +1 -1
- package/dist/{types-7PeMi1bD.d.cts → types-DSOefLpY.d.cts} +44 -123
- package/dist/{types-35POpVfa.d.cts → types-WNSeZbWa.d.ts} +22 -1
- package/dist/{types-DhTCEMhr.d.cts → types-ZHs2v9Ap.d.cts} +10 -0
- package/dist/{types-D_igp10o.d.cts → types-mCVxKIZb.d.cts} +233 -137
- package/dist/{types-D_igp10o.d.ts → types-mCVxKIZb.d.ts} +233 -137
- package/dist/workflow.cjs +28 -11
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +11 -11
- package/dist/workflow.d.ts +11 -11
- package/dist/workflow.js +29 -12
- package/dist/workflow.js.map +1 -1
- package/package.json +26 -1
- package/src/adapters/sandbox/bedrock/filesystem.ts +43 -10
- package/src/adapters/sandbox/virtual/with-virtual-sandbox.ts +8 -3
- package/src/adapters/thread/anthropic/activities.ts +223 -0
- package/src/adapters/thread/anthropic/index.ts +44 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +124 -0
- package/src/adapters/thread/anthropic/proxy.ts +33 -0
- package/src/adapters/thread/anthropic/thread-manager.ts +191 -0
- package/src/adapters/thread/google-genai/activities.ts +107 -32
- package/src/adapters/thread/google-genai/index.ts +3 -1
- package/src/adapters/thread/google-genai/model-invoker.ts +7 -40
- package/src/adapters/thread/google-genai/proxy.ts +6 -34
- package/src/adapters/thread/google-genai/thread-manager.ts +84 -104
- package/src/adapters/thread/langchain/activities.ts +53 -20
- package/src/adapters/thread/langchain/index.ts +3 -1
- package/src/adapters/thread/langchain/model-invoker.ts +7 -9
- package/src/adapters/thread/langchain/proxy.ts +6 -34
- package/src/adapters/thread/langchain/thread-manager.ts +44 -98
- package/src/index.ts +5 -1
- package/src/lib/activity.ts +4 -3
- package/src/lib/hooks/types.ts +12 -12
- package/src/lib/model/types.ts +2 -0
- package/src/lib/session/session-edge-cases.integration.test.ts +24 -6
- package/src/lib/session/session.ts +18 -14
- package/src/lib/session/types.ts +31 -14
- package/src/lib/subagent/handler.ts +20 -11
- package/src/lib/subagent/subagent.integration.test.ts +36 -4
- package/src/lib/subagent/types.ts +3 -2
- package/src/lib/thread/index.ts +2 -0
- package/src/lib/thread/manager.ts +4 -7
- package/src/lib/thread/proxy.ts +57 -0
- package/src/lib/thread/types.ts +31 -0
- package/src/lib/tool-router/auto-append-sandbox.integration.test.ts +54 -0
- package/src/lib/tool-router/auto-append.ts +5 -2
- package/src/lib/tool-router/router-edge-cases.integration.test.ts +9 -5
- package/src/lib/tool-router/router.ts +13 -7
- package/src/lib/tool-router/types.ts +20 -13
- package/src/lib/tool-router/with-sandbox.ts +4 -3
- package/src/lib/types.ts +7 -14
- package/src/workflow.ts +0 -4
- package/tsup.config.ts +5 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type Redis from "ioredis";
|
|
2
|
+
import type Anthropic from "@anthropic-ai/sdk";
|
|
3
|
+
import type { JsonValue } from "../../../lib/state/types";
|
|
4
|
+
import {
|
|
5
|
+
createThreadManager,
|
|
6
|
+
type ProviderThreadManager,
|
|
7
|
+
type ThreadManagerConfig,
|
|
8
|
+
} from "../../../lib/thread";
|
|
9
|
+
|
|
10
|
+
/** SDK-native content type for Anthropic human messages */
|
|
11
|
+
export type AnthropicContent =
|
|
12
|
+
| string
|
|
13
|
+
| Anthropic.Messages.ContentBlockParam[];
|
|
14
|
+
|
|
15
|
+
/** A MessageParam with a unique ID for idempotent Redis storage */
|
|
16
|
+
export interface StoredMessage {
|
|
17
|
+
id: string;
|
|
18
|
+
message: Anthropic.Messages.MessageParam;
|
|
19
|
+
/** System messages are stored separately since Anthropic passes them via config */
|
|
20
|
+
isSystem?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface AnthropicThreadManagerConfig {
|
|
24
|
+
redis: Redis;
|
|
25
|
+
threadId: string;
|
|
26
|
+
/** Thread key, defaults to 'messages' */
|
|
27
|
+
key?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Prepared payload ready to send to the Anthropic API */
|
|
31
|
+
export interface AnthropicInvocationPayload {
|
|
32
|
+
messages: Anthropic.Messages.MessageParam[];
|
|
33
|
+
system?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Thread manager with Anthropic MessageParam convenience helpers */
|
|
37
|
+
export interface AnthropicThreadManager
|
|
38
|
+
extends ProviderThreadManager<StoredMessage, AnthropicContent> {
|
|
39
|
+
appendAssistantMessage(
|
|
40
|
+
id: string,
|
|
41
|
+
content: Anthropic.Messages.ContentBlock[],
|
|
42
|
+
): Promise<void>;
|
|
43
|
+
prepareForInvocation(): Promise<AnthropicInvocationPayload>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function storedMessageId(msg: StoredMessage): string {
|
|
47
|
+
return msg.id;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Normalise content into an array of ContentBlockParam */
|
|
51
|
+
function toContentBlocks(
|
|
52
|
+
content: AnthropicContent,
|
|
53
|
+
): Anthropic.Messages.ContentBlockParam[] {
|
|
54
|
+
if (typeof content === "string") {
|
|
55
|
+
return [{ type: "text", text: content }];
|
|
56
|
+
}
|
|
57
|
+
return content;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Merge consecutive messages with the same role.
|
|
62
|
+
* The Anthropic API requires alternating user/assistant turns; without
|
|
63
|
+
* merging, multiple sequential tool-result messages would violate this.
|
|
64
|
+
*/
|
|
65
|
+
function mergeConsecutiveMessages(
|
|
66
|
+
messages: Anthropic.Messages.MessageParam[],
|
|
67
|
+
): Anthropic.Messages.MessageParam[] {
|
|
68
|
+
const merged: Anthropic.Messages.MessageParam[] = [];
|
|
69
|
+
for (const msg of messages) {
|
|
70
|
+
const last = merged[merged.length - 1];
|
|
71
|
+
if (last && last.role === msg.role) {
|
|
72
|
+
const lastContent = Array.isArray(last.content)
|
|
73
|
+
? last.content
|
|
74
|
+
: [{ type: "text" as const, text: last.content }];
|
|
75
|
+
const msgContent = Array.isArray(msg.content)
|
|
76
|
+
? msg.content
|
|
77
|
+
: [{ type: "text" as const, text: msg.content }];
|
|
78
|
+
last.content = [...lastContent, ...msgContent];
|
|
79
|
+
} else {
|
|
80
|
+
merged.push({
|
|
81
|
+
...msg,
|
|
82
|
+
content: Array.isArray(msg.content)
|
|
83
|
+
? [...msg.content]
|
|
84
|
+
: msg.content,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return merged;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Creates an Anthropic-specific thread manager that stores StoredMessage
|
|
93
|
+
* instances in Redis and provides convenience helpers for creating and
|
|
94
|
+
* appending typed messages.
|
|
95
|
+
*/
|
|
96
|
+
export function createAnthropicThreadManager(
|
|
97
|
+
config: AnthropicThreadManagerConfig,
|
|
98
|
+
): AnthropicThreadManager {
|
|
99
|
+
const baseConfig: ThreadManagerConfig<StoredMessage> = {
|
|
100
|
+
redis: config.redis,
|
|
101
|
+
threadId: config.threadId,
|
|
102
|
+
key: config.key,
|
|
103
|
+
idOf: storedMessageId,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const base = createThreadManager(baseConfig);
|
|
107
|
+
|
|
108
|
+
const helpers: Omit<AnthropicThreadManager, keyof typeof base> = {
|
|
109
|
+
async appendUserMessage(
|
|
110
|
+
id: string,
|
|
111
|
+
content: AnthropicContent,
|
|
112
|
+
): Promise<void> {
|
|
113
|
+
await base.append([{
|
|
114
|
+
id,
|
|
115
|
+
message: { role: "user", content: toContentBlocks(content) },
|
|
116
|
+
}]);
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
async appendSystemMessage(id: string, content: string): Promise<void> {
|
|
120
|
+
await base.initialize();
|
|
121
|
+
await base.append([{
|
|
122
|
+
id,
|
|
123
|
+
message: { role: "user", content },
|
|
124
|
+
isSystem: true,
|
|
125
|
+
}]);
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
async appendAssistantMessage(
|
|
129
|
+
id: string,
|
|
130
|
+
content: Anthropic.Messages.ContentBlock[],
|
|
131
|
+
): Promise<void> {
|
|
132
|
+
await base.append([{
|
|
133
|
+
id,
|
|
134
|
+
message: {
|
|
135
|
+
role: "assistant",
|
|
136
|
+
content: content as unknown as Anthropic.Messages.ContentBlockParam[],
|
|
137
|
+
},
|
|
138
|
+
}]);
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
async appendToolResult(
|
|
142
|
+
id: string,
|
|
143
|
+
toolCallId: string,
|
|
144
|
+
_toolName: string,
|
|
145
|
+
content: JsonValue,
|
|
146
|
+
): Promise<void> {
|
|
147
|
+
const toolContent =
|
|
148
|
+
typeof content === "string"
|
|
149
|
+
? content
|
|
150
|
+
: Array.isArray(content)
|
|
151
|
+
? (content as unknown as Anthropic.Messages.ToolResultBlockParam["content"])
|
|
152
|
+
: JSON.stringify(content);
|
|
153
|
+
await base.append([{
|
|
154
|
+
id,
|
|
155
|
+
message: {
|
|
156
|
+
role: "user",
|
|
157
|
+
content: [{
|
|
158
|
+
type: "tool_result" as const,
|
|
159
|
+
tool_use_id: toolCallId,
|
|
160
|
+
content: toolContent,
|
|
161
|
+
}],
|
|
162
|
+
},
|
|
163
|
+
}]);
|
|
164
|
+
},
|
|
165
|
+
|
|
166
|
+
async prepareForInvocation(): Promise<AnthropicInvocationPayload> {
|
|
167
|
+
const stored = await base.load();
|
|
168
|
+
|
|
169
|
+
let system: string | undefined;
|
|
170
|
+
const conversationMessages: Anthropic.Messages.MessageParam[] = [];
|
|
171
|
+
|
|
172
|
+
for (const item of stored) {
|
|
173
|
+
if (item.isSystem) {
|
|
174
|
+
system =
|
|
175
|
+
typeof item.message.content === "string"
|
|
176
|
+
? item.message.content
|
|
177
|
+
: undefined;
|
|
178
|
+
} else {
|
|
179
|
+
conversationMessages.push(item.message);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
messages: mergeConsecutiveMessages(conversationMessages),
|
|
185
|
+
...(system ? { system } : {}),
|
|
186
|
+
};
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
return Object.assign(base, helpers);
|
|
191
|
+
}
|
|
@@ -1,33 +1,67 @@
|
|
|
1
1
|
import type Redis from "ioredis";
|
|
2
|
-
import type { GoogleGenAI, Content } from "@google/genai";
|
|
2
|
+
import type { GoogleGenAI, Content, Part } from "@google/genai";
|
|
3
3
|
import type { ToolResultConfig } from "../../../lib/types";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
ActivityToolHandler,
|
|
6
|
+
RouterContext,
|
|
7
|
+
ToolHandlerResponse,
|
|
8
|
+
} from "../../../lib/tool-router/types";
|
|
5
9
|
import type {
|
|
6
10
|
ThreadOps,
|
|
7
11
|
PrefixedThreadOps,
|
|
8
12
|
ScopedPrefix,
|
|
9
13
|
} from "../../../lib/session/types";
|
|
10
14
|
import type { ModelInvoker } from "../../../lib/model";
|
|
11
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
createGoogleGenAIThreadManager,
|
|
17
|
+
type GoogleGenAIContent,
|
|
18
|
+
} from "./thread-manager";
|
|
12
19
|
import { createGoogleGenAIModelInvoker } from "./model-invoker";
|
|
13
20
|
|
|
14
21
|
const ADAPTER_PREFIX = "googleGenAI" as const;
|
|
15
22
|
|
|
16
23
|
export type GoogleGenAIThreadOps<TScope extends string = ""> =
|
|
17
|
-
PrefixedThreadOps<
|
|
24
|
+
PrefixedThreadOps<
|
|
25
|
+
ScopedPrefix<TScope, typeof ADAPTER_PREFIX>,
|
|
26
|
+
GoogleGenAIContent
|
|
27
|
+
>;
|
|
18
28
|
|
|
19
29
|
export interface GoogleGenAIAdapterConfig {
|
|
20
30
|
redis: Redis;
|
|
21
|
-
client
|
|
31
|
+
client?: GoogleGenAI;
|
|
22
32
|
/** Default model name (e.g. 'gemini-2.5-flash'). If omitted, use `createModelInvoker()` */
|
|
23
33
|
model?: string;
|
|
24
34
|
}
|
|
25
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Tool response type accepted by the Google GenAI adapter.
|
|
38
|
+
*
|
|
39
|
+
* Handlers can return:
|
|
40
|
+
* - **`string`** — plain text, wrapped in a `functionResponse` part.
|
|
41
|
+
* - **`Record<string, unknown>`** — structured object used as `functionResponse.response`.
|
|
42
|
+
* - **`Part[]`** — pre-built parts used directly as `Content.parts`.
|
|
43
|
+
* The handler is responsible for building correct Part objects (e.g. `functionResponse`,
|
|
44
|
+
* `inlineData`, `text`). Use `context.toolCallId` and `context.toolName` to construct
|
|
45
|
+
* `functionResponse` parts.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```typescript
|
|
49
|
+
* adapter.wrapHandler(async (args, ctx) => ({
|
|
50
|
+
* toolResponse: [
|
|
51
|
+
* { functionResponse: { id: ctx.toolCallId, name: ctx.toolName, response: { result: "done" } } },
|
|
52
|
+
* { inlineData: { data: base64, mimeType: "image/png" } },
|
|
53
|
+
* ],
|
|
54
|
+
* data: null,
|
|
55
|
+
* }));
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export type GoogleGenAIToolResponse = string | Record<string, unknown> | Part[];
|
|
59
|
+
|
|
26
60
|
export interface GoogleGenAIAdapter {
|
|
27
61
|
/** Model invoker using the default model (only available when `model` was provided) */
|
|
28
62
|
invoker: ModelInvoker<Content>;
|
|
29
63
|
/** Create an invoker for a specific model name (for multi-model setups) */
|
|
30
|
-
createModelInvoker(model: string): ModelInvoker<Content>;
|
|
64
|
+
createModelInvoker(model: string, client: GoogleGenAI): ModelInvoker<Content>;
|
|
31
65
|
/**
|
|
32
66
|
* Create prefixed thread activities for registration on the worker.
|
|
33
67
|
*
|
|
@@ -43,9 +77,18 @@ export interface GoogleGenAIAdapter {
|
|
|
43
77
|
* // → { googleGenAIResearchAgentInitializeThread, … }
|
|
44
78
|
* ```
|
|
45
79
|
*/
|
|
46
|
-
createActivities<S extends string = "">(
|
|
47
|
-
|
|
48
|
-
|
|
80
|
+
createActivities<S extends string = "">(scope?: S): GoogleGenAIThreadOps<S>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Identity wrapper that types a tool handler for this adapter.
|
|
84
|
+
* Constrains `toolResponse` to {@link GoogleGenAIToolResponse}.
|
|
85
|
+
*/
|
|
86
|
+
wrapHandler<TArgs, TResult, TContext extends RouterContext = RouterContext>(
|
|
87
|
+
handler: (
|
|
88
|
+
args: TArgs,
|
|
89
|
+
context: TContext
|
|
90
|
+
) => Promise<ToolHandlerResponse<TResult, GoogleGenAIToolResponse>>
|
|
91
|
+
): ActivityToolHandler<TArgs, TResult, TContext, GoogleGenAIToolResponse>;
|
|
49
92
|
}
|
|
50
93
|
|
|
51
94
|
/**
|
|
@@ -91,45 +134,73 @@ export interface GoogleGenAIAdapter {
|
|
|
91
134
|
export function createGoogleGenAIAdapter(
|
|
92
135
|
config: GoogleGenAIAdapterConfig
|
|
93
136
|
): GoogleGenAIAdapter {
|
|
94
|
-
const { redis
|
|
137
|
+
const { redis } = config;
|
|
95
138
|
|
|
96
|
-
const threadOps: ThreadOps = {
|
|
97
|
-
async initializeThread(
|
|
98
|
-
|
|
139
|
+
const threadOps: ThreadOps<GoogleGenAIContent> = {
|
|
140
|
+
async initializeThread(
|
|
141
|
+
threadId: string,
|
|
142
|
+
threadKey?: string
|
|
143
|
+
): Promise<void> {
|
|
144
|
+
const thread = createGoogleGenAIThreadManager({
|
|
145
|
+
redis,
|
|
146
|
+
threadId,
|
|
147
|
+
key: threadKey,
|
|
148
|
+
});
|
|
99
149
|
await thread.initialize();
|
|
100
150
|
},
|
|
101
151
|
|
|
102
152
|
async appendHumanMessage(
|
|
103
153
|
threadId: string,
|
|
104
154
|
id: string,
|
|
105
|
-
content:
|
|
155
|
+
content: GoogleGenAIContent,
|
|
156
|
+
threadKey?: string
|
|
106
157
|
): Promise<void> {
|
|
107
|
-
const thread = createGoogleGenAIThreadManager({
|
|
158
|
+
const thread = createGoogleGenAIThreadManager({
|
|
159
|
+
redis,
|
|
160
|
+
threadId,
|
|
161
|
+
key: threadKey,
|
|
162
|
+
});
|
|
108
163
|
await thread.appendUserMessage(id, content);
|
|
109
164
|
},
|
|
110
165
|
|
|
111
166
|
async appendSystemMessage(
|
|
112
167
|
threadId: string,
|
|
113
168
|
id: string,
|
|
114
|
-
content: string
|
|
169
|
+
content: string,
|
|
170
|
+
threadKey?: string
|
|
115
171
|
): Promise<void> {
|
|
116
|
-
const thread = createGoogleGenAIThreadManager({
|
|
172
|
+
const thread = createGoogleGenAIThreadManager({
|
|
173
|
+
redis,
|
|
174
|
+
threadId,
|
|
175
|
+
key: threadKey,
|
|
176
|
+
});
|
|
117
177
|
await thread.appendSystemMessage(id, content);
|
|
118
178
|
},
|
|
119
179
|
|
|
120
180
|
async appendToolResult(id: string, cfg: ToolResultConfig): Promise<void> {
|
|
121
|
-
const { threadId, toolCallId, toolName, content } = cfg;
|
|
122
|
-
const thread = createGoogleGenAIThreadManager({
|
|
123
|
-
|
|
181
|
+
const { threadId, threadKey, toolCallId, toolName, content } = cfg;
|
|
182
|
+
const thread = createGoogleGenAIThreadManager({
|
|
183
|
+
redis,
|
|
184
|
+
threadId,
|
|
185
|
+
key: threadKey,
|
|
186
|
+
});
|
|
187
|
+
await thread.appendToolResult(
|
|
188
|
+
id,
|
|
189
|
+
toolCallId,
|
|
190
|
+
toolName,
|
|
191
|
+
content as GoogleGenAIToolResponse
|
|
192
|
+
);
|
|
124
193
|
},
|
|
125
194
|
|
|
126
195
|
async forkThread(
|
|
127
196
|
sourceThreadId: string,
|
|
128
|
-
targetThreadId: string
|
|
197
|
+
targetThreadId: string,
|
|
198
|
+
threadKey?: string
|
|
129
199
|
): Promise<void> {
|
|
130
200
|
const thread = createGoogleGenAIThreadManager({
|
|
131
201
|
redis,
|
|
132
202
|
threadId: sourceThreadId,
|
|
203
|
+
key: threadKey,
|
|
133
204
|
});
|
|
134
205
|
await thread.fork(targetThreadId);
|
|
135
206
|
},
|
|
@@ -141,28 +212,32 @@ export function createGoogleGenAIAdapter(
|
|
|
141
212
|
const prefix = scope
|
|
142
213
|
? `${ADAPTER_PREFIX}${scope.charAt(0).toUpperCase()}${scope.slice(1)}`
|
|
143
214
|
: ADAPTER_PREFIX;
|
|
144
|
-
const cap = (s: string): string =>
|
|
145
|
-
s.charAt(0).toUpperCase() + s.slice(1);
|
|
215
|
+
const cap = (s: string): string => s.charAt(0).toUpperCase() + s.slice(1);
|
|
146
216
|
return Object.fromEntries(
|
|
147
217
|
Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v])
|
|
148
218
|
) as GoogleGenAIThreadOps<S>;
|
|
149
219
|
}
|
|
150
220
|
|
|
151
|
-
const makeInvoker = (
|
|
221
|
+
const makeInvoker = (
|
|
222
|
+
model: string,
|
|
223
|
+
client: GoogleGenAI
|
|
224
|
+
): ModelInvoker<Content> =>
|
|
152
225
|
createGoogleGenAIModelInvoker({ redis, client, model });
|
|
153
226
|
|
|
154
|
-
const invoker: ModelInvoker<Content> =
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
"
|
|
160
|
-
|
|
161
|
-
|
|
227
|
+
const invoker: ModelInvoker<Content> =
|
|
228
|
+
config.model && config.client
|
|
229
|
+
? makeInvoker(config.model, config.client)
|
|
230
|
+
: ((() => {
|
|
231
|
+
throw new Error(
|
|
232
|
+
"No default model provided to createGoogleGenAIAdapter. " +
|
|
233
|
+
"Either pass `model` in the config or use `createModelInvoker(model)` instead."
|
|
234
|
+
);
|
|
235
|
+
}) as unknown as ModelInvoker<Content>);
|
|
162
236
|
|
|
163
237
|
return {
|
|
164
238
|
createActivities,
|
|
165
239
|
invoker,
|
|
166
240
|
createModelInvoker: makeInvoker,
|
|
241
|
+
wrapHandler: (handler) => handler,
|
|
167
242
|
};
|
|
168
243
|
}
|
|
@@ -23,14 +23,16 @@ export {
|
|
|
23
23
|
type GoogleGenAIAdapter,
|
|
24
24
|
type GoogleGenAIAdapterConfig,
|
|
25
25
|
type GoogleGenAIThreadOps,
|
|
26
|
+
type GoogleGenAIToolResponse,
|
|
26
27
|
} from "./activities";
|
|
27
28
|
|
|
28
29
|
// Thread manager
|
|
29
30
|
export {
|
|
30
31
|
createGoogleGenAIThreadManager,
|
|
31
|
-
messageContentToParts,
|
|
32
32
|
type GoogleGenAIThreadManager,
|
|
33
33
|
type GoogleGenAIThreadManagerConfig,
|
|
34
|
+
type GoogleGenAIContent,
|
|
35
|
+
type GoogleGenAIInvocationPayload,
|
|
34
36
|
type StoredContent,
|
|
35
37
|
} from "./thread-manager";
|
|
36
38
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import type Redis from "ioredis";
|
|
2
2
|
import type { GoogleGenAI, Content, FunctionDeclaration } from "@google/genai";
|
|
3
3
|
import type { SerializableToolDefinition } from "../../../lib/types";
|
|
4
|
-
import type { AgentResponse } from "../../../lib/model";
|
|
5
|
-
import type { ModelInvokerConfig } from "../../../lib/model";
|
|
4
|
+
import type { AgentResponse, ModelInvokerConfig } from "../../../lib/model";
|
|
6
5
|
import { createGoogleGenAIThreadManager } from "./thread-manager";
|
|
7
6
|
import { v4 as uuidv4 } from "uuid";
|
|
8
7
|
|
|
@@ -13,7 +12,7 @@ export interface GoogleGenAIModelInvokerConfig {
|
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
function toFunctionDeclarations(
|
|
16
|
-
tools: SerializableToolDefinition[]
|
|
15
|
+
tools: SerializableToolDefinition[],
|
|
17
16
|
): FunctionDeclaration[] {
|
|
18
17
|
return tools.map((t) => ({
|
|
19
18
|
name: t.name,
|
|
@@ -22,24 +21,6 @@ function toFunctionDeclarations(
|
|
|
22
21
|
}));
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
/**
|
|
26
|
-
* Merge consecutive Content objects sharing the same role.
|
|
27
|
-
* The Gemini API requires alternating user/model turns; without
|
|
28
|
-
* merging, multiple sequential tool-result messages would violate this.
|
|
29
|
-
*/
|
|
30
|
-
function mergeConsecutiveContents(contents: Content[]): Content[] {
|
|
31
|
-
const merged: Content[] = [];
|
|
32
|
-
for (const content of contents) {
|
|
33
|
-
const last = merged[merged.length - 1];
|
|
34
|
-
if (last && last.role === content.role) {
|
|
35
|
-
last.parts = [...(last.parts ?? []), ...(content.parts ?? [])];
|
|
36
|
-
} else {
|
|
37
|
-
merged.push({ ...content, parts: [...(content.parts ?? [])] });
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return merged;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
24
|
/**
|
|
44
25
|
* Creates a Google GenAI model invoker that satisfies the generic
|
|
45
26
|
* `ModelInvoker<Content>` contract.
|
|
@@ -70,27 +51,13 @@ export function createGoogleGenAIModelInvoker({
|
|
|
70
51
|
model,
|
|
71
52
|
}: GoogleGenAIModelInvokerConfig) {
|
|
72
53
|
return async function invokeGoogleGenAIModel(
|
|
73
|
-
config: ModelInvokerConfig
|
|
54
|
+
config: ModelInvokerConfig,
|
|
74
55
|
): Promise<AgentResponse<Content>> {
|
|
75
|
-
const { threadId, state } = config;
|
|
76
|
-
|
|
77
|
-
const thread = createGoogleGenAIThreadManager({ redis, threadId });
|
|
78
|
-
const stored = await thread.load();
|
|
79
|
-
|
|
80
|
-
// Separate system instructions from conversation content.
|
|
81
|
-
// Google GenAI takes system instructions via config, not in the contents array.
|
|
82
|
-
let systemInstruction: string | undefined;
|
|
83
|
-
const conversationContents: Content[] = [];
|
|
84
|
-
|
|
85
|
-
for (const item of stored) {
|
|
86
|
-
if (item.content.role === "system") {
|
|
87
|
-
systemInstruction = item.content.parts?.[0]?.text;
|
|
88
|
-
} else {
|
|
89
|
-
conversationContents.push(item.content);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
56
|
+
const { threadId, threadKey, state } = config;
|
|
92
57
|
|
|
93
|
-
const
|
|
58
|
+
const thread = createGoogleGenAIThreadManager({ redis, threadId, key: threadKey });
|
|
59
|
+
const { contents, systemInstruction } =
|
|
60
|
+
await thread.prepareForInvocation();
|
|
94
61
|
|
|
95
62
|
const functionDeclarations = toFunctionDeclarations(state.tools);
|
|
96
63
|
const tools =
|
|
@@ -18,44 +18,16 @@
|
|
|
18
18
|
* const threadOps = proxyGoogleGenAIThreadOps("customScope");
|
|
19
19
|
* ```
|
|
20
20
|
*/
|
|
21
|
-
import {
|
|
22
|
-
proxyActivities,
|
|
23
|
-
workflowInfo,
|
|
24
|
-
type ActivityInterfaceFor,
|
|
25
|
-
} from "@temporalio/workflow";
|
|
21
|
+
import { type ActivityInterfaceFor } from "@temporalio/workflow";
|
|
26
22
|
import type { ThreadOps } from "../../../lib/session/types";
|
|
23
|
+
import type { GoogleGenAIContent } from "./thread-manager";
|
|
24
|
+
import { createThreadOpsProxy } from "../../../lib/thread/proxy";
|
|
27
25
|
|
|
28
26
|
const ADAPTER_PREFIX = "googleGenAI";
|
|
29
27
|
|
|
30
28
|
export function proxyGoogleGenAIThreadOps(
|
|
31
29
|
scope?: string,
|
|
32
|
-
options?: Parameters<typeof
|
|
33
|
-
): ActivityInterfaceFor<ThreadOps
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
-
const acts = proxyActivities<Record<string, (...args: any[]) => any>>(
|
|
38
|
-
options ?? {
|
|
39
|
-
startToCloseTimeout: "10s",
|
|
40
|
-
retry: {
|
|
41
|
-
maximumAttempts: 6,
|
|
42
|
-
initialInterval: "5s",
|
|
43
|
-
maximumInterval: "15m",
|
|
44
|
-
backoffCoefficient: 4,
|
|
45
|
-
},
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
|
-
|
|
49
|
-
const prefix =
|
|
50
|
-
`${ADAPTER_PREFIX}${resolvedScope.charAt(0).toUpperCase()}${resolvedScope.slice(1)}`;
|
|
51
|
-
const p = (key: string): string =>
|
|
52
|
-
`${prefix}${key.charAt(0).toUpperCase()}${key.slice(1)}`;
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
initializeThread: acts[p("initializeThread")],
|
|
56
|
-
appendHumanMessage: acts[p("appendHumanMessage")],
|
|
57
|
-
appendToolResult: acts[p("appendToolResult")],
|
|
58
|
-
appendSystemMessage: acts[p("appendSystemMessage")],
|
|
59
|
-
forkThread: acts[p("forkThread")],
|
|
60
|
-
} as ActivityInterfaceFor<ThreadOps>;
|
|
30
|
+
options?: Parameters<typeof createThreadOpsProxy>[2],
|
|
31
|
+
): ActivityInterfaceFor<ThreadOps<GoogleGenAIContent>> {
|
|
32
|
+
return createThreadOpsProxy(ADAPTER_PREFIX, scope, options) as ActivityInterfaceFor<ThreadOps<GoogleGenAIContent>>;
|
|
61
33
|
}
|