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.cjs CHANGED
@@ -2,9 +2,6 @@
2
2
 
3
3
  var workflow = require('@temporalio/workflow');
4
4
  var z14 = require('zod');
5
- var plugin = require('@temporalio/plugin');
6
- var messages = require('@langchain/core/messages');
7
- var crypto = require('crypto');
8
5
  var activity = require('@temporalio/activity');
9
6
  var justBash = require('just-bash');
10
7
  var promises = require('fs/promises');
@@ -17,8 +14,11 @@ var z14__default = /*#__PURE__*/_interopDefault(z14);
17
14
  // src/lib/session.ts
18
15
  var SUBAGENT_TOOL_NAME = "Subagent";
19
16
  function buildSubagentDescription(subagents) {
20
- const subagentList = subagents.map((s) => `## ${s.agentName}
21
- ${s.description}`).join("\n\n");
17
+ const subagentList = subagents.map((s) => {
18
+ const continuation = s.allowThreadContinuation ? "\n*(Supports thread continuation \u2014 pass a threadId to resume a previous conversation)*" : "";
19
+ return `## ${s.agentName}
20
+ ${s.description}${continuation}`;
21
+ }).join("\n\n");
22
22
  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.
23
23
 
24
24
  # Available subagents:
@@ -30,16 +30,38 @@ function createSubagentTool(subagents) {
30
30
  throw new Error("createTaskTool requires at least one subagent");
31
31
  }
32
32
  const names = subagents.map((s) => s.agentName);
33
+ const hasThreadContinuation = subagents.some(
34
+ (s) => s.allowThreadContinuation
35
+ );
36
+ const baseFields = {
37
+ subagent: z14__default.default.enum(names).describe("The type of subagent to launch"),
38
+ description: z14__default.default.string().describe("A short (3-5 word) description of the task"),
39
+ prompt: z14__default.default.string().describe("The task for the agent to perform")
40
+ };
41
+ const schema = hasThreadContinuation ? z14__default.default.object({
42
+ ...baseFields,
43
+ threadId: z14__default.default.string().nullable().describe(
44
+ "Thread ID to continue an existing conversation, or null to start a new one"
45
+ )
46
+ }) : z14__default.default.object(baseFields);
33
47
  return {
34
48
  name: SUBAGENT_TOOL_NAME,
35
49
  description: buildSubagentDescription(subagents),
36
- schema: z14__default.default.object({
37
- subagent: z14__default.default.enum(names).describe("The type of subagent to launch"),
38
- description: z14__default.default.string().describe("A short (3-5 word) description of the task"),
39
- prompt: z14__default.default.string().describe("The task for the agent to perform")
40
- })
50
+ schema
41
51
  };
42
52
  }
53
+ var BASE62 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
54
+ function getShortId(length = 12) {
55
+ const hex = workflow.uuid4().replace(/-/g, "");
56
+ let result = "";
57
+ for (let i = 0; i < length; i++) {
58
+ const byte = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
59
+ result += BASE62[byte % BASE62.length];
60
+ }
61
+ return result;
62
+ }
63
+
64
+ // src/tools/subagent/handler.ts
43
65
  function createSubagentHandler(subagents) {
44
66
  const { taskQueue: parentTaskQueue } = workflow.workflowInfo();
45
67
  return async (args) => {
@@ -49,17 +71,18 @@ function createSubagentHandler(subagents) {
49
71
  `Unknown subagent: ${args.subagent}. Available: ${subagents.map((s) => s.agentName).join(", ")}`
50
72
  );
51
73
  }
52
- const childWorkflowId = `${args.subagent}-${workflow.uuid4()}`;
74
+ const childWorkflowId = `${args.subagent}-${getShortId()}`;
53
75
  const input = {
54
76
  prompt: args.prompt,
55
- ...config.context && { context: config.context }
77
+ ...config.context && { context: config.context },
78
+ ...args.threadId && config.allowThreadContinuation && { threadId: args.threadId }
56
79
  };
57
80
  const childOpts = {
58
81
  workflowId: childWorkflowId,
59
82
  args: [input],
60
83
  taskQueue: config.taskQueue ?? parentTaskQueue
61
84
  };
62
- const { toolResponse, data, usage } = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
85
+ const { toolResponse, data, usage, threadId: childThreadId } = typeof config.workflow === "string" ? await workflow.executeChild(config.workflow, childOpts) : await workflow.executeChild(config.workflow, childOpts);
63
86
  if (!toolResponse) {
64
87
  return {
65
88
  toolResponse: "Subagent workflow returned no response",
@@ -75,8 +98,14 @@ function createSubagentHandler(subagents) {
75
98
  ...usage && { usage }
76
99
  };
77
100
  }
101
+ let finalToolResponse = toolResponse;
102
+ if (config.allowThreadContinuation && childThreadId) {
103
+ finalToolResponse = typeof toolResponse === "string" ? `${toolResponse}
104
+
105
+ [Thread ID: ${childThreadId}]` : toolResponse;
106
+ }
78
107
  return {
79
- toolResponse,
108
+ toolResponse: finalToolResponse,
80
109
  data: validated ? validated.data : data,
81
110
  ...usage && { usage }
82
111
  };
@@ -464,7 +493,7 @@ function hasNoOtherToolCalls(toolCalls, excludeName) {
464
493
 
465
494
  // src/lib/session.ts
466
495
  var createSession = async ({
467
- threadId,
496
+ threadId: providedThreadId,
468
497
  agentName,
469
498
  maxTurns = 50,
470
499
  metadata = {},
@@ -477,8 +506,10 @@ var createSession = async ({
477
506
  processToolsInParallel = true,
478
507
  hooks = {},
479
508
  appendSystemPrompt = true,
509
+ continueThread = false,
480
510
  waitForInputTimeout = "48h"
481
511
  }) => {
512
+ const threadId = providedThreadId ?? getShortId();
482
513
  const {
483
514
  appendToolResult,
484
515
  appendHumanMessage,
@@ -536,15 +567,18 @@ var createSession = async ({
536
567
  });
537
568
  }
538
569
  const systemPrompt = stateManager.getSystemPrompt();
539
- await initializeThread(threadId);
540
- if (appendSystemPrompt) {
541
- if (!systemPrompt || systemPrompt.trim() === "") {
542
- throw workflow.ApplicationFailure.create({
543
- message: "No system prompt in state",
544
- nonRetryable: true
545
- });
570
+ if (!continueThread) {
571
+ if (appendSystemPrompt) {
572
+ if (!systemPrompt || systemPrompt.trim() === "") {
573
+ throw workflow.ApplicationFailure.create({
574
+ message: "No system prompt in state",
575
+ nonRetryable: true
576
+ });
577
+ }
578
+ await appendSystemMessage(threadId, systemPrompt);
579
+ } else {
580
+ await initializeThread(threadId);
546
581
  }
547
- await appendSystemMessage(threadId, systemPrompt);
548
582
  }
549
583
  await appendHumanMessage(threadId, await buildContextMessage());
550
584
  let exitReason = "completed";
@@ -626,7 +660,7 @@ var createSession = async ({
626
660
  };
627
661
  };
628
662
  function proxyDefaultThreadOps(options) {
629
- const activities = workflow.proxyActivities(
663
+ return workflow.proxyActivities(
630
664
  options ?? {
631
665
  startToCloseTimeout: "10s",
632
666
  retry: {
@@ -637,12 +671,6 @@ function proxyDefaultThreadOps(options) {
637
671
  }
638
672
  }
639
673
  );
640
- return {
641
- initializeThread: activities.initializeThread,
642
- appendHumanMessage: activities.appendHumanMessage,
643
- appendToolResult: activities.appendToolResult,
644
- appendSystemMessage: activities.appendSystemMessage
645
- };
646
674
  }
647
675
 
648
676
  // src/lib/types.ts
@@ -1229,51 +1257,6 @@ var createAskUserQuestionHandler = () => async (args) => {
1229
1257
  };
1230
1258
  };
1231
1259
 
1232
- // node_modules/uuid/dist/esm/stringify.js
1233
- var byteToHex = [];
1234
- for (let i = 0; i < 256; ++i) {
1235
- byteToHex.push((i + 256).toString(16).slice(1));
1236
- }
1237
- function unsafeStringify(arr, offset = 0) {
1238
- 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();
1239
- }
1240
- var rnds8Pool = new Uint8Array(256);
1241
- var poolPtr = rnds8Pool.length;
1242
- function rng() {
1243
- if (poolPtr > rnds8Pool.length - 16) {
1244
- crypto.randomFillSync(rnds8Pool);
1245
- poolPtr = 0;
1246
- }
1247
- return rnds8Pool.slice(poolPtr, poolPtr += 16);
1248
- }
1249
- var native_default = { randomUUID: crypto.randomUUID };
1250
-
1251
- // node_modules/uuid/dist/esm/v4.js
1252
- function v4(options, buf, offset) {
1253
- if (native_default.randomUUID && !buf && !options) {
1254
- return native_default.randomUUID();
1255
- }
1256
- options = options || {};
1257
- const rnds = options.random ?? options.rng?.() ?? rng();
1258
- if (rnds.length < 16) {
1259
- throw new Error("Random bytes length must be >= 16");
1260
- }
1261
- rnds[6] = rnds[6] & 15 | 64;
1262
- rnds[8] = rnds[8] & 63 | 128;
1263
- if (buf) {
1264
- offset = offset || 0;
1265
- if (offset < 0 || offset + 16 > buf.length) {
1266
- throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
1267
- }
1268
- for (let i = 0; i < 16; ++i) {
1269
- buf[offset + i] = rnds[i];
1270
- }
1271
- return buf;
1272
- }
1273
- return unsafeStringify(rnds);
1274
- }
1275
- var v4_default = v4;
1276
-
1277
1260
  // src/lib/thread-manager.ts
1278
1261
  var THREAD_TTL_SECONDS = 60 * 60 * 24 * 90;
1279
1262
  var APPEND_IDEMPOTENT_SCRIPT = `
@@ -1290,29 +1273,36 @@ return 1
1290
1273
  function getThreadKey(threadId, key) {
1291
1274
  return `thread:${threadId}:${key}`;
1292
1275
  }
1293
- function storedMessageId(msg) {
1294
- return msg.data.id ?? "";
1295
- }
1296
1276
  function createThreadManager(config) {
1297
1277
  const {
1298
1278
  redis,
1299
1279
  threadId,
1300
1280
  key = "messages",
1301
1281
  serialize = (m) => JSON.stringify(m),
1302
- deserialize = (raw) => JSON.parse(raw)
1282
+ deserialize = (raw) => JSON.parse(raw),
1283
+ idOf
1303
1284
  } = config;
1304
1285
  const redisKey = getThreadKey(threadId, key);
1305
- const idOf = config.idOf ?? (!config.serialize ? storedMessageId : void 0);
1306
- const base = {
1286
+ const metaKey = getThreadKey(threadId, `${key}:meta`);
1287
+ async function assertThreadExists() {
1288
+ const exists = await redis.exists(metaKey);
1289
+ if (!exists) {
1290
+ throw new Error(`Thread "${threadId}" (key: ${key}) does not exist`);
1291
+ }
1292
+ }
1293
+ return {
1307
1294
  async initialize() {
1308
1295
  await redis.del(redisKey);
1296
+ await redis.set(metaKey, "1", "EX", THREAD_TTL_SECONDS);
1309
1297
  },
1310
1298
  async load() {
1299
+ await assertThreadExists();
1311
1300
  const data = await redis.lrange(redisKey, 0, -1);
1312
1301
  return data.map(deserialize);
1313
1302
  },
1314
1303
  async append(messages) {
1315
1304
  if (messages.length === 0) return;
1305
+ await assertThreadExists();
1316
1306
  if (idOf) {
1317
1307
  const dedupId = messages.map(idOf).join(":");
1318
1308
  const dedupKey = getThreadKey(threadId, `dedup:${dedupId}`);
@@ -1330,135 +1320,25 @@ function createThreadManager(config) {
1330
1320
  }
1331
1321
  },
1332
1322
  async delete() {
1333
- await redis.del(redisKey);
1334
- }
1335
- };
1336
- const helpers = {
1337
- createHumanMessage(content) {
1338
- return new messages.HumanMessage({
1339
- id: v4_default(),
1340
- content
1341
- }).toDict();
1342
- },
1343
- createSystemMessage(content) {
1344
- return new messages.SystemMessage({
1345
- id: v4_default(),
1346
- content
1347
- }).toDict();
1348
- },
1349
- createAIMessage(content, kwargs) {
1350
- return new messages.AIMessage({
1351
- id: v4_default(),
1352
- content,
1353
- additional_kwargs: kwargs ? {
1354
- header: kwargs.header,
1355
- options: kwargs.options,
1356
- multiSelect: kwargs.multiSelect
1357
- } : void 0
1358
- }).toDict();
1359
- },
1360
- createToolMessage(content, toolCallId) {
1361
- return new messages.ToolMessage({
1362
- id: v4_default(),
1363
- content,
1364
- tool_call_id: toolCallId
1365
- }).toDict();
1366
- },
1367
- async appendHumanMessage(content) {
1368
- const message = helpers.createHumanMessage(content);
1369
- await base.append([message]);
1370
- },
1371
- async appendToolMessage(content, toolCallId) {
1372
- const message = helpers.createToolMessage(content, toolCallId);
1373
- await base.append([message]);
1374
- },
1375
- async appendAIMessage(content) {
1376
- const message = helpers.createAIMessage(content);
1377
- await base.append([message]);
1378
- },
1379
- async appendSystemMessage(content) {
1380
- const message = helpers.createSystemMessage(content);
1381
- await base.append([message]);
1382
- }
1383
- };
1384
- return Object.assign(base, helpers);
1385
- }
1386
-
1387
- // src/activities.ts
1388
- function createSharedActivities(redis) {
1389
- return {
1390
- async appendToolResult(config) {
1391
- const { threadId, toolCallId, content } = config;
1392
- const thread = createThreadManager({ redis, threadId });
1393
- await thread.appendToolMessage(content, toolCallId);
1394
- },
1395
- async initializeThread(threadId) {
1396
- const thread = createThreadManager({ redis, threadId });
1397
- await thread.initialize();
1398
- },
1399
- async appendThreadMessages(threadId, messages) {
1400
- const thread = createThreadManager({ redis, threadId });
1401
- await thread.append(messages);
1402
- },
1403
- async appendHumanMessage(threadId, content) {
1404
- const thread = createThreadManager({ redis, threadId });
1405
- await thread.appendHumanMessage(content);
1406
- },
1407
- async appendSystemMessage(threadId, content) {
1408
- const thread = createThreadManager({ redis, threadId });
1409
- await thread.appendSystemMessage(content);
1323
+ await redis.del(redisKey, metaKey);
1410
1324
  }
1411
1325
  };
1412
1326
  }
1413
-
1414
- // src/plugin.ts
1415
- var ZeitlichPlugin = class extends plugin.SimplePlugin {
1416
- constructor(options) {
1417
- super({
1418
- name: "ZeitlichPlugin",
1419
- activities: createSharedActivities(options.redis)
1420
- });
1421
- }
1422
- };
1423
- async function invokeModel({
1424
- redis,
1425
- model,
1426
- client,
1427
- config: { threadId, agentName }
1428
- }) {
1429
- const thread = createThreadManager({ redis, threadId });
1430
- const runId = v4_default();
1431
- const info = activity.Context.current().info;
1432
- const parentWorkflowId = info.workflowExecution.workflowId;
1433
- const parentRunId = info.workflowExecution.runId;
1434
- const handle = client.getHandle(parentWorkflowId, parentRunId);
1435
- const { tools } = await handle.query(agentQueryName(agentName));
1436
- const messages$1 = await thread.load();
1437
- const response = await model.invoke(
1438
- [...messages.mapStoredMessagesToChatMessages(messages$1)],
1439
- {
1440
- runName: agentName,
1441
- runId,
1442
- metadata: { thread_id: threadId },
1443
- tools
1444
- }
1327
+ async function queryParentWorkflowState(client, queryName) {
1328
+ const { workflowExecution } = activity.Context.current().info;
1329
+ const handle = client.getHandle(
1330
+ workflowExecution.workflowId,
1331
+ workflowExecution.runId
1445
1332
  );
1446
- await thread.append([response.toDict()]);
1447
- const toolCalls = response.tool_calls ?? [];
1448
- return {
1449
- message: response.toDict(),
1450
- rawToolCalls: toolCalls.map((tc) => ({
1451
- id: tc.id,
1452
- name: tc.name,
1453
- args: tc.args
1454
- })),
1455
- usage: {
1456
- inputTokens: response.usage_metadata?.input_tokens,
1457
- outputTokens: response.usage_metadata?.output_tokens,
1458
- reasonTokens: response.usage_metadata?.output_token_details?.reasoning,
1459
- cachedWriteTokens: response.usage_metadata?.input_token_details?.cache_creation,
1460
- cachedReadTokens: response.usage_metadata?.input_token_details?.cache_read
1461
- }
1333
+ return handle.query(queryName);
1334
+ }
1335
+ function createRunAgentActivity(client, invoker) {
1336
+ return async (config) => {
1337
+ const state = await queryParentWorkflowState(
1338
+ client,
1339
+ agentQueryName(config.agentName)
1340
+ );
1341
+ return invoker({ ...config, state });
1462
1342
  };
1463
1343
  }
1464
1344
  function createGlobHandler(fs) {
@@ -1686,7 +1566,6 @@ var FileSystemSkillProvider = class {
1686
1566
  };
1687
1567
 
1688
1568
  exports.FileSystemSkillProvider = FileSystemSkillProvider;
1689
- exports.ZeitlichPlugin = ZeitlichPlugin;
1690
1569
  exports.agentQueryName = agentQueryName;
1691
1570
  exports.agentStateChangeUpdateName = agentStateChangeUpdateName;
1692
1571
  exports.askUserQuestionTool = askUserQuestionTool;
@@ -1699,8 +1578,8 @@ exports.createEditHandler = createEditHandler;
1699
1578
  exports.createGlobHandler = createGlobHandler;
1700
1579
  exports.createReadSkillHandler = createReadSkillHandler;
1701
1580
  exports.createReadSkillTool = createReadSkillTool;
1581
+ exports.createRunAgentActivity = createRunAgentActivity;
1702
1582
  exports.createSession = createSession;
1703
- exports.createSharedActivities = createSharedActivities;
1704
1583
  exports.createSubagentTool = createSubagentTool;
1705
1584
  exports.createTaskCreateHandler = createTaskCreateHandler;
1706
1585
  exports.createTaskGetHandler = createTaskGetHandler;
@@ -1711,13 +1590,14 @@ exports.createToolRouter = createToolRouter;
1711
1590
  exports.defineSubagent = defineSubagent;
1712
1591
  exports.defineTool = defineTool;
1713
1592
  exports.editTool = editTool;
1593
+ exports.getShortId = getShortId;
1714
1594
  exports.globTool = globTool;
1715
1595
  exports.grepTool = grepTool;
1716
1596
  exports.hasNoOtherToolCalls = hasNoOtherToolCalls;
1717
- exports.invokeModel = invokeModel;
1718
1597
  exports.isTerminalStatus = isTerminalStatus;
1719
1598
  exports.parseSkillFile = parseSkillFile;
1720
1599
  exports.proxyDefaultThreadOps = proxyDefaultThreadOps;
1600
+ exports.queryParentWorkflowState = queryParentWorkflowState;
1721
1601
  exports.readFileTool = readFileTool;
1722
1602
  exports.taskCreateTool = taskCreateTool;
1723
1603
  exports.taskGetTool = taskGetTool;