@ai-sdk/harness-deepagents 1.0.93 → 1.0.94

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.
@@ -0,0 +1,137 @@
1
+ import { mkdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
2
+ import { dirname } from 'node:path';
3
+ import type { MemorySaver } from '@langchain/langgraph';
4
+
5
+ const SNAPSHOT_HEADER = 'deepagents-memory-saver-v1';
6
+
7
+ function encodeString(value: string): string {
8
+ return Buffer.from(value, 'utf8').toString('base64');
9
+ }
10
+
11
+ function decodeString(value: string): string {
12
+ return Buffer.from(value, 'base64').toString('utf8');
13
+ }
14
+
15
+ function encodeBytes(value: Uint8Array): string {
16
+ return Buffer.from(value).toString('base64');
17
+ }
18
+
19
+ function decodeBytes(value: string): Uint8Array {
20
+ return Buffer.from(value, 'base64');
21
+ }
22
+
23
+ export async function loadMemorySaver({
24
+ path,
25
+ saver,
26
+ }: {
27
+ path: string;
28
+ saver: MemorySaver;
29
+ }): Promise<void> {
30
+ let snapshot: string;
31
+ try {
32
+ snapshot = await readFile(path, 'utf8');
33
+ } catch (error) {
34
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;
35
+ throw error;
36
+ }
37
+
38
+ const [header, ...lines] = snapshot.split('\n');
39
+ if (header !== SNAPSHOT_HEADER) {
40
+ throw new Error('Unsupported Deep Agents conversation checkpoint format');
41
+ }
42
+
43
+ const storage: MemorySaver['storage'] = Object.create(null);
44
+ const writes: MemorySaver['writes'] = Object.create(null);
45
+
46
+ for (const line of lines) {
47
+ if (line === '') continue;
48
+ const fields = line.split('\t');
49
+ if (fields[0] === 'S' && fields.length === 7) {
50
+ const [, threadIdValue, namespaceValue, checkpointIdValue] = fields;
51
+ const threadId = decodeString(threadIdValue);
52
+ const namespace = decodeString(namespaceValue);
53
+ const checkpointId = decodeString(checkpointIdValue);
54
+ storage[threadId] ??= Object.create(null);
55
+ storage[threadId][namespace] ??= Object.create(null);
56
+ storage[threadId][namespace][checkpointId] = [
57
+ decodeBytes(fields[4]),
58
+ decodeBytes(fields[5]),
59
+ fields[6] === '' ? undefined : decodeString(fields[6]),
60
+ ];
61
+ continue;
62
+ }
63
+ if (fields[0] === 'W' && fields.length === 6) {
64
+ const [, keyValue, indexValue, taskIdValue, channelValue, value] = fields;
65
+ const key = decodeString(keyValue);
66
+ const index = decodeString(indexValue);
67
+ writes[key] ??= Object.create(null);
68
+ writes[key][index] = [
69
+ decodeString(taskIdValue),
70
+ decodeString(channelValue),
71
+ decodeBytes(value),
72
+ ];
73
+ continue;
74
+ }
75
+ throw new Error('Invalid Deep Agents conversation checkpoint');
76
+ }
77
+
78
+ saver.storage = storage;
79
+ saver.writes = writes;
80
+ }
81
+
82
+ export async function saveMemorySaver({
83
+ path,
84
+ saver,
85
+ }: {
86
+ path: string;
87
+ saver: MemorySaver;
88
+ }): Promise<void> {
89
+ const lines = [SNAPSHOT_HEADER];
90
+
91
+ for (const [threadId, namespaces] of Object.entries(saver.storage)) {
92
+ for (const [namespace, checkpoints] of Object.entries(namespaces)) {
93
+ for (const [
94
+ checkpointId,
95
+ [checkpoint, metadata, parentCheckpointId],
96
+ ] of Object.entries(checkpoints)) {
97
+ lines.push(
98
+ [
99
+ 'S',
100
+ encodeString(threadId),
101
+ encodeString(namespace),
102
+ encodeString(checkpointId),
103
+ encodeBytes(checkpoint),
104
+ encodeBytes(metadata),
105
+ parentCheckpointId == null ? '' : encodeString(parentCheckpointId),
106
+ ].join('\t'),
107
+ );
108
+ }
109
+ }
110
+ }
111
+
112
+ for (const [key, indexedWrites] of Object.entries(saver.writes)) {
113
+ for (const [index, [taskId, channel, value]] of Object.entries(
114
+ indexedWrites,
115
+ )) {
116
+ lines.push(
117
+ [
118
+ 'W',
119
+ encodeString(key),
120
+ encodeString(index),
121
+ encodeString(taskId),
122
+ encodeString(channel),
123
+ encodeBytes(value),
124
+ ].join('\t'),
125
+ );
126
+ }
127
+ }
128
+
129
+ await mkdir(dirname(path), { recursive: true });
130
+ const temporaryPath = `${path}.${process.pid}.tmp`;
131
+ await writeFile(temporaryPath, `${lines.join('\n')}\n`, 'utf8');
132
+ await rename(temporaryPath, path);
133
+ }
134
+
135
+ export async function removeMemorySaverSnapshot(path: string): Promise<void> {
136
+ await rm(path, { force: true });
137
+ }
@@ -222,7 +222,6 @@ export function createDeepAgents(
222
222
  lifecycleStateSchema: deepAgentsResumeStateSchema,
223
223
  getBootstrap: getDeepAgentsBootstrap,
224
224
  doStart: async startOpts => {
225
- const model = startOpts.model ?? settings.model;
226
225
  const permissionMode = startOpts.permissionMode;
227
226
  const sandboxSession = startOpts.sandboxSession;
228
227
  const toolSafeSandboxSession =
@@ -355,7 +354,7 @@ export function createDeepAgents(
355
354
  sessionId: startOpts.sessionId,
356
355
  channel: attachChannel,
357
356
  proc: undefined,
358
- model,
357
+ model: settings.model,
359
358
  thinking: settings.thinking,
360
359
  effort: settings.effort,
361
360
  bridgePort: coords.port,
@@ -413,7 +412,7 @@ export function createDeepAgents(
413
412
  });
414
413
 
415
414
  const proc = await toolSafeSandboxSession.spawn({
416
- command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)} --bootstrap-dir ${shellQuote(bootstrapDir)}`,
415
+ command: `node ${shellQuote(`${bootstrapDir}/bridge.mjs`)} --workdir ${shellQuote(workDir)} --bridge-state-dir ${shellQuote(bridgeStateDir)} --bootstrap-dir ${shellQuote(bootstrapDir)}${isResume ? ' --resume true' : ''}`,
417
416
  env,
418
417
  abortSignal: startOpts.abortSignal,
419
418
  });
@@ -470,7 +469,7 @@ export function createDeepAgents(
470
469
  sessionId: startOpts.sessionId,
471
470
  channel,
472
471
  proc,
473
- model,
472
+ model: settings.model,
474
473
  thinking: settings.thinking,
475
474
  effort: settings.effort,
476
475
  bridgePort: boundPort,
@@ -785,7 +784,6 @@ function createSession({
785
784
  return {
786
785
  sessionId,
787
786
  isResume,
788
- modelId: model,
789
787
  doPromptTurn: async promptOpts => {
790
788
  if (
791
789
  promptOpts.responseFormat?.type === 'json' &&
@@ -822,7 +820,9 @@ function createSession({
822
820
  ...(promptOpts.responseFormat == null
823
821
  ? {}
824
822
  : { responseFormat: promptOpts.responseFormat }),
825
- ...(model ? { model } : {}),
823
+ ...((promptOpts.model ?? model)
824
+ ? { model: promptOpts.model ?? model }
825
+ : {}),
826
826
  ...(thinking ? { thinking } : {}),
827
827
  ...(effort ? { effort } : {}),
828
828
  ...(skillsPaths?.length ? { skillsPaths } : {}),
@@ -915,7 +915,6 @@ function createSession({
915
915
  }
916
916
  stopped = true;
917
917
  await teardown({ channel, proc, operation: 'stop' });
918
- // In-memory conversation is lost on teardown; the sandbox snapshot preserves the workspace files, not the conversation.
919
918
  const payload: HarnessV1ResumeSessionState = {
920
919
  type: 'resume-session',
921
920
  harnessId: 'deepagents',