@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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # @ai-sdk/harness-deepagents
2
2
 
3
+ ## 1.0.94
4
+
5
+ ### Patch Changes
6
+
7
+ - 9ec34bd: Preserve Deep Agents conversation context when a stopped session is resumed.
8
+ - 8961fde: feat(harness): allow changing `model` between turns via call options
9
+ - Updated dependencies [8961fde]
10
+ - Updated dependencies [eb59f2a]
11
+ - @ai-sdk/harness@1.0.94
12
+ - @ai-sdk/provider-utils@5.0.34
13
+
3
14
  ## 1.0.93
4
15
 
5
16
  ### Patch Changes
@@ -1892,6 +1892,124 @@ function createLocalShellBackend({
1892
1892
  });
1893
1893
  }
1894
1894
 
1895
+ // src/bridge/persistent-memory-saver.ts
1896
+ import { mkdir as mkdir2, readFile, rename, rm, writeFile as writeFile2 } from "fs/promises";
1897
+ import { dirname } from "path";
1898
+ var SNAPSHOT_HEADER = "deepagents-memory-saver-v1";
1899
+ function encodeString(value) {
1900
+ return Buffer.from(value, "utf8").toString("base64");
1901
+ }
1902
+ function decodeString(value) {
1903
+ return Buffer.from(value, "base64").toString("utf8");
1904
+ }
1905
+ function encodeBytes(value) {
1906
+ return Buffer.from(value).toString("base64");
1907
+ }
1908
+ function decodeBytes(value) {
1909
+ return Buffer.from(value, "base64");
1910
+ }
1911
+ async function loadMemorySaver({
1912
+ path,
1913
+ saver
1914
+ }) {
1915
+ let snapshot;
1916
+ try {
1917
+ snapshot = await readFile(path, "utf8");
1918
+ } catch (error) {
1919
+ if (error.code === "ENOENT") return;
1920
+ throw error;
1921
+ }
1922
+ const [header, ...lines] = snapshot.split("\n");
1923
+ if (header !== SNAPSHOT_HEADER) {
1924
+ throw new Error("Unsupported Deep Agents conversation checkpoint format");
1925
+ }
1926
+ const storage = /* @__PURE__ */ Object.create(null);
1927
+ const writes = /* @__PURE__ */ Object.create(null);
1928
+ for (const line of lines) {
1929
+ if (line === "") continue;
1930
+ const fields = line.split(" ");
1931
+ if (fields[0] === "S" && fields.length === 7) {
1932
+ const [, threadIdValue, namespaceValue, checkpointIdValue] = fields;
1933
+ const threadId = decodeString(threadIdValue);
1934
+ const namespace = decodeString(namespaceValue);
1935
+ const checkpointId = decodeString(checkpointIdValue);
1936
+ storage[threadId] ??= /* @__PURE__ */ Object.create(null);
1937
+ storage[threadId][namespace] ??= /* @__PURE__ */ Object.create(null);
1938
+ storage[threadId][namespace][checkpointId] = [
1939
+ decodeBytes(fields[4]),
1940
+ decodeBytes(fields[5]),
1941
+ fields[6] === "" ? void 0 : decodeString(fields[6])
1942
+ ];
1943
+ continue;
1944
+ }
1945
+ if (fields[0] === "W" && fields.length === 6) {
1946
+ const [, keyValue, indexValue, taskIdValue, channelValue, value] = fields;
1947
+ const key = decodeString(keyValue);
1948
+ const index = decodeString(indexValue);
1949
+ writes[key] ??= /* @__PURE__ */ Object.create(null);
1950
+ writes[key][index] = [
1951
+ decodeString(taskIdValue),
1952
+ decodeString(channelValue),
1953
+ decodeBytes(value)
1954
+ ];
1955
+ continue;
1956
+ }
1957
+ throw new Error("Invalid Deep Agents conversation checkpoint");
1958
+ }
1959
+ saver.storage = storage;
1960
+ saver.writes = writes;
1961
+ }
1962
+ async function saveMemorySaver({
1963
+ path,
1964
+ saver
1965
+ }) {
1966
+ const lines = [SNAPSHOT_HEADER];
1967
+ for (const [threadId, namespaces] of Object.entries(saver.storage)) {
1968
+ for (const [namespace, checkpoints] of Object.entries(namespaces)) {
1969
+ for (const [
1970
+ checkpointId,
1971
+ [checkpoint, metadata, parentCheckpointId]
1972
+ ] of Object.entries(checkpoints)) {
1973
+ lines.push(
1974
+ [
1975
+ "S",
1976
+ encodeString(threadId),
1977
+ encodeString(namespace),
1978
+ encodeString(checkpointId),
1979
+ encodeBytes(checkpoint),
1980
+ encodeBytes(metadata),
1981
+ parentCheckpointId == null ? "" : encodeString(parentCheckpointId)
1982
+ ].join(" ")
1983
+ );
1984
+ }
1985
+ }
1986
+ }
1987
+ for (const [key, indexedWrites] of Object.entries(saver.writes)) {
1988
+ for (const [index, [taskId, channel, value]] of Object.entries(
1989
+ indexedWrites
1990
+ )) {
1991
+ lines.push(
1992
+ [
1993
+ "W",
1994
+ encodeString(key),
1995
+ encodeString(index),
1996
+ encodeString(taskId),
1997
+ encodeString(channel),
1998
+ encodeBytes(value)
1999
+ ].join(" ")
2000
+ );
2001
+ }
2002
+ }
2003
+ await mkdir2(dirname(path), { recursive: true });
2004
+ const temporaryPath = `${path}.${process.pid}.tmp`;
2005
+ await writeFile2(temporaryPath, `${lines.join("\n")}
2006
+ `, "utf8");
2007
+ await rename(temporaryPath, path);
2008
+ }
2009
+ async function removeMemorySaverSnapshot(path) {
2010
+ await rm(path, { force: true });
2011
+ }
2012
+
1895
2013
  // src/bridge/tool-filtering.ts
1896
2014
  import {
1897
2015
  AIMessage as AIMessage18,
@@ -2008,14 +2126,22 @@ function buildModel({
2008
2126
  } : {}
2009
2127
  });
2010
2128
  }
2011
- function createReasoningMiddleware({
2012
- thinking,
2013
- effort
2014
- }) {
2015
- if (!thinking && !effort) return void 0;
2129
+ function createModelMiddleware() {
2016
2130
  return createMiddleware({
2017
- name: "harnessReasoning",
2131
+ name: "harnessModel",
2018
2132
  wrapModelCall: async (request, handler) => {
2133
+ if (!activeModel && !activeThinking && !activeEffort) {
2134
+ return handler(request);
2135
+ }
2136
+ if (activeModel) {
2137
+ const configuredModel2 = buildModel({
2138
+ rawModel: activeModel,
2139
+ thinking: activeThinking,
2140
+ effort: activeEffort
2141
+ });
2142
+ if (!configuredModel2) throw new Error("Deep Agents model is missing");
2143
+ return handler({ ...request, model: configuredModel2 });
2144
+ }
2019
2145
  let model = request.model;
2020
2146
  if ("_getModelInstance" in model && typeof model._getModelInstance === "function") {
2021
2147
  model = await model._getModelInstance();
@@ -2025,8 +2151,8 @@ function createReasoningMiddleware({
2025
2151
  }
2026
2152
  const configuredModel = buildModel({
2027
2153
  rawModel: model.model,
2028
- thinking,
2029
- effort
2154
+ thinking: activeThinking,
2155
+ effort: activeEffort
2030
2156
  });
2031
2157
  if (!configuredModel) throw new Error("Deep Agents model is missing");
2032
2158
  return handler({ ...request, model: configuredModel });
@@ -2040,13 +2166,26 @@ if (!workdir || !bridgeStateDir) {
2040
2166
  console.error("deepagents bridge: missing --workdir / --bridge-state-dir");
2041
2167
  process.exit(1);
2042
2168
  }
2169
+ var conversationCheckpointPath = `${bridgeStateDir}/conversation.checkpoint`;
2043
2170
  var agent;
2044
2171
  var currentTurn;
2045
2172
  var mcpClient;
2046
2173
  var mcpToolNames = /* @__PURE__ */ new Set();
2047
2174
  var currentResponseFormat;
2048
2175
  var checkpointer = new MemorySaver2();
2176
+ if (args.resume === "true") {
2177
+ await loadMemorySaver({
2178
+ path: conversationCheckpointPath,
2179
+ saver: checkpointer
2180
+ });
2181
+ } else {
2182
+ await removeMemorySaverSnapshot(conversationCheckpointPath);
2183
+ }
2049
2184
  var agentConfigurationSignature;
2185
+ var activeModel;
2186
+ var activeThinking;
2187
+ var activeEffort;
2188
+ var modelMiddleware = createModelMiddleware();
2050
2189
  var responseFormatMiddleware = createMiddleware({
2051
2190
  name: "HarnessResponseFormat",
2052
2191
  wrapModelCall(request, handler) {
@@ -2083,6 +2222,9 @@ function buildHostTools(toolSchemas) {
2083
2222
  }
2084
2223
  async function runTurn(start, turn) {
2085
2224
  currentTurn = turn;
2225
+ if (start.model) activeModel = start.model;
2226
+ activeThinking = start.thinking;
2227
+ activeEffort = start.effort;
2086
2228
  currentResponseFormat = start.responseFormat?.type === "json" && start.responseFormat.schema != null ? toolStrategy(start.responseFormat.schema) : void 0;
2087
2229
  const emit = (event) => turn.emit(event);
2088
2230
  const interruptOn = buildInterruptOn(
@@ -2108,15 +2250,6 @@ async function runTurn(start, turn) {
2108
2250
  });
2109
2251
  }
2110
2252
  await closeMcpClient();
2111
- const model = buildModel({
2112
- rawModel: start.model,
2113
- thinking: start.thinking,
2114
- effort: start.effort
2115
- });
2116
- const reasoningMiddleware = model ? void 0 : createReasoningMiddleware({
2117
- thinking: start.thinking,
2118
- effort: start.effort
2119
- });
2120
2253
  const builtinToolFilteringMiddleware = createBuiltinToolFilteringMiddleware(
2121
2254
  {
2122
2255
  builtinToolFiltering: start.builtinToolFiltering,
@@ -2129,7 +2262,7 @@ async function runTurn(start, turn) {
2129
2262
  );
2130
2263
  const middleware = [
2131
2264
  responseFormatMiddleware,
2132
- ...reasoningMiddleware ? [reasoningMiddleware] : [],
2265
+ modelMiddleware,
2133
2266
  ...builtinToolFilteringMiddleware ? [builtinToolFilteringMiddleware] : []
2134
2267
  ];
2135
2268
  const hostTools = buildHostTools(start.tools);
@@ -2142,8 +2275,6 @@ async function runTurn(start, turn) {
2142
2275
  );
2143
2276
  mcpToolNames = new Set(mcpTools.map((mcpTool) => mcpTool.name));
2144
2277
  agent = createDeepAgent({
2145
- // Defer to Deep Agents's own default when the host configured no model.
2146
- ...model ? { model } : {},
2147
2278
  tools: [...mcpTools, ...hostTools],
2148
2279
  backend: createLocalShellBackend({ rootDir: workdir }),
2149
2280
  systemPrompt: start.instructions ? { suffix: start.instructions } : void 0,
@@ -2165,7 +2296,7 @@ async function runTurn(start, turn) {
2165
2296
  const streamEventState = createDeepAgentsStreamEventState();
2166
2297
  const emitStreamEvent = createEmitStreamEvent({
2167
2298
  state: streamEventState,
2168
- configuredModel: start.model,
2299
+ configuredModel: activeModel,
2169
2300
  hostToolNames,
2170
2301
  mcpToolNames,
2171
2302
  structuredOutputToolNames: new Set(
@@ -2268,9 +2399,16 @@ await runBridge({
2268
2399
  onStart: runTurn,
2269
2400
  onStop: async () => {
2270
2401
  await closeMcpClient();
2402
+ await saveMemorySaver({
2403
+ path: conversationCheckpointPath,
2404
+ saver: checkpointer
2405
+ });
2271
2406
  return {};
2272
2407
  },
2273
- onDestroy: closeMcpClient
2408
+ onDestroy: async () => {
2409
+ await closeMcpClient();
2410
+ await removeMemorySaverSnapshot(conversationCheckpointPath);
2411
+ }
2274
2412
  });
2275
2413
  async function loadMcpTools({
2276
2414
  mcpServers