zeitlich 0.2.11 → 0.2.13

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.
Files changed (46) hide show
  1. package/README.md +313 -126
  2. package/dist/adapters/langchain/index.cjs +270 -0
  3. package/dist/adapters/langchain/index.cjs.map +1 -0
  4. package/dist/adapters/langchain/index.d.cts +132 -0
  5. package/dist/adapters/langchain/index.d.ts +132 -0
  6. package/dist/adapters/langchain/index.js +265 -0
  7. package/dist/adapters/langchain/index.js.map +1 -0
  8. package/dist/index.cjs +89 -209
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.d.cts +62 -46
  11. package/dist/index.d.ts +62 -46
  12. package/dist/index.js +88 -208
  13. package/dist/index.js.map +1 -1
  14. package/dist/{workflow-BhjsEQc1.d.cts → model-invoker-y_zlyMqu.d.cts} +45 -482
  15. package/dist/{workflow-BhjsEQc1.d.ts → model-invoker-y_zlyMqu.d.ts} +45 -482
  16. package/dist/thread-manager-qc0g5Rvd.d.cts +39 -0
  17. package/dist/thread-manager-qc0g5Rvd.d.ts +39 -0
  18. package/dist/workflow.cjs +59 -27
  19. package/dist/workflow.cjs.map +1 -1
  20. package/dist/workflow.d.cts +459 -6
  21. package/dist/workflow.d.ts +459 -6
  22. package/dist/workflow.js +60 -29
  23. package/dist/workflow.js.map +1 -1
  24. package/package.json +17 -2
  25. package/src/adapters/langchain/activities.ts +120 -0
  26. package/src/adapters/langchain/index.ts +38 -0
  27. package/src/adapters/langchain/model-invoker.ts +102 -0
  28. package/src/adapters/langchain/thread-manager.ts +142 -0
  29. package/src/index.ts +24 -23
  30. package/src/lib/fs.ts +25 -0
  31. package/src/lib/model-invoker.ts +15 -75
  32. package/src/lib/session.ts +52 -21
  33. package/src/lib/state-manager.ts +23 -5
  34. package/src/lib/thread-id.ts +25 -0
  35. package/src/lib/thread-manager.ts +18 -142
  36. package/src/lib/tool-router.ts +12 -18
  37. package/src/lib/types.ts +26 -10
  38. package/src/lib/workflow-helpers.ts +50 -0
  39. package/src/tools/ask-user-question/handler.ts +25 -1
  40. package/src/tools/bash/handler.ts +13 -0
  41. package/src/tools/subagent/handler.ts +16 -5
  42. package/src/tools/subagent/tool.ts +34 -15
  43. package/src/workflow.ts +26 -7
  44. package/tsup.config.ts +1 -0
  45. package/src/activities.ts +0 -91
  46. package/src/plugin.ts +0 -28
package/dist/index.js CHANGED
@@ -1,8 +1,5 @@
1
- import { setHandler, defineUpdate, ApplicationFailure, condition, proxyActivities, defineQuery, uuid4, workflowInfo, executeChild } from '@temporalio/workflow';
1
+ import { uuid4, setHandler, defineUpdate, ApplicationFailure, condition, proxyActivities, defineQuery, workflowInfo, executeChild } from '@temporalio/workflow';
2
2
  import z14, { z } from 'zod';
3
- import { SimplePlugin } from '@temporalio/plugin';
4
- import { mapStoredMessagesToChatMessages, ToolMessage, AIMessage, SystemMessage, HumanMessage } from '@langchain/core/messages';
5
- import { randomUUID, randomFillSync } from 'crypto';
6
3
  import { Context } from '@temporalio/activity';
7
4
  import { Bash } from 'just-bash';
8
5
  import { readFile, readdir } from 'fs/promises';
@@ -11,8 +8,11 @@ import { join } from 'path';
11
8
  // src/lib/session.ts
12
9
  var SUBAGENT_TOOL_NAME = "Subagent";
13
10
  function buildSubagentDescription(subagents) {
14
- const subagentList = subagents.map((s) => `## ${s.agentName}
15
- ${s.description}`).join("\n\n");
11
+ const subagentList = subagents.map((s) => {
12
+ const continuation = s.allowThreadContinuation ? "\n*(Supports thread continuation \u2014 pass a threadId to resume a previous conversation)*" : "";
13
+ return `## ${s.agentName}
14
+ ${s.description}${continuation}`;
15
+ }).join("\n\n");
16
16
  return `The ${SUBAGENT_TOOL_NAME} tool launches specialized agents (subagents) that autonomously handle complex work. Each agent type has specific capabilities and tools available to it.
17
17
 
18
18
  # Available subagents:
@@ -24,16 +24,38 @@ function createSubagentTool(subagents) {
24
24
  throw new Error("createTaskTool requires at least one subagent");
25
25
  }
26
26
  const names = subagents.map((s) => s.agentName);
27
+ const hasThreadContinuation = subagents.some(
28
+ (s) => s.allowThreadContinuation
29
+ );
30
+ const baseFields = {
31
+ subagent: z14.enum(names).describe("The type of subagent to launch"),
32
+ description: z14.string().describe("A short (3-5 word) description of the task"),
33
+ prompt: z14.string().describe("The task for the agent to perform")
34
+ };
35
+ const schema = hasThreadContinuation ? z14.object({
36
+ ...baseFields,
37
+ threadId: z14.string().nullable().describe(
38
+ "Thread ID to continue an existing conversation, or null to start a new one"
39
+ )
40
+ }) : z14.object(baseFields);
27
41
  return {
28
42
  name: SUBAGENT_TOOL_NAME,
29
43
  description: buildSubagentDescription(subagents),
30
- schema: z14.object({
31
- subagent: z14.enum(names).describe("The type of subagent to launch"),
32
- description: z14.string().describe("A short (3-5 word) description of the task"),
33
- prompt: z14.string().describe("The task for the agent to perform")
34
- })
44
+ schema
35
45
  };
36
46
  }
47
+ var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
48
+ function getShortId(length = 12) {
49
+ const hex = uuid4().replace(/-/g, "");
50
+ let result = "";
51
+ for (let i = 0; i < length; i++) {
52
+ const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
53
+ result += BASE62[byte % BASE62.length];
54
+ }
55
+ return result;
56
+ }
57
+
58
+ // src/tools/subagent/handler.ts
37
59
  function createSubagentHandler(subagents) {
38
60
  const { taskQueue: parentTaskQueue } = workflowInfo();
39
61
  return async (args) => {
@@ -43,17 +65,18 @@ function createSubagentHandler(subagents) {
43
65
  `Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
44
66
  );
45
67
  }
46
- const childWorkflowId = `${args.subagent}-${uuid4()}`;
68
+ const childWorkflowId = `${args.subagent}-${getShortId()}`;
47
69
  const input = {
48
70
  prompt: args.prompt,
49
- ...config.context && { context: config.context }
71
+ ...config.context && { context: config.context },
72
+ ...args.threadId && config.allowThreadContinuation && { threadId: args.threadId }
50
73
  };
51
74
  const childOpts = {
52
75
  workflowId: childWorkflowId,
53
76
  args: [input],
54
77
  taskQueue: config.taskQueue ?? parentTaskQueue
55
78
  };
56
- const { toolResponse, data, usage } = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
79
+ const { toolResponse, data, usage, threadId: childThreadId } = typeof config.workflow === "string" ? await executeChild(config.workflow, childOpts) : await executeChild(config.workflow, childOpts);
57
80
  if (!toolResponse) {
58
81
  return {
59
82
  toolResponse: "Subagent workflow returned no response",
@@ -69,8 +92,14 @@ function createSubagentHandler(subagents) {
69
92
  ...usage && { usage }
70
93
  };
71
94
  }
95
+ let finalToolResponse = toolResponse;
96
+ if (config.allowThreadContinuation && childThreadId) {
97
+ finalToolResponse = typeof toolResponse === "string" ? `${toolResponse}
98
+
99
+ [Thread ID: ${childThreadId}]` : toolResponse;
100
+ }
72
101
  return {
73
- toolResponse,
102
+ toolResponse: finalToolResponse,
74
103
  data: validated ? validated.data : data,
75
104
  ...usage && { usage }
76
105
  };
@@ -458,7 +487,7 @@ function hasNoOtherToolCalls(toolCalls, excludeName) {
458
487
 
459
488
  // src/lib/session.ts
460
489
  var createSession = async ({
461
- threadId,
490
+ threadId: providedThreadId,
462
491
  agentName,
463
492
  maxTurns = 50,
464
493
  metadata = {},
@@ -471,8 +500,10 @@ var createSession = async ({
471
500
  processToolsInParallel = true,
472
501
  hooks = {},
473
502
  appendSystemPrompt = true,
503
+ continueThread = false,
474
504
  waitForInputTimeout = "48h"
475
505
  }) => {
506
+ const threadId = providedThreadId ?? getShortId();
476
507
  const {
477
508
  appendToolResult,
478
509
  appendHumanMessage,
@@ -530,15 +561,18 @@ var createSession = async ({
530
561
  });
531
562
  }
532
563
  const systemPrompt = stateManager.getSystemPrompt();
533
- await initializeThread(threadId);
534
- if (appendSystemPrompt) {
535
- if (!systemPrompt || systemPrompt.trim() === "") {
536
- throw ApplicationFailure.create({
537
- message: "No system prompt in state",
538
- nonRetryable: true
539
- });
564
+ if (!continueThread) {
565
+ if (appendSystemPrompt) {
566
+ if (!systemPrompt || systemPrompt.trim() === "") {
567
+ throw ApplicationFailure.create({
568
+ message: "No system prompt in state",
569
+ nonRetryable: true
570
+ });
571
+ }
572
+ await appendSystemMessage(threadId, systemPrompt);
573
+ } else {
574
+ await initializeThread(threadId);
540
575
  }
541
- await appendSystemMessage(threadId, systemPrompt);
542
576
  }
543
577
  await appendHumanMessage(threadId, await buildContextMessage());
544
578
  let exitReason = "completed";
@@ -620,7 +654,7 @@ var createSession = async ({
620
654
  };
621
655
  };
622
656
  function proxyDefaultThreadOps(options) {
623
- const activities = proxyActivities(
657
+ return proxyActivities(
624
658
  options ?? {
625
659
  startToCloseTimeout: "10s",
626
660
  retry: {
@@ -631,12 +665,6 @@ function proxyDefaultThreadOps(options) {
631
665
  }
632
666
  }
633
667
  );
634
- return {
635
- initializeThread: activities.initializeThread,
636
- appendHumanMessage: activities.appendHumanMessage,
637
- appendToolResult: activities.appendToolResult,
638
- appendSystemMessage: activities.appendSystemMessage
639
- };
640
668
  }
641
669
 
642
670
  // src/lib/types.ts
@@ -1223,51 +1251,6 @@ var createAskUserQuestionHandler = () => async (args) => {
1223
1251
  };
1224
1252
  };
1225
1253
 
1226
- // node_modules/uuid/dist/esm/stringify.js
1227
- var byteToHex = [];
1228
- for (let i = 0; i < 256; ++i) {
1229
- byteToHex.push((i + 256).toString(16).slice(1));
1230
- }
1231
- function unsafeStringify(arr, offset = 0) {
1232
- return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
1233
- }
1234
- var rnds8Pool = new Uint8Array(256);
1235
- var poolPtr = rnds8Pool.length;
1236
- function rng() {
1237
- if (poolPtr > rnds8Pool.length - 16) {
1238
- randomFillSync(rnds8Pool);
1239
- poolPtr = 0;
1240
- }
1241
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
1242
- }
1243
- var native_default = { randomUUID };
1244
-
1245
- // node_modules/uuid/dist/esm/v4.js
1246
- function v4(options, buf, offset) {
1247
- if (native_default.randomUUID && !buf && !options) {
1248
- return native_default.randomUUID();
1249
- }
1250
- options = options || {};
1251
- const rnds = options.random ?? options.rng?.() ?? rng();
1252
- if (rnds.length < 16) {
1253
- throw new Error("Random bytes length must be >= 16");
1254
- }
1255
- rnds[6] = rnds[6] & 15 | 64;
1256
- rnds[8] = rnds[8] & 63 | 128;
1257
- if (buf) {
1258
- offset = offset || 0;
1259
- if (offset < 0 || offset + 16 > buf.length) {
1260
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
1261
- }
1262
- for (let i = 0; i < 16; ++i) {
1263
- buf[offset + i] = rnds[i];
1264
- }
1265
- return buf;
1266
- }
1267
- return unsafeStringify(rnds);
1268
- }
1269
- var v4_default = v4;
1270
-
1271
1254
  // src/lib/thread-manager.ts
1272
1255
  var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
1273
1256
  var APPEND_IDEMPOTENT_SCRIPT = `
@@ -1284,29 +1267,36 @@ return 1
1284
1267
  function getThreadKey(threadId, key) {
1285
1268
  return `thread:${threadId}:${key}`;
1286
1269
  }
1287
- function storedMessageId(msg) {
1288
- return msg.data.id ?? "";
1289
- }
1290
1270
  function createThreadManager(config) {
1291
1271
  const {
1292
1272
  redis,
1293
1273
  threadId,
1294
1274
  key = "messages",
1295
1275
  serialize = (m) => JSON.stringify(m),
1296
- deserialize = (raw) => JSON.parse(raw)
1276
+ deserialize = (raw) => JSON.parse(raw),
1277
+ idOf
1297
1278
  } = config;
1298
1279
  const redisKey = getThreadKey(threadId, key);
1299
- const idOf = config.idOf ?? (!config.serialize ? storedMessageId : void 0);
1300
- const base = {
1280
+ const metaKey = getThreadKey(threadId, `${key}:meta`);
1281
+ async function assertThreadExists() {
1282
+ const exists = await redis.exists(metaKey);
1283
+ if (!exists) {
1284
+ throw new Error(`Thread "${threadId}" (key: ${key}) does not exist`);
1285
+ }
1286
+ }
1287
+ return {
1301
1288
  async initialize() {
1302
1289
  await redis.del(redisKey);
1290
+ await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
1303
1291
  },
1304
1292
  async load() {
1293
+ await assertThreadExists();
1305
1294
  const data = await redis.lrange(redisKey, 0, -1);
1306
1295
  return data.map(deserialize);
1307
1296
  },
1308
1297
  async append(messages) {
1309
1298
  if (messages.length === 0) return;
1299
+ await assertThreadExists();
1310
1300
  if (idOf) {
1311
1301
  const dedupId = messages.map(idOf).join(":");
1312
1302
  const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
@@ -1324,135 +1314,25 @@ function createThreadManager(config) {
1324
1314
  }
1325
1315
  },
1326
1316
  async delete() {
1327
- await redis.del(redisKey);
1328
- }
1329
- };
1330
- const helpers = {
1331
- createHumanMessage(content) {
1332
- return new HumanMessage({
1333
- id: v4_default(),
1334
- content
1335
- }).toDict();
1336
- },
1337
- createSystemMessage(content) {
1338
- return new SystemMessage({
1339
- id: v4_default(),
1340
- content
1341
- }).toDict();
1342
- },
1343
- createAIMessage(content, kwargs) {
1344
- return new AIMessage({
1345
- id: v4_default(),
1346
- content,
1347
- additional_kwargs: kwargs ? {
1348
- header: kwargs.header,
1349
- options: kwargs.options,
1350
- multiSelect: kwargs.multiSelect
1351
- } : void 0
1352
- }).toDict();
1353
- },
1354
- createToolMessage(content, toolCallId) {
1355
- return new ToolMessage({
1356
- id: v4_default(),
1357
- content,
1358
- tool_call_id: toolCallId
1359
- }).toDict();
1360
- },
1361
- async appendHumanMessage(content) {
1362
- const message = helpers.createHumanMessage(content);
1363
- await base.append([message]);
1364
- },
1365
- async appendToolMessage(content, toolCallId) {
1366
- const message = helpers.createToolMessage(content, toolCallId);
1367
- await base.append([message]);
1368
- },
1369
- async appendAIMessage(content) {
1370
- const message = helpers.createAIMessage(content);
1371
- await base.append([message]);
1372
- },
1373
- async appendSystemMessage(content) {
1374
- const message = helpers.createSystemMessage(content);
1375
- await base.append([message]);
1376
- }
1377
- };
1378
- return Object.assign(base, helpers);
1379
- }
1380
-
1381
- // src/activities.ts
1382
- function createSharedActivities(redis) {
1383
- return {
1384
- async appendToolResult(config) {
1385
- const { threadId, toolCallId, content } = config;
1386
- const thread = createThreadManager({ redis, threadId });
1387
- await thread.appendToolMessage(content, toolCallId);
1388
- },
1389
- async initializeThread(threadId) {
1390
- const thread = createThreadManager({ redis, threadId });
1391
- await thread.initialize();
1392
- },
1393
- async appendThreadMessages(threadId, messages) {
1394
- const thread = createThreadManager({ redis, threadId });
1395
- await thread.append(messages);
1396
- },
1397
- async appendHumanMessage(threadId, content) {
1398
- const thread = createThreadManager({ redis, threadId });
1399
- await thread.appendHumanMessage(content);
1400
- },
1401
- async appendSystemMessage(threadId, content) {
1402
- const thread = createThreadManager({ redis, threadId });
1403
- await thread.appendSystemMessage(content);
1317
+ await redis.del(redisKey, metaKey);
1404
1318
  }
1405
1319
  };
1406
1320
  }
1407
-
1408
- // src/plugin.ts
1409
- var ZeitlichPlugin = class extends SimplePlugin {
1410
- constructor(options) {
1411
- super({
1412
- name: "ZeitlichPlugin",
1413
- activities: createSharedActivities(options.redis)
1414
- });
1415
- }
1416
- };
1417
- async function invokeModel({
1418
- redis,
1419
- model,
1420
- client,
1421
- config: { threadId, agentName }
1422
- }) {
1423
- const thread = createThreadManager({ redis, threadId });
1424
- const runId = v4_default();
1425
- const info = Context.current().info;
1426
- const parentWorkflowId = info.workflowExecution.workflowId;
1427
- const parentRunId = info.workflowExecution.runId;
1428
- const handle = client.getHandle(parentWorkflowId, parentRunId);
1429
- const { tools } = await handle.query(agentQueryName(agentName));
1430
- const messages = await thread.load();
1431
- const response = await model.invoke(
1432
- [...mapStoredMessagesToChatMessages(messages)],
1433
- {
1434
- runName: agentName,
1435
- runId,
1436
- metadata: { thread_id: threadId },
1437
- tools
1438
- }
1321
+ async function queryParentWorkflowState(client, queryName) {
1322
+ const { workflowExecution } = Context.current().info;
1323
+ const handle = client.getHandle(
1324
+ workflowExecution.workflowId,
1325
+ workflowExecution.runId
1439
1326
  );
1440
- await thread.append([response.toDict()]);
1441
- const toolCalls = response.tool_calls ?? [];
1442
- return {
1443
- message: response.toDict(),
1444
- rawToolCalls: toolCalls.map((tc) => ({
1445
- id: tc.id,
1446
- name: tc.name,
1447
- args: tc.args
1448
- })),
1449
- usage: {
1450
- inputTokens: response.usage_metadata?.input_tokens,
1451
- outputTokens: response.usage_metadata?.output_tokens,
1452
- reasonTokens: response.usage_metadata?.output_token_details?.reasoning,
1453
- cachedWriteTokens: response.usage_metadata?.input_token_details?.cache_creation,
1454
- cachedReadTokens: response.usage_metadata?.input_token_details?.cache_read
1455
- }
1327
+ return handle.query(queryName);
1328
+ }
1329
+ function createRunAgentActivity(client, invoker) {
1330
+ return async (config) => {
1331
+ const state = await queryParentWorkflowState(
1332
+ client,
1333
+ agentQueryName(config.agentName)
1334
+ );
1335
+ return invoker({ ...config, state });
1456
1336
  };
1457
1337
  }
1458
1338
  function createGlobHandler(fs) {
@@ -1679,6 +1559,6 @@ var FileSystemSkillProvider = class {
1679
1559
  }
1680
1560
  };
1681
1561
 
1682
- export { FileSystemSkillProvider, ZeitlichPlugin, agentQueryName, agentStateChangeUpdateName, askUserQuestionTool, bashTool, createAgentStateManager, createAskUserQuestionHandler, createBashHandler, createBashToolDescription, createEditHandler, createGlobHandler, createReadSkillHandler, createReadSkillTool, createSession, createSharedActivities, createSubagentTool, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, defineSubagent, defineTool, editTool, globTool, grepTool, hasNoOtherToolCalls, invokeModel, isTerminalStatus, parseSkillFile, proxyDefaultThreadOps, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, writeFileTool };
1562
+ export { FileSystemSkillProvider, agentQueryName, agentStateChangeUpdateName, askUserQuestionTool, bashTool, createAgentStateManager, createAskUserQuestionHandler, createBashHandler, createBashToolDescription, createEditHandler, createGlobHandler, createReadSkillHandler, createReadSkillTool, createRunAgentActivity, createSession, createSubagentTool, createTaskCreateHandler, createTaskGetHandler, createTaskListHandler, createTaskUpdateHandler, createThreadManager, createToolRouter, defineSubagent, defineTool, editTool, getShortId, globTool, grepTool, hasNoOtherToolCalls, isTerminalStatus, parseSkillFile, proxyDefaultThreadOps, queryParentWorkflowState, readFileTool, taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, toTree, withAutoAppend, writeFileTool };
1683
1563
  //# sourceMappingURL=index.js.map
1684
1564
  //# sourceMappingURL=index.js.map