zeitlich 0.2.38 → 0.2.40
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 +18 -0
- package/dist/{activities-BKhMtKDd.d.ts → activities-CULxRzJ1.d.ts} +4 -6
- package/dist/{activities-CDcwkRZs.d.cts → activities-CvUrG3YG.d.cts} +4 -6
- package/dist/adapter-id-BB-mmrts.d.cts +17 -0
- package/dist/adapter-id-BB-mmrts.d.ts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.cts +17 -0
- package/dist/adapter-id-CMwVrVqv.d.ts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.cts +17 -0
- package/dist/adapter-id-CbY2zeSt.d.ts +17 -0
- package/dist/adapters/thread/anthropic/index.cjs +140 -23
- package/dist/adapters/thread/anthropic/index.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/index.d.cts +8 -7
- package/dist/adapters/thread/anthropic/index.d.ts +8 -7
- package/dist/adapters/thread/anthropic/index.js +140 -24
- package/dist/adapters/thread/anthropic/index.js.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.cjs +8 -3
- package/dist/adapters/thread/anthropic/workflow.cjs.map +1 -1
- package/dist/adapters/thread/anthropic/workflow.d.cts +5 -4
- package/dist/adapters/thread/anthropic/workflow.d.ts +5 -4
- package/dist/adapters/thread/anthropic/workflow.js +8 -4
- package/dist/adapters/thread/anthropic/workflow.js.map +1 -1
- package/dist/adapters/thread/google-genai/index.cjs +140 -23
- package/dist/adapters/thread/google-genai/index.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/index.d.cts +5 -4
- package/dist/adapters/thread/google-genai/index.d.ts +5 -4
- package/dist/adapters/thread/google-genai/index.js +140 -24
- package/dist/adapters/thread/google-genai/index.js.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.cjs +8 -3
- package/dist/adapters/thread/google-genai/workflow.cjs.map +1 -1
- package/dist/adapters/thread/google-genai/workflow.d.cts +5 -4
- package/dist/adapters/thread/google-genai/workflow.d.ts +5 -4
- package/dist/adapters/thread/google-genai/workflow.js +8 -4
- package/dist/adapters/thread/google-genai/workflow.js.map +1 -1
- package/dist/adapters/thread/index.cjs +16 -0
- package/dist/adapters/thread/index.cjs.map +1 -0
- package/dist/adapters/thread/index.d.cts +34 -0
- package/dist/adapters/thread/index.d.ts +34 -0
- package/dist/adapters/thread/index.js +12 -0
- package/dist/adapters/thread/index.js.map +1 -0
- package/dist/adapters/thread/langchain/index.cjs +139 -24
- package/dist/adapters/thread/langchain/index.cjs.map +1 -1
- package/dist/adapters/thread/langchain/index.d.cts +8 -7
- package/dist/adapters/thread/langchain/index.d.ts +8 -7
- package/dist/adapters/thread/langchain/index.js +139 -25
- package/dist/adapters/thread/langchain/index.js.map +1 -1
- package/dist/adapters/thread/langchain/workflow.cjs +8 -3
- package/dist/adapters/thread/langchain/workflow.cjs.map +1 -1
- package/dist/adapters/thread/langchain/workflow.d.cts +5 -4
- package/dist/adapters/thread/langchain/workflow.d.ts +5 -4
- package/dist/adapters/thread/langchain/workflow.js +8 -4
- package/dist/adapters/thread/langchain/workflow.js.map +1 -1
- package/dist/index.cjs +267 -48
- 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 +264 -49
- package/dist/index.js.map +1 -1
- package/dist/{proxy-D_3x7RN4.d.cts → proxy-5EbwzaY4.d.cts} +1 -1
- package/dist/{proxy-CUlKSvZS.d.ts → proxy-wZufFfBh.d.ts} +1 -1
- package/dist/{thread-manager-CVu7o2cs.d.ts → thread-manager-BNiIt5r8.d.ts} +2 -4
- package/dist/{thread-manager-c1gPopAG.d.ts → thread-manager-BoN5DOvG.d.cts} +2 -4
- package/dist/{thread-manager-wGi-LqIP.d.cts → thread-manager-BqBAIsED.d.ts} +2 -4
- package/dist/{thread-manager-HSwyh28L.d.cts → thread-manager-DF8WuCRs.d.cts} +2 -4
- package/dist/{types-BH_IRryz.d.ts → types-C7OoY7h8.d.ts} +54 -6
- package/dist/{types-C06FwR96.d.cts → types-Cn2r3ol3.d.cts} +163 -44
- package/dist/{types-BaOw4hKI.d.cts → types-CuISs0Ub.d.cts} +54 -6
- package/dist/{types-DNr31FzL.d.ts → types-DeQH84C_.d.ts} +163 -44
- package/dist/{workflow-CSCkpwAL.d.ts → workflow-C2MZZj5K.d.ts} +82 -2
- package/dist/{workflow-DuvMZ8Vm.d.cts → workflow-DhplIN65.d.cts} +82 -2
- package/dist/workflow.cjs +189 -37
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +2 -2
- package/dist/workflow.d.ts +2 -2
- package/dist/workflow.js +186 -38
- package/dist/workflow.js.map +1 -1
- package/package.json +11 -1
- package/src/adapters/thread/adapter-id.test.ts +42 -0
- package/src/adapters/thread/anthropic/activities.ts +33 -7
- package/src/adapters/thread/anthropic/adapter-id.ts +16 -0
- package/src/adapters/thread/anthropic/fork-transform.test.ts +291 -0
- package/src/adapters/thread/anthropic/index.ts +3 -0
- package/src/adapters/thread/anthropic/model-invoker.ts +8 -4
- package/src/adapters/thread/anthropic/proxy.ts +3 -2
- package/src/adapters/thread/anthropic/thread-manager.ts +27 -4
- package/src/adapters/thread/google-genai/activities.ts +33 -7
- package/src/adapters/thread/google-genai/adapter-id.ts +16 -0
- package/src/adapters/thread/google-genai/fork-transform.test.ts +149 -0
- package/src/adapters/thread/google-genai/index.ts +3 -0
- package/src/adapters/thread/google-genai/model-invoker.ts +7 -3
- package/src/adapters/thread/google-genai/proxy.ts +3 -2
- package/src/adapters/thread/google-genai/thread-manager.ts +27 -4
- package/src/adapters/thread/index.ts +39 -0
- package/src/adapters/thread/langchain/activities.ts +33 -7
- package/src/adapters/thread/langchain/adapter-id.ts +16 -0
- package/src/adapters/thread/langchain/fork-transform.test.ts +142 -0
- package/src/adapters/thread/langchain/index.ts +3 -0
- package/src/adapters/thread/langchain/model-invoker.ts +8 -3
- package/src/adapters/thread/langchain/proxy.ts +3 -2
- package/src/adapters/thread/langchain/thread-manager.ts +27 -4
- package/src/lib/lifecycle.ts +3 -1
- package/src/lib/model/types.ts +7 -10
- package/src/lib/session/session-edge-cases.integration.test.ts +131 -63
- package/src/lib/session/session.integration.test.ts +174 -5
- package/src/lib/session/session.ts +69 -28
- package/src/lib/session/types.ts +61 -9
- package/src/lib/state/index.ts +1 -0
- package/src/lib/state/manager.integration.test.ts +109 -0
- package/src/lib/state/manager.ts +38 -8
- package/src/lib/state/types.ts +25 -0
- package/src/lib/subagent/handler.ts +124 -11
- package/src/lib/subagent/index.ts +5 -1
- package/src/lib/subagent/subagent.integration.test.ts +528 -0
- package/src/lib/subagent/types.ts +63 -14
- package/src/lib/subagent/workflow.ts +29 -2
- package/src/lib/thread/index.ts +5 -0
- package/src/lib/thread/keys.test.ts +101 -0
- package/src/lib/thread/keys.ts +94 -0
- package/src/lib/thread/manager.test.ts +139 -0
- package/src/lib/thread/manager.ts +92 -14
- package/src/lib/thread/proxy.ts +2 -0
- package/src/lib/thread/types.ts +60 -6
- package/src/lib/tool-router/types.ts +16 -8
- package/src/lib/types.ts +12 -0
- package/src/workflow.ts +12 -1
- package/tsup.config.ts +1 -0
package/README.md
CHANGED
|
@@ -482,6 +482,24 @@ const session = await createSession({
|
|
|
482
482
|
|
|
483
483
|
The `Subagent` tool is automatically added when subagents are configured, allowing the LLM to spawn child workflows.
|
|
484
484
|
|
|
485
|
+
#### Child workflow timeouts
|
|
486
|
+
|
|
487
|
+
Every subagent child workflow runs with a default `workflowRunTimeout` of `1h` (exported as `DEFAULT_SUBAGENT_WORKFLOW_RUN_TIMEOUT`). This is a safety bound: without it, a child that fails to initialize or repeatedly fails workflow tasks is retried forever by Temporal and the parent's `Subagent` tool call would hang indefinitely. With it, Temporal eventually terminates the child and the parent receives a structured `ChildWorkflowFailure` which the tool router surfaces to the LLM through the normal failure-hook pipeline (`onPostToolUseFailure`, per-subagent `onExecutionFailure`).
|
|
488
|
+
|
|
489
|
+
You can override the default — or set any other `ChildWorkflowOptions` — via the `workflowOptions` field:
|
|
490
|
+
|
|
491
|
+
```typescript
|
|
492
|
+
export const researcherSubagent = defineSubagent(researcherWorkflow, {
|
|
493
|
+
workflowOptions: {
|
|
494
|
+
workflowRunTimeout: "10m",
|
|
495
|
+
workflowTaskTimeout: "1m",
|
|
496
|
+
retry: { maximumAttempts: 2 },
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
`workflowId`, `taskQueue`, and `args` are managed by the subagent handler itself and cannot be overridden via `workflowOptions` — use the top-level `taskQueue` field on `SubagentConfig` to route a subagent to a different task queue.
|
|
502
|
+
|
|
485
503
|
### Skills
|
|
486
504
|
|
|
487
505
|
Zeitlich has first-class support for the [agentskills.io](https://agentskills.io) specification. Skills are reusable instruction sets that an agent can load on-demand via the built-in `ReadSkill` tool — progressive disclosure keeps token usage low while giving agents access to rich, domain-specific guidance.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
2
|
import { Part, Content, GoogleGenAI } from '@google/genai';
|
|
3
|
-
import { a as ModelInvoker,
|
|
4
|
-
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-
|
|
3
|
+
import { a as ModelInvoker, b as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, c as ToolHandlerResponse, d as ActivityToolHandler } from './types-DeQH84C_.js';
|
|
4
|
+
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-C7OoY7h8.js';
|
|
5
|
+
import { A as ADAPTER_ID } from './adapter-id-BB-mmrts.js';
|
|
5
6
|
|
|
6
7
|
/** SDK-native content type for Google GenAI human messages */
|
|
7
8
|
type GoogleGenAIContent = string | Part[];
|
|
@@ -24,8 +25,6 @@ interface GoogleGenAIThreadManagerConfig {
|
|
|
24
25
|
interface GoogleGenAIInvocationPayload {
|
|
25
26
|
contents: Content[];
|
|
26
27
|
systemInstruction?: Part[];
|
|
27
|
-
/** Number of stored messages loaded from Redis before preparation. */
|
|
28
|
-
storedLength: number;
|
|
29
28
|
}
|
|
30
29
|
/** Thread manager with Google GenAI Content convenience helpers */
|
|
31
30
|
interface GoogleGenAIThreadManager extends ProviderThreadManager<StoredContent, GoogleGenAIContent, GoogleGenAIToolResponse, GoogleGenAISystemContent> {
|
|
@@ -39,8 +38,7 @@ interface GoogleGenAIThreadManager extends ProviderThreadManager<StoredContent,
|
|
|
39
38
|
*/
|
|
40
39
|
declare function createGoogleGenAIThreadManager(config: GoogleGenAIThreadManagerConfig): GoogleGenAIThreadManager;
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
type GoogleGenAIThreadOps<TScope extends string = ""> = PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_PREFIX>, GoogleGenAIContent>;
|
|
41
|
+
type GoogleGenAIThreadOps<TScope extends string = ""> = PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_ID>, GoogleGenAIContent>;
|
|
44
42
|
interface GoogleGenAIAdapterConfig {
|
|
45
43
|
redis: Redis;
|
|
46
44
|
client?: GoogleGenAI;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
2
|
import { Part, Content, GoogleGenAI } from '@google/genai';
|
|
3
|
-
import { a as ModelInvoker,
|
|
4
|
-
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-
|
|
3
|
+
import { a as ModelInvoker, b as PrefixedThreadOps, S as ScopedPrefix, R as RouterContext, c as ToolHandlerResponse, d as ActivityToolHandler } from './types-Cn2r3ol3.cjs';
|
|
4
|
+
import { T as ThreadManagerHooks, P as ProviderThreadManager } from './types-CuISs0Ub.cjs';
|
|
5
|
+
import { A as ADAPTER_ID } from './adapter-id-BB-mmrts.cjs';
|
|
5
6
|
|
|
6
7
|
/** SDK-native content type for Google GenAI human messages */
|
|
7
8
|
type GoogleGenAIContent = string | Part[];
|
|
@@ -24,8 +25,6 @@ interface GoogleGenAIThreadManagerConfig {
|
|
|
24
25
|
interface GoogleGenAIInvocationPayload {
|
|
25
26
|
contents: Content[];
|
|
26
27
|
systemInstruction?: Part[];
|
|
27
|
-
/** Number of stored messages loaded from Redis before preparation. */
|
|
28
|
-
storedLength: number;
|
|
29
28
|
}
|
|
30
29
|
/** Thread manager with Google GenAI Content convenience helpers */
|
|
31
30
|
interface GoogleGenAIThreadManager extends ProviderThreadManager<StoredContent, GoogleGenAIContent, GoogleGenAIToolResponse, GoogleGenAISystemContent> {
|
|
@@ -39,8 +38,7 @@ interface GoogleGenAIThreadManager extends ProviderThreadManager<StoredContent,
|
|
|
39
38
|
*/
|
|
40
39
|
declare function createGoogleGenAIThreadManager(config: GoogleGenAIThreadManagerConfig): GoogleGenAIThreadManager;
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
type GoogleGenAIThreadOps<TScope extends string = ""> = PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_PREFIX>, GoogleGenAIContent>;
|
|
41
|
+
type GoogleGenAIThreadOps<TScope extends string = ""> = PrefixedThreadOps<ScopedPrefix<TScope, typeof ADAPTER_ID>, GoogleGenAIContent>;
|
|
44
42
|
interface GoogleGenAIAdapterConfig {
|
|
45
43
|
redis: Redis;
|
|
46
44
|
client?: GoogleGenAI;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the Google GenAI thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `googleGenAICodingAgentInitializeThread`) and
|
|
6
|
+
* must never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/google-genai` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"googleGenAI"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "googleGenAI";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the Google GenAI thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `googleGenAICodingAgentInitializeThread`) and
|
|
6
|
+
* must never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/google-genai` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"googleGenAI"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "googleGenAI";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the Anthropic thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `anthropicCodingAgentInitializeThread`) and must
|
|
6
|
+
* never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/anthropic` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"anthropic"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "anthropic";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the Anthropic thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `anthropicCodingAgentInitializeThread`) and must
|
|
6
|
+
* never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/anthropic` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"anthropic"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "anthropic";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the LangChain thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `langChainCodingAgentInitializeThread`) and must
|
|
6
|
+
* never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/langchain` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"langChain"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "langChain";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public adapter identity for the LangChain thread adapter.
|
|
3
|
+
*
|
|
4
|
+
* This value is wire format — it appears as the prefix for Temporal
|
|
5
|
+
* activity names (e.g. `langChainCodingAgentInitializeThread`) and must
|
|
6
|
+
* never change, since renaming it would orphan existing persisted
|
|
7
|
+
* threads and break in-flight workflows.
|
|
8
|
+
*
|
|
9
|
+
* Re-exported from `zeitlich/adapters/thread/langchain` so downstream
|
|
10
|
+
* consumers can use the exact same literal the adapter uses internally,
|
|
11
|
+
* typed as the narrow string literal `"langChain"`.
|
|
12
|
+
*/
|
|
13
|
+
declare const ADAPTER_ID: "langChain";
|
|
14
|
+
/** Narrow string-literal type for {@link ADAPTER_ID}. */
|
|
15
|
+
type AdapterId = typeof ADAPTER_ID;
|
|
16
|
+
|
|
17
|
+
export { ADAPTER_ID as A, type AdapterId as a };
|
|
@@ -2,8 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
var activity = require('@temporalio/activity');
|
|
4
4
|
|
|
5
|
-
// src/
|
|
5
|
+
// src/adapters/thread/anthropic/adapter-id.ts
|
|
6
|
+
var ADAPTER_ID = "anthropic";
|
|
7
|
+
|
|
8
|
+
// src/lib/thread/keys.ts
|
|
6
9
|
var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
10
|
+
function getThreadListKey(threadKey, threadId) {
|
|
11
|
+
return `${threadKey}:thread:${threadId}`;
|
|
12
|
+
}
|
|
13
|
+
function getThreadMetaKey(threadKey, threadId) {
|
|
14
|
+
return `${threadKey}:meta:thread:${threadId}`;
|
|
15
|
+
}
|
|
16
|
+
function getThreadStateKey(threadKey, threadId) {
|
|
17
|
+
return `${threadKey}:state:thread:${threadId}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/lib/thread/manager.ts
|
|
7
21
|
var APPEND_IDEMPOTENT_SCRIPT = `
|
|
8
22
|
if redis.call('EXISTS', KEYS[1]) == 1 then
|
|
9
23
|
return 0
|
|
@@ -15,8 +29,8 @@ redis.call('EXPIRE', KEYS[2], tonumber(ARGV[1]))
|
|
|
15
29
|
redis.call('SET', KEYS[1], '1', 'EX', tonumber(ARGV[1]))
|
|
16
30
|
return 1
|
|
17
31
|
`;
|
|
18
|
-
function
|
|
19
|
-
return
|
|
32
|
+
function getDedupKey(threadId, id) {
|
|
33
|
+
return `dedup:${id}:thread:${threadId}`;
|
|
20
34
|
}
|
|
21
35
|
function createThreadManager(config) {
|
|
22
36
|
const {
|
|
@@ -27,8 +41,9 @@ function createThreadManager(config) {
|
|
|
27
41
|
deserialize = (raw) => JSON.parse(raw),
|
|
28
42
|
idOf
|
|
29
43
|
} = config;
|
|
30
|
-
const redisKey =
|
|
31
|
-
const metaKey =
|
|
44
|
+
const redisKey = getThreadListKey(key, threadId);
|
|
45
|
+
const metaKey = getThreadMetaKey(key, threadId);
|
|
46
|
+
const stateKey = getThreadStateKey(key, threadId);
|
|
32
47
|
async function assertThreadExists() {
|
|
33
48
|
const exists = await redis.exists(metaKey);
|
|
34
49
|
if (!exists) {
|
|
@@ -50,7 +65,7 @@ function createThreadManager(config) {
|
|
|
50
65
|
await assertThreadExists();
|
|
51
66
|
if (idOf) {
|
|
52
67
|
const dedupId = messages.map(idOf).join(":");
|
|
53
|
-
const dedupKey =
|
|
68
|
+
const dedupKey = getDedupKey(threadId, dedupId);
|
|
54
69
|
await redis.eval(
|
|
55
70
|
APPEND_IDEMPOTENT_SCRIPT,
|
|
56
71
|
2,
|
|
@@ -67,34 +82,98 @@ function createThreadManager(config) {
|
|
|
67
82
|
async fork(newThreadId) {
|
|
68
83
|
await assertThreadExists();
|
|
69
84
|
const data = await redis.lrange(redisKey, 0, -1);
|
|
85
|
+
const stateRaw = await redis.get(stateKey);
|
|
70
86
|
const forked = createThreadManager({
|
|
71
87
|
...config,
|
|
72
88
|
threadId: newThreadId
|
|
73
89
|
});
|
|
74
90
|
await forked.initialize();
|
|
75
91
|
if (data.length > 0) {
|
|
76
|
-
const newKey =
|
|
92
|
+
const newKey = getThreadListKey(key, newThreadId);
|
|
77
93
|
await redis.rpush(newKey, ...data);
|
|
78
94
|
await redis.expire(newKey, THREAD_TTL_SECONDS);
|
|
79
95
|
}
|
|
96
|
+
if (stateRaw != null) {
|
|
97
|
+
const newStateKey = getThreadStateKey(key, newThreadId);
|
|
98
|
+
await redis.set(newStateKey, stateRaw, "EX", THREAD_TTL_SECONDS);
|
|
99
|
+
}
|
|
80
100
|
return forked;
|
|
81
101
|
},
|
|
102
|
+
async replaceAll(messages) {
|
|
103
|
+
await assertThreadExists();
|
|
104
|
+
if (!idOf) {
|
|
105
|
+
throw new Error(
|
|
106
|
+
"replaceAll requires the thread manager to be configured with `idOf`"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
const existing = await redis.lrange(redisKey, 0, -1);
|
|
110
|
+
const existingIds = existing.map((raw) => idOf(deserialize(raw))).filter((id) => typeof id === "string");
|
|
111
|
+
await redis.del(redisKey);
|
|
112
|
+
if (existingIds.length > 0) {
|
|
113
|
+
await redis.del(
|
|
114
|
+
...existingIds.map((id) => getDedupKey(threadId, id))
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (messages.length > 0) {
|
|
118
|
+
await redis.rpush(redisKey, ...messages.map(serialize));
|
|
119
|
+
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
120
|
+
}
|
|
121
|
+
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
122
|
+
},
|
|
82
123
|
async delete() {
|
|
83
|
-
await redis.del(redisKey, metaKey);
|
|
124
|
+
await redis.del(redisKey, metaKey, stateKey);
|
|
125
|
+
},
|
|
126
|
+
async loadState() {
|
|
127
|
+
const raw = await redis.get(stateKey);
|
|
128
|
+
if (raw == null) return null;
|
|
129
|
+
return JSON.parse(raw);
|
|
130
|
+
},
|
|
131
|
+
async saveState(state) {
|
|
132
|
+
await assertThreadExists();
|
|
133
|
+
await redis.set(
|
|
134
|
+
stateKey,
|
|
135
|
+
JSON.stringify(state),
|
|
136
|
+
"EX",
|
|
137
|
+
THREAD_TTL_SECONDS
|
|
138
|
+
);
|
|
139
|
+
},
|
|
140
|
+
async deleteState() {
|
|
141
|
+
await redis.del(stateKey);
|
|
84
142
|
},
|
|
85
143
|
async length() {
|
|
86
144
|
await assertThreadExists();
|
|
87
145
|
return redis.llen(redisKey);
|
|
88
146
|
},
|
|
89
|
-
async
|
|
147
|
+
async truncateFromId(messageId) {
|
|
90
148
|
await assertThreadExists();
|
|
91
|
-
if (
|
|
149
|
+
if (!idOf) {
|
|
150
|
+
throw new Error(
|
|
151
|
+
"truncateFromId requires the thread manager to be configured with `idOf`"
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
const data = await redis.lrange(redisKey, 0, -1);
|
|
155
|
+
let idx = -1;
|
|
156
|
+
const removedIds = [];
|
|
157
|
+
for (let i = 0; i < data.length; i++) {
|
|
158
|
+
const raw = data[i];
|
|
159
|
+
if (raw === void 0) continue;
|
|
160
|
+
const id = idOf(deserialize(raw));
|
|
161
|
+
if (idx === -1 && id === messageId) idx = i;
|
|
162
|
+
if (idx !== -1) removedIds.push(id);
|
|
163
|
+
}
|
|
164
|
+
if (idx === -1) return;
|
|
165
|
+
if (idx === 0) {
|
|
92
166
|
await redis.del(redisKey);
|
|
93
167
|
await redis.expire(metaKey, THREAD_TTL_SECONDS);
|
|
94
168
|
} else {
|
|
95
|
-
await redis.ltrim(redisKey, 0,
|
|
169
|
+
await redis.ltrim(redisKey, 0, idx - 1);
|
|
96
170
|
await redis.expire(redisKey, THREAD_TTL_SECONDS);
|
|
97
171
|
}
|
|
172
|
+
if (removedIds.length > 0) {
|
|
173
|
+
await redis.del(
|
|
174
|
+
...removedIds.map((id) => getDedupKey(threadId, id))
|
|
175
|
+
);
|
|
176
|
+
}
|
|
98
177
|
}
|
|
99
178
|
};
|
|
100
179
|
}
|
|
@@ -203,12 +282,33 @@ function createAnthropicThreadManager(config) {
|
|
|
203
282
|
const messages = mergeConsecutiveMessages(conversationMessages);
|
|
204
283
|
return {
|
|
205
284
|
messages: onPreparedMessage ? messages.map((msg, i) => onPreparedMessage(msg, i, messages)) : messages,
|
|
206
|
-
...system ? { system } : {}
|
|
207
|
-
storedLength: stored.length
|
|
285
|
+
...system ? { system } : {}
|
|
208
286
|
};
|
|
209
287
|
}
|
|
210
288
|
};
|
|
211
|
-
|
|
289
|
+
const manager = Object.assign(base, helpers);
|
|
290
|
+
const originalFork = manager.fork.bind(manager);
|
|
291
|
+
manager.fork = async (newThreadId) => {
|
|
292
|
+
await originalFork(newThreadId);
|
|
293
|
+
const forked = createAnthropicThreadManager({
|
|
294
|
+
...config,
|
|
295
|
+
threadId: newThreadId
|
|
296
|
+
});
|
|
297
|
+
const { onForkPrepareThread, onForkTransform } = config.hooks ?? {};
|
|
298
|
+
if (!onForkPrepareThread && !onForkTransform) {
|
|
299
|
+
return forked;
|
|
300
|
+
}
|
|
301
|
+
let next = await forked.load();
|
|
302
|
+
if (onForkPrepareThread) {
|
|
303
|
+
next = await onForkPrepareThread(next);
|
|
304
|
+
}
|
|
305
|
+
if (onForkTransform) {
|
|
306
|
+
next = next.map((msg, i) => onForkTransform(msg, i, next));
|
|
307
|
+
}
|
|
308
|
+
await forked.replaceAll(next);
|
|
309
|
+
return forked;
|
|
310
|
+
};
|
|
311
|
+
return manager;
|
|
212
312
|
}
|
|
213
313
|
function getActivityContext() {
|
|
214
314
|
try {
|
|
@@ -235,7 +335,7 @@ function createAnthropicModelInvoker({
|
|
|
235
335
|
hooks
|
|
236
336
|
}) {
|
|
237
337
|
return async function invokeAnthropicModel2(config) {
|
|
238
|
-
const { threadId, threadKey, state } = config;
|
|
338
|
+
const { threadId, threadKey, state, assistantMessageId } = config;
|
|
239
339
|
const { heartbeat, signal } = getActivityContext();
|
|
240
340
|
const thread = createAnthropicThreadManager({
|
|
241
341
|
redis,
|
|
@@ -243,7 +343,8 @@ function createAnthropicModelInvoker({
|
|
|
243
343
|
key: threadKey,
|
|
244
344
|
hooks
|
|
245
345
|
});
|
|
246
|
-
|
|
346
|
+
await thread.truncateFromId(assistantMessageId);
|
|
347
|
+
const { messages, system } = await thread.prepareForInvocation();
|
|
247
348
|
const anthropicTools = toAnthropicTools(state.tools);
|
|
248
349
|
const tools = anthropicTools.length > 0 ? anthropicTools : void 0;
|
|
249
350
|
const params = {
|
|
@@ -273,8 +374,7 @@ function createAnthropicModelInvoker({
|
|
|
273
374
|
outputTokens: response.usage.output_tokens,
|
|
274
375
|
cachedWriteTokens: response.usage.cache_creation_input_tokens ?? void 0,
|
|
275
376
|
cachedReadTokens: response.usage.cache_read_input_tokens ?? void 0
|
|
276
|
-
}
|
|
277
|
-
threadLengthAtCall: storedLength
|
|
377
|
+
}
|
|
278
378
|
};
|
|
279
379
|
};
|
|
280
380
|
}
|
|
@@ -297,7 +397,6 @@ async function invokeAnthropicModel({
|
|
|
297
397
|
}
|
|
298
398
|
|
|
299
399
|
// src/adapters/thread/anthropic/activities.ts
|
|
300
|
-
var ADAPTER_PREFIX = "anthropic";
|
|
301
400
|
function createAnthropicAdapter(config) {
|
|
302
401
|
const { redis, client } = config;
|
|
303
402
|
const threadOps = {
|
|
@@ -346,17 +445,34 @@ function createAnthropicAdapter(config) {
|
|
|
346
445
|
const thread = createAnthropicThreadManager({
|
|
347
446
|
redis,
|
|
348
447
|
threadId: sourceThreadId,
|
|
349
|
-
key: threadKey
|
|
448
|
+
key: threadKey,
|
|
449
|
+
hooks: config.hooks
|
|
350
450
|
});
|
|
351
451
|
await thread.fork(targetThreadId);
|
|
352
452
|
},
|
|
353
|
-
async truncateThread(threadId,
|
|
453
|
+
async truncateThread(threadId, messageId, threadKey) {
|
|
354
454
|
const thread = createAnthropicThreadManager({ redis, threadId, key: threadKey });
|
|
355
|
-
await thread.
|
|
455
|
+
await thread.truncateFromId(messageId);
|
|
456
|
+
},
|
|
457
|
+
async loadThreadState(threadId, threadKey) {
|
|
458
|
+
const thread = createAnthropicThreadManager({
|
|
459
|
+
redis,
|
|
460
|
+
threadId,
|
|
461
|
+
key: threadKey
|
|
462
|
+
});
|
|
463
|
+
return thread.loadState();
|
|
464
|
+
},
|
|
465
|
+
async saveThreadState(threadId, state, threadKey) {
|
|
466
|
+
const thread = createAnthropicThreadManager({
|
|
467
|
+
redis,
|
|
468
|
+
threadId,
|
|
469
|
+
key: threadKey
|
|
470
|
+
});
|
|
471
|
+
await thread.saveState(state);
|
|
356
472
|
}
|
|
357
473
|
};
|
|
358
474
|
function createActivities(scope) {
|
|
359
|
-
const prefix = scope ? `${
|
|
475
|
+
const prefix = scope ? `${ADAPTER_ID}${scope.charAt(0).toUpperCase()}${scope.slice(1)}` : ADAPTER_ID;
|
|
360
476
|
const cap = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
361
477
|
return Object.fromEntries(
|
|
362
478
|
Object.entries(threadOps).map(([k, v]) => [`${prefix}${cap(k)}`, v])
|
|
@@ -386,6 +502,7 @@ function createAnthropicAdapter(config) {
|
|
|
386
502
|
};
|
|
387
503
|
}
|
|
388
504
|
|
|
505
|
+
exports.ADAPTER_ID = ADAPTER_ID;
|
|
389
506
|
exports.createAnthropicAdapter = createAnthropicAdapter;
|
|
390
507
|
exports.createAnthropicModelInvoker = createAnthropicModelInvoker;
|
|
391
508
|
exports.createAnthropicThreadManager = createAnthropicThreadManager;
|