@ai-sdk/harness-deepagents 1.0.77 → 1.0.79

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,21 @@
1
1
  # @ai-sdk/harness-deepagents
2
2
 
3
+ ## 1.0.79
4
+
5
+ ### Patch Changes
6
+
7
+ - @ai-sdk/harness@1.0.79
8
+
9
+ ## 1.0.78
10
+
11
+ ### Patch Changes
12
+
13
+ - eace6fb: feat(harness): add experimental support for steering agent conversations mid-turn
14
+ - c0595b4: feat(harness): support passing a filesystem and process restricted sandbox session to `HarnessAgentSession`, using fallbacks in favor of the preferred network sandbox session methods
15
+ - Updated dependencies [eace6fb]
16
+ - Updated dependencies [c0595b4]
17
+ - @ai-sdk/harness@1.0.78
18
+
3
19
  ## 1.0.77
4
20
 
5
21
  ### Patch Changes
@@ -1,10 +1,11 @@
1
1
  // src/bridge/index.ts
2
- import { randomUUID as randomUUID2 } from "crypto";
2
+ import { randomUUID as randomUUID3 } from "crypto";
3
3
  import { argv, env as procEnv2 } from "process";
4
4
 
5
5
  // ../harness/dist/bridge/index.js
6
6
  import { appendFile, mkdir, writeFile } from "fs/promises";
7
7
  import { existsSync, readFileSync } from "fs";
8
+ import { randomUUID } from "crypto";
8
9
  import { env as procEnv, pid, stdout } from "process";
9
10
  import { WebSocketServer } from "ws";
10
11
  var DEBUG_LEVEL_WEIGHT = {
@@ -35,6 +36,106 @@ function formatBridgeError(err) {
35
36
  }
36
37
  return { message: String(err) };
37
38
  }
39
+ function createBridgeUserMessageQueue(options) {
40
+ const messages = [];
41
+ const waiters = [];
42
+ const entries = /* @__PURE__ */ new Map();
43
+ let closed = false;
44
+ let pendingCount = 0;
45
+ const enqueue = (input) => {
46
+ const existing = entries.get(input.messageId);
47
+ if (existing != null) {
48
+ if (existing.response != null) {
49
+ options.respond(existing.response);
50
+ }
51
+ return;
52
+ }
53
+ let settled = false;
54
+ const settle = (response) => {
55
+ if (settled) return;
56
+ settled = true;
57
+ pendingCount--;
58
+ const entry = entries.get(input.messageId);
59
+ if (entry != null) entry.response = response;
60
+ options.respond(response);
61
+ };
62
+ const message = {
63
+ messageId: input.messageId,
64
+ text: input.text,
65
+ accept: () => {
66
+ settle({
67
+ type: "user-message-response",
68
+ messageId: input.messageId,
69
+ accepted: true
70
+ });
71
+ },
72
+ reject: (error) => {
73
+ settle({
74
+ type: "user-message-response",
75
+ messageId: input.messageId,
76
+ accepted: false,
77
+ error: { message: formatBridgeError(error).message }
78
+ });
79
+ }
80
+ };
81
+ entries.set(input.messageId, {
82
+ reject: message.reject
83
+ });
84
+ pendingCount++;
85
+ if (closed) {
86
+ message.reject(
87
+ new Error("The bridge turn is no longer accepting user messages.")
88
+ );
89
+ return;
90
+ }
91
+ const waiter = waiters.shift();
92
+ if (waiter != null) {
93
+ waiter({ done: false, value: message });
94
+ } else {
95
+ messages.push(message);
96
+ }
97
+ };
98
+ const close = (error) => {
99
+ if (closed) return;
100
+ closed = true;
101
+ const reason = error ?? new Error("The bridge turn ended before accepting the user message.");
102
+ for (const entry of entries.values()) {
103
+ if (entry.response == null) entry.reject(reason);
104
+ }
105
+ messages.length = 0;
106
+ while (waiters.length > 0) {
107
+ waiters.shift()({ done: true, value: void 0 });
108
+ }
109
+ };
110
+ return {
111
+ get pendingCount() {
112
+ return pendingCount;
113
+ },
114
+ enqueue,
115
+ close,
116
+ [Symbol.asyncIterator]() {
117
+ return {
118
+ next: () => {
119
+ const message = messages.shift();
120
+ if (message != null) {
121
+ return Promise.resolve({ done: false, value: message });
122
+ }
123
+ if (closed) {
124
+ return Promise.resolve({
125
+ done: true,
126
+ value: void 0
127
+ });
128
+ }
129
+ return new Promise(
130
+ (resolve) => {
131
+ waiters.push(resolve);
132
+ }
133
+ );
134
+ }
135
+ };
136
+ }
137
+ };
138
+ }
38
139
  function parseEnvList(value) {
39
140
  if (!value) return void 0;
40
141
  const items = value.split(",").map((item) => item.trim()).filter(Boolean);
@@ -251,6 +352,9 @@ async function runBridge(options) {
251
352
  switch (msg.type) {
252
353
  case "start": {
253
354
  activeSocket = ws;
355
+ currentUserMessages?.close(
356
+ new Error("A new bridge turn replaced the active turn.")
357
+ );
254
358
  const firstTurn = isFirstTurn;
255
359
  isFirstTurn = false;
256
360
  eventLog = [];
@@ -270,6 +374,7 @@ async function runBridge(options) {
270
374
  if (debugConfig.enabled) {
271
375
  installConsoleCapture();
272
376
  }
377
+ const userMessages = createBridgeUserMessageQueue({ respond: emit });
273
378
  const turn = {
274
379
  emit,
275
380
  requestToolResult: (toolCallId) => new Promise((resolve) => {
@@ -278,7 +383,7 @@ async function runBridge(options) {
278
383
  requestToolApproval: (approvalId) => new Promise((resolve) => {
279
384
  pendingToolApprovals.set(approvalId, resolve);
280
385
  }),
281
- pendingUserMessages: [],
386
+ experimental_userMessages: userMessages,
282
387
  abortSignal: turnAbort.signal,
283
388
  firstTurn,
284
389
  bridgeLog: (input) => {
@@ -296,12 +401,16 @@ async function runBridge(options) {
296
401
  emitWarning,
297
402
  emitError
298
403
  };
299
- currentUserMessages = turn.pendingUserMessages;
404
+ currentUserMessages = userMessages;
300
405
  try {
301
406
  await onStart(msg, turn);
302
407
  } catch (err) {
303
408
  emitError({ error: err, message: "bridge turn failed" });
304
409
  } finally {
410
+ userMessages.close();
411
+ if (currentUserMessages === userMessages) {
412
+ currentUserMessages = void 0;
413
+ }
305
414
  currentTurnState = "waiting";
306
415
  void writeBridgeMeta("waiting");
307
416
  }
@@ -323,9 +432,34 @@ async function runBridge(options) {
323
432
  }
324
433
  return;
325
434
  }
326
- case "user-message":
327
- currentUserMessages?.push(msg.text);
435
+ case "user-message": {
436
+ const messageId = msg.messageId ?? randomUUID();
437
+ if (currentUserMessages == null) {
438
+ sendControl(ws, {
439
+ type: "user-message-response",
440
+ messageId,
441
+ accepted: false,
442
+ error: { message: "The bridge has no active turn to steer." }
443
+ });
444
+ return;
445
+ }
446
+ if (ws !== activeSocket) {
447
+ sendControl(ws, {
448
+ type: "user-message-response",
449
+ messageId,
450
+ accepted: false,
451
+ error: {
452
+ message: "The connection does not own the active bridge turn."
453
+ }
454
+ });
455
+ return;
456
+ }
457
+ currentUserMessages.enqueue({
458
+ messageId,
459
+ text: msg.text
460
+ });
328
461
  return;
462
+ }
329
463
  case "abort":
330
464
  turnAbort?.abort();
331
465
  return;
@@ -399,7 +533,8 @@ async function runBridge(options) {
399
533
  sendControl(ws, {
400
534
  type: "bridge-hello",
401
535
  state: currentTurnState,
402
- lastSeq: seqCounter
536
+ lastSeq: seqCounter,
537
+ capabilities: { experimental_userMessageResponses: true }
403
538
  });
404
539
  ws.on("message", (raw) => {
405
540
  let parsed;
@@ -1423,7 +1558,7 @@ function collectActionRequests(interrupts) {
1423
1558
  }
1424
1559
 
1425
1560
  // src/bridge/create-emit-stream-event.ts
1426
- import { randomUUID } from "crypto";
1561
+ import { randomUUID as randomUUID2 } from "crypto";
1427
1562
  function createDeepAgentsStreamEventState() {
1428
1563
  return {
1429
1564
  streamStarted: false,
@@ -1607,7 +1742,7 @@ function ensureTextBlock({
1607
1742
  emit
1608
1743
  }) {
1609
1744
  if (!state.textBlockId) {
1610
- state.textBlockId = `text-${randomUUID()}`;
1745
+ state.textBlockId = `text-${randomUUID2()}`;
1611
1746
  emit({ type: "text-start", id: state.textBlockId });
1612
1747
  }
1613
1748
  return state.textBlockId;
@@ -1627,7 +1762,7 @@ function emitReasoning({
1627
1762
  }) {
1628
1763
  endTextBlock({ state, emit });
1629
1764
  if (!state.reasoningBlockId) {
1630
- state.reasoningBlockId = `reasoning-${randomUUID()}`;
1765
+ state.reasoningBlockId = `reasoning-${randomUUID2()}`;
1631
1766
  emit({ type: "reasoning-start", id: state.reasoningBlockId });
1632
1767
  }
1633
1768
  emit({ type: "reasoning-delta", id: state.reasoningBlockId, delta });
@@ -1883,7 +2018,7 @@ function buildHostTools(toolSchemas) {
1883
2018
  async (input) => {
1884
2019
  const turn = currentTurn;
1885
2020
  if (!turn) throw new Error("no active turn");
1886
- const toolCallId = `${schema.name}-${randomUUID2()}`;
2021
+ const toolCallId = `${schema.name}-${randomUUID3()}`;
1887
2022
  turn.emit({
1888
2023
  type: "tool-call",
1889
2024
  toolCallId,
@@ -2001,7 +2136,7 @@ async function runTurn(start, turn) {
2001
2136
  const namespace = streamEvent.metadata?.langgraph_checkpoint_ns ?? "";
2002
2137
  const output = streamEvent.data?.output;
2003
2138
  if (!emittedStructuredOutput && streamEvent.event === "on_chain_end" && !namespace.includes("|") && output?.structuredResponse !== void 0) {
2004
- const id = `structured-output-${randomUUID2()}`;
2139
+ const id = `structured-output-${randomUUID3()}`;
2005
2140
  emit({ type: "text-start", id });
2006
2141
  emit({
2007
2142
  type: "text-delta",
@@ -2016,7 +2151,7 @@ async function runTurn(start, turn) {
2016
2151
  if (actionRequests.length === 0) break;
2017
2152
  const decisions = [];
2018
2153
  for (const action of actionRequests) {
2019
- const approvalId = `approval-${randomUUID2()}`;
2154
+ const approvalId = `approval-${randomUUID3()}`;
2020
2155
  endTextBlock({ state: streamEventState, emit });
2021
2156
  endReasoningBlock({ state: streamEventState, emit });
2022
2157
  emit({