@ai-sdk/harness-codex 1.0.152 → 1.0.154

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.
@@ -17,6 +17,8 @@ export type CodexStepTracker = {
17
17
  itemId: string | undefined;
18
18
  }): void;
19
19
  finishTurn(): void;
20
+ awaitHostInput(input: { itemId: string }): void;
21
+ resolveHostInput(input: { itemId: string }): void;
20
22
  };
21
23
 
22
24
  export function createCodexStepTracker(input: {
@@ -24,6 +26,14 @@ export function createCodexStepTracker(input: {
24
26
  }): CodexStepTracker {
25
27
  let stepOpen = false;
26
28
  const pendingToolItemIds = new Set<string>();
29
+ /*
30
+ * Dynamic tool calls waiting for the host to return their result. When
31
+ * every pending tool item waits on the host, Codex cannot make progress, so
32
+ * the tracker emits an early `finish-step` that lets the host pause the
33
+ * turn. The step stays open until the regular `finish-step`.
34
+ */
35
+ const hostInputWaitingItemIds = new Set<string>();
36
+ const earlyFinishStepItemIds = new Set<string>();
27
37
 
28
38
  const finishStep = (): void => {
29
39
  if (!stepOpen || pendingToolItemIds.size > 0) return;
@@ -34,6 +44,25 @@ export function createCodexStepTracker(input: {
34
44
  harnessMetadata: { codex: { inferredStep: true } },
35
45
  });
36
46
  stepOpen = false;
47
+ earlyFinishStepItemIds.clear();
48
+ };
49
+
50
+ const emitEarlyFinishStepIfReady = (): void => {
51
+ if (!stepOpen || pendingToolItemIds.size === 0) return;
52
+ for (const itemId of pendingToolItemIds) {
53
+ if (!hostInputWaitingItemIds.has(itemId)) return;
54
+ }
55
+ const uncovered = [...pendingToolItemIds].filter(
56
+ itemId => !earlyFinishStepItemIds.has(itemId),
57
+ );
58
+ if (uncovered.length === 0) return;
59
+ for (const itemId of uncovered) earlyFinishStepItemIds.add(itemId);
60
+ input.send({
61
+ type: 'finish-step',
62
+ finishReason: { unified: 'tool-calls', raw: 'host-input' },
63
+ usage: defaultUsage(),
64
+ harnessMetadata: { codex: { inferredStep: true } },
65
+ });
37
66
  };
38
67
 
39
68
  return {
@@ -46,6 +75,7 @@ export function createCodexStepTracker(input: {
46
75
  if (isToolStepItem(item)) {
47
76
  if (event.type === 'item.started' && itemId) {
48
77
  pendingToolItemIds.add(itemId);
78
+ emitEarlyFinishStepIfReady();
49
79
  } else if (event.type === 'item.completed') {
50
80
  if (itemId) pendingToolItemIds.delete(itemId);
51
81
  finishStep();
@@ -54,8 +84,18 @@ export function createCodexStepTracker(input: {
54
84
  },
55
85
  finishTurn() {
56
86
  pendingToolItemIds.clear();
87
+ hostInputWaitingItemIds.clear();
57
88
  finishStep();
58
89
  },
90
+ awaitHostInput({ itemId }) {
91
+ stepOpen = true;
92
+ pendingToolItemIds.add(itemId);
93
+ hostInputWaitingItemIds.add(itemId);
94
+ emitEarlyFinishStepIfReady();
95
+ },
96
+ resolveHostInput({ itemId }) {
97
+ hostInputWaitingItemIds.delete(itemId);
98
+ },
59
99
  };
60
100
  }
61
101
 
@@ -958,6 +958,7 @@ function createSession({
958
958
  toolCallId: input.toolCallId,
959
959
  output: input.output,
960
960
  isError: input.isError,
961
+ ...(input.toolResult != null ? { toolResult: input.toolResult } : {}),
961
962
  });
962
963
  },
963
964
  submitToolApproval: async input => {