@openai/agents-core 0.3.7 → 0.3.9
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/dist/errors.d.ts +40 -0
- package/dist/errors.js +39 -1
- package/dist/errors.js.map +1 -1
- package/dist/errors.mjs +35 -0
- package/dist/errors.mjs.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/index.mjs.map +1 -1
- package/dist/metadata.js +2 -2
- package/dist/metadata.mjs +2 -2
- package/dist/result.d.ts +17 -0
- package/dist/result.js +71 -24
- package/dist/result.js.map +1 -1
- package/dist/result.mjs +69 -22
- package/dist/result.mjs.map +1 -1
- package/dist/run.d.ts +14 -47
- package/dist/run.js +421 -994
- package/dist/run.js.map +1 -1
- package/dist/run.mjs +405 -978
- package/dist/run.mjs.map +1 -1
- package/dist/runState.d.ts +1286 -172
- package/dist/runState.js +146 -16
- package/dist/runState.js.map +1 -1
- package/dist/runState.mjs +142 -12
- package/dist/runState.mjs.map +1 -1
- package/dist/runner/constants.d.ts +1 -0
- package/dist/runner/constants.js +6 -0
- package/dist/runner/constants.js.map +1 -0
- package/dist/runner/constants.mjs +3 -0
- package/dist/runner/constants.mjs.map +1 -0
- package/dist/runner/conversation.d.ts +85 -0
- package/dist/runner/conversation.js +275 -0
- package/dist/runner/conversation.js.map +1 -0
- package/dist/runner/conversation.mjs +269 -0
- package/dist/runner/conversation.mjs.map +1 -0
- package/dist/runner/guardrails.d.ts +23 -0
- package/dist/runner/guardrails.js +174 -0
- package/dist/runner/guardrails.js.map +1 -0
- package/dist/runner/guardrails.mjs +166 -0
- package/dist/runner/guardrails.mjs.map +1 -0
- package/dist/runner/items.d.ts +18 -0
- package/dist/runner/items.js +89 -0
- package/dist/runner/items.js.map +1 -0
- package/dist/runner/items.mjs +79 -0
- package/dist/runner/items.mjs.map +1 -0
- package/dist/runner/mcpApprovals.d.ts +25 -0
- package/dist/runner/mcpApprovals.js +66 -0
- package/dist/runner/mcpApprovals.js.map +1 -0
- package/dist/runner/mcpApprovals.mjs +63 -0
- package/dist/runner/mcpApprovals.mjs.map +1 -0
- package/dist/runner/modelOutputs.d.ts +10 -0
- package/dist/runner/modelOutputs.js +206 -0
- package/dist/runner/modelOutputs.js.map +1 -0
- package/dist/runner/modelOutputs.mjs +203 -0
- package/dist/runner/modelOutputs.mjs.map +1 -0
- package/dist/runner/modelPreparation.d.ts +8 -0
- package/dist/runner/modelPreparation.js +41 -0
- package/dist/runner/modelPreparation.js.map +1 -0
- package/dist/runner/modelPreparation.mjs +38 -0
- package/dist/runner/modelPreparation.mjs.map +1 -0
- package/dist/runner/modelSettings.d.ts +20 -0
- package/dist/runner/modelSettings.js +97 -0
- package/dist/runner/modelSettings.js.map +1 -0
- package/dist/runner/modelSettings.mjs +92 -0
- package/dist/runner/modelSettings.mjs.map +1 -0
- package/dist/runner/runLoop.d.ts +32 -0
- package/dist/runner/runLoop.js +62 -0
- package/dist/runner/runLoop.js.map +1 -0
- package/dist/runner/runLoop.mjs +57 -0
- package/dist/runner/runLoop.mjs.map +1 -0
- package/dist/runner/sessionPersistence.d.ts +26 -0
- package/dist/runner/sessionPersistence.js +441 -0
- package/dist/runner/sessionPersistence.js.map +1 -0
- package/dist/runner/sessionPersistence.mjs +431 -0
- package/dist/runner/sessionPersistence.mjs.map +1 -0
- package/dist/runner/steps.d.ts +48 -0
- package/dist/runner/steps.js +40 -0
- package/dist/runner/steps.js.map +1 -0
- package/dist/runner/steps.mjs +36 -0
- package/dist/runner/steps.mjs.map +1 -0
- package/dist/runner/streaming.d.ts +9 -0
- package/dist/runner/streaming.js +74 -0
- package/dist/runner/streaming.js.map +1 -0
- package/dist/runner/streaming.mjs +65 -0
- package/dist/runner/streaming.mjs.map +1 -0
- package/dist/runner/toolExecution.d.ts +15 -0
- package/dist/runner/toolExecution.js +997 -0
- package/dist/runner/toolExecution.js.map +1 -0
- package/dist/runner/toolExecution.mjs +984 -0
- package/dist/runner/toolExecution.mjs.map +1 -0
- package/dist/runner/toolUseTracker.d.ts +9 -0
- package/dist/runner/toolUseTracker.js +34 -0
- package/dist/runner/toolUseTracker.js.map +1 -0
- package/dist/runner/toolUseTracker.mjs +30 -0
- package/dist/runner/toolUseTracker.mjs.map +1 -0
- package/dist/runner/tracing.d.ts +23 -0
- package/dist/runner/tracing.js +45 -0
- package/dist/runner/tracing.js.map +1 -0
- package/dist/runner/tracing.mjs +41 -0
- package/dist/runner/tracing.mjs.map +1 -0
- package/dist/runner/turnPreparation.d.ts +30 -0
- package/dist/runner/turnPreparation.js +80 -0
- package/dist/runner/turnPreparation.js.map +1 -0
- package/dist/runner/turnPreparation.mjs +74 -0
- package/dist/runner/turnPreparation.mjs.map +1 -0
- package/dist/runner/turnResolution.d.ts +3 -0
- package/dist/runner/turnResolution.js +531 -0
- package/dist/runner/turnResolution.js.map +1 -0
- package/dist/runner/turnResolution.mjs +526 -0
- package/dist/runner/turnResolution.mjs.map +1 -0
- package/dist/runner/types.d.ts +66 -0
- package/dist/runner/types.js +3 -0
- package/dist/runner/types.js.map +1 -0
- package/dist/runner/types.mjs +2 -0
- package/dist/runner/types.mjs.map +1 -0
- package/dist/shims/mcp-server/node.js +51 -6
- package/dist/shims/mcp-server/node.js.map +1 -1
- package/dist/shims/mcp-server/node.mjs +51 -6
- package/dist/shims/mcp-server/node.mjs.map +1 -1
- package/dist/tool.d.ts +28 -2
- package/dist/tool.js +7 -1
- package/dist/tool.js.map +1 -1
- package/dist/tool.mjs +8 -2
- package/dist/tool.mjs.map +1 -1
- package/dist/toolGuardrail.d.ts +101 -0
- package/dist/toolGuardrail.js +58 -0
- package/dist/toolGuardrail.js.map +1 -0
- package/dist/toolGuardrail.mjs +51 -0
- package/dist/toolGuardrail.mjs.map +1 -0
- package/dist/tracing/config.d.ts +3 -0
- package/dist/tracing/config.js +3 -0
- package/dist/tracing/config.js.map +1 -0
- package/dist/tracing/config.mjs +2 -0
- package/dist/tracing/config.mjs.map +1 -0
- package/dist/tracing/context.d.ts +2 -0
- package/dist/tracing/context.js +95 -24
- package/dist/tracing/context.js.map +1 -1
- package/dist/tracing/context.mjs +95 -24
- package/dist/tracing/context.mjs.map +1 -1
- package/dist/tracing/createSpans.d.ts +11 -11
- package/dist/tracing/index.d.ts +2 -0
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/index.mjs.map +1 -1
- package/dist/tracing/provider.js +54 -4
- package/dist/tracing/provider.js.map +1 -1
- package/dist/tracing/provider.mjs +54 -4
- package/dist/tracing/provider.mjs.map +1 -1
- package/dist/tracing/spans.d.ts +2 -0
- package/dist/tracing/spans.js +6 -0
- package/dist/tracing/spans.js.map +1 -1
- package/dist/tracing/spans.mjs +6 -0
- package/dist/tracing/spans.mjs.map +1 -1
- package/dist/tracing/traces.d.ts +11 -1
- package/dist/tracing/traces.js +15 -2
- package/dist/tracing/traces.js.map +1 -1
- package/dist/tracing/traces.mjs +15 -2
- package/dist/tracing/traces.mjs.map +1 -1
- package/dist/types/protocol.d.ts +11 -0
- package/dist/types/protocol.js +1 -0
- package/dist/types/protocol.js.map +1 -1
- package/dist/types/protocol.mjs +1 -0
- package/dist/types/protocol.mjs.map +1 -1
- package/dist/utils/binary.d.ts +6 -0
- package/dist/utils/binary.js +53 -0
- package/dist/utils/binary.js.map +1 -0
- package/dist/utils/binary.mjs +49 -0
- package/dist/utils/binary.mjs.map +1 -0
- package/dist/utils/toolGuardrails.d.ts +24 -0
- package/dist/utils/toolGuardrails.js +58 -0
- package/dist/utils/toolGuardrails.js.map +1 -0
- package/dist/utils/toolGuardrails.mjs +54 -0
- package/dist/utils/toolGuardrails.mjs.map +1 -0
- package/package.json +4 -3
- package/dist/runImplementation.d.ts +0 -161
- package/dist/runImplementation.js +0 -2054
- package/dist/runImplementation.js.map +0 -1
- package/dist/runImplementation.mjs +0 -2028
- package/dist/runImplementation.mjs.map +0 -1
package/dist/run.js
CHANGED
|
@@ -3,32 +3,40 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.Runner = void 0;
|
|
6
|
+
exports.Runner = exports.getTurnInput = exports.selectModel = exports.getTracing = void 0;
|
|
7
7
|
exports.run = run;
|
|
8
|
-
exports.getTurnInput = getTurnInput;
|
|
9
|
-
exports.selectModel = selectModel;
|
|
10
|
-
exports.getTracing = getTracing;
|
|
11
8
|
const agent_1 = require("./agent.js");
|
|
9
|
+
const events_1 = require("./events.js");
|
|
10
|
+
const errors_1 = require("./errors.js");
|
|
12
11
|
const guardrail_1 = require("./guardrail.js");
|
|
12
|
+
const lifecycle_1 = require("./lifecycle.js");
|
|
13
|
+
const logger_1 = __importDefault(require("./logger.js"));
|
|
13
14
|
const providers_1 = require("./providers.js");
|
|
14
15
|
const runContext_1 = require("./runContext.js");
|
|
15
16
|
const result_1 = require("./result.js");
|
|
16
|
-
const
|
|
17
|
-
const logger_1 = __importDefault(require("./logger.js"));
|
|
18
|
-
const serialize_1 = require("./utils/serialize.js");
|
|
19
|
-
const errors_1 = require("./errors.js");
|
|
20
|
-
const runImplementation_1 = require("./runImplementation.js");
|
|
17
|
+
const runState_1 = require("./runState.js");
|
|
21
18
|
const tool_1 = require("./tool.js");
|
|
22
19
|
const context_1 = require("./tracing/context.js");
|
|
23
|
-
const tracing_1 = require("./tracing/index.js");
|
|
24
20
|
const usage_1 = require("./usage.js");
|
|
25
|
-
const events_1 = require("./events.js");
|
|
26
|
-
const runState_1 = require("./runState.js");
|
|
27
|
-
const protocol_1 = require("./types/protocol.js");
|
|
28
21
|
const tools_1 = require("./utils/tools.js");
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
22
|
+
const constants_1 = require("./runner/constants.js");
|
|
23
|
+
const protocol_1 = require("./types/protocol.js");
|
|
24
|
+
const conversation_1 = require("./runner/conversation.js");
|
|
25
|
+
const guardrails_1 = require("./runner/guardrails.js");
|
|
26
|
+
const modelSettings_1 = require("./runner/modelSettings.js");
|
|
27
|
+
const modelOutputs_1 = require("./runner/modelOutputs.js");
|
|
28
|
+
const streaming_1 = require("./runner/streaming.js");
|
|
29
|
+
const sessionPersistence_1 = require("./runner/sessionPersistence.js");
|
|
30
|
+
const turnResolution_1 = require("./runner/turnResolution.js");
|
|
31
|
+
const turnPreparation_1 = require("./runner/turnPreparation.js");
|
|
32
|
+
const runLoop_1 = require("./runner/runLoop.js");
|
|
33
|
+
const tracing_1 = require("./runner/tracing.js");
|
|
34
|
+
var tracing_2 = require("./runner/tracing.js");
|
|
35
|
+
Object.defineProperty(exports, "getTracing", { enumerable: true, get: function () { return tracing_2.getTracing; } });
|
|
36
|
+
var modelSettings_2 = require("./runner/modelSettings.js");
|
|
37
|
+
Object.defineProperty(exports, "selectModel", { enumerable: true, get: function () { return modelSettings_2.selectModel; } });
|
|
38
|
+
var items_1 = require("./runner/items.js");
|
|
39
|
+
Object.defineProperty(exports, "getTurnInput", { enumerable: true, get: function () { return items_1.getTurnInput; } });
|
|
32
40
|
async function run(agent, input, options) {
|
|
33
41
|
const runner = getDefaultRunner();
|
|
34
42
|
if (options?.stream) {
|
|
@@ -64,6 +72,7 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
64
72
|
traceId: config.traceId,
|
|
65
73
|
groupId: config.groupId,
|
|
66
74
|
traceMetadata: config.traceMetadata,
|
|
75
|
+
tracing: config.tracing,
|
|
67
76
|
sessionInputCallback: config.sessionInputCallback,
|
|
68
77
|
callModelInputFilter: config.callModelInputFilter,
|
|
69
78
|
};
|
|
@@ -80,148 +89,35 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
80
89
|
// Likewise allow callers to override callModelInputFilter on individual runs.
|
|
81
90
|
const callModelInputFilter = resolvedOptions.callModelInputFilter ?? this.config.callModelInputFilter;
|
|
82
91
|
const hasCallModelInputFilter = Boolean(callModelInputFilter);
|
|
92
|
+
const tracingConfig = resolvedOptions.tracing ?? this.config.tracing;
|
|
83
93
|
const effectiveOptions = {
|
|
84
94
|
...resolvedOptions,
|
|
85
95
|
sessionInputCallback,
|
|
86
96
|
callModelInputFilter,
|
|
87
97
|
};
|
|
88
|
-
const
|
|
89
|
-
|
|
98
|
+
const resumingFromState = input instanceof runState_1.RunState;
|
|
99
|
+
const preserveTurnPersistenceOnResume = resumingFromState &&
|
|
100
|
+
input._currentTurnInProgress === true;
|
|
101
|
+
const resumedConversationId = resumingFromState
|
|
102
|
+
? input._conversationId
|
|
103
|
+
: undefined;
|
|
104
|
+
const resumedPreviousResponseId = resumingFromState
|
|
105
|
+
? input._previousResponseId
|
|
106
|
+
: undefined;
|
|
107
|
+
const serverManagesConversation = Boolean(effectiveOptions.conversationId ?? resumedConversationId) ||
|
|
108
|
+
Boolean(effectiveOptions.previousResponseId ?? resumedPreviousResponseId);
|
|
90
109
|
// When the server tracks conversation history we defer to it for previous turns so local session
|
|
91
110
|
// persistence can focus solely on the new delta being generated in this process.
|
|
92
111
|
const session = effectiveOptions.session;
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// the original objects (so we can respect resume counts) while `filteredItems`, when present,
|
|
100
|
-
// contains the filtered/redacted clones that must be persisted for history.
|
|
101
|
-
// The helper reconciles the filtered copies produced by callModelInputFilter with their original
|
|
102
|
-
// counterparts so resume-from-state bookkeeping stays consistent and duplicate references only
|
|
103
|
-
// consume a single persistence slot.
|
|
104
|
-
const recordSessionItemsForPersistence = (sourceItems, filteredItems) => {
|
|
105
|
-
const pendingWriteCounts = sessionInputPendingWriteCounts;
|
|
106
|
-
if (filteredItems !== undefined) {
|
|
107
|
-
if (!pendingWriteCounts) {
|
|
108
|
-
sessionInputFilteredSnapshot = filteredItems.map((item) => structuredClone(item));
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
const persistableItems = [];
|
|
112
|
-
const sourceOccurrenceCounts = new WeakMap();
|
|
113
|
-
// Track how many times each original object appears so duplicate references only consume one persistence slot.
|
|
114
|
-
for (const source of sourceItems) {
|
|
115
|
-
if (!source || typeof source !== 'object') {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
const nextCount = (sourceOccurrenceCounts.get(source) ?? 0) + 1;
|
|
119
|
-
sourceOccurrenceCounts.set(source, nextCount);
|
|
120
|
-
}
|
|
121
|
-
// Let filtered items without a one-to-one source match claim any remaining persistence count.
|
|
122
|
-
const consumeAnyPendingWriteSlot = () => {
|
|
123
|
-
for (const [key, remaining] of pendingWriteCounts) {
|
|
124
|
-
if (remaining > 0) {
|
|
125
|
-
pendingWriteCounts.set(key, remaining - 1);
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
};
|
|
131
|
-
for (let i = 0; i < filteredItems.length; i++) {
|
|
132
|
-
const filteredItem = filteredItems[i];
|
|
133
|
-
if (!filteredItem) {
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
let allocated = false;
|
|
137
|
-
const source = sourceItems[i];
|
|
138
|
-
if (source && typeof source === 'object') {
|
|
139
|
-
const pendingOccurrences = (sourceOccurrenceCounts.get(source) ?? 0) - 1;
|
|
140
|
-
sourceOccurrenceCounts.set(source, pendingOccurrences);
|
|
141
|
-
if (pendingOccurrences > 0) {
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const sourceKey = getAgentInputItemKey(source);
|
|
145
|
-
const remaining = pendingWriteCounts.get(sourceKey) ?? 0;
|
|
146
|
-
if (remaining > 0) {
|
|
147
|
-
pendingWriteCounts.set(sourceKey, remaining - 1);
|
|
148
|
-
persistableItems.push(structuredClone(filteredItem));
|
|
149
|
-
allocated = true;
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
const filteredKey = getAgentInputItemKey(filteredItem);
|
|
154
|
-
const filteredRemaining = pendingWriteCounts.get(filteredKey) ?? 0;
|
|
155
|
-
if (filteredRemaining > 0) {
|
|
156
|
-
pendingWriteCounts.set(filteredKey, filteredRemaining - 1);
|
|
157
|
-
persistableItems.push(structuredClone(filteredItem));
|
|
158
|
-
allocated = true;
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if (!source && consumeAnyPendingWriteSlot()) {
|
|
162
|
-
persistableItems.push(structuredClone(filteredItem));
|
|
163
|
-
allocated = true;
|
|
164
|
-
}
|
|
165
|
-
if (!allocated &&
|
|
166
|
-
!source &&
|
|
167
|
-
sessionInputFilteredSnapshot === undefined) {
|
|
168
|
-
// Preserve at least one copy so later persistence resolves even when no counters remain.
|
|
169
|
-
persistableItems.push(structuredClone(filteredItem));
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
if (persistableItems.length > 0 ||
|
|
173
|
-
sessionInputFilteredSnapshot === undefined) {
|
|
174
|
-
sessionInputFilteredSnapshot = persistableItems;
|
|
175
|
-
}
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
const filtered = [];
|
|
179
|
-
if (!pendingWriteCounts) {
|
|
180
|
-
for (const item of sourceItems) {
|
|
181
|
-
if (!item) {
|
|
182
|
-
continue;
|
|
183
|
-
}
|
|
184
|
-
filtered.push(structuredClone(item));
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
for (const item of sourceItems) {
|
|
189
|
-
if (!item) {
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
const key = getAgentInputItemKey(item);
|
|
193
|
-
const remaining = pendingWriteCounts.get(key) ?? 0;
|
|
194
|
-
if (remaining <= 0) {
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
pendingWriteCounts.set(key, remaining - 1);
|
|
198
|
-
filtered.push(structuredClone(item));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (filtered.length > 0) {
|
|
202
|
-
sessionInputFilteredSnapshot = filtered;
|
|
203
|
-
}
|
|
204
|
-
else if (sessionInputFilteredSnapshot === undefined) {
|
|
205
|
-
sessionInputFilteredSnapshot = [];
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
// Determine which items should be committed to session memory for this turn.
|
|
209
|
-
// Filters take precedence because they reflect the exact payload delivered to the model.
|
|
210
|
-
const resolveSessionItemsForPersistence = () => {
|
|
211
|
-
if (sessionInputFilteredSnapshot !== undefined) {
|
|
212
|
-
return sessionInputFilteredSnapshot;
|
|
213
|
-
}
|
|
214
|
-
if (hasCallModelInputFilter) {
|
|
215
|
-
return undefined;
|
|
216
|
-
}
|
|
217
|
-
return sessionInputOriginalSnapshot;
|
|
218
|
-
};
|
|
112
|
+
const sessionPersistence = (0, sessionPersistence_1.createSessionPersistenceTracker)({
|
|
113
|
+
session,
|
|
114
|
+
hasCallModelInputFilter,
|
|
115
|
+
persistInput: sessionPersistence_1.saveStreamInputToSession,
|
|
116
|
+
resumingFromState,
|
|
117
|
+
});
|
|
219
118
|
let preparedInput = input;
|
|
220
119
|
if (!(preparedInput instanceof runState_1.RunState)) {
|
|
221
|
-
|
|
222
|
-
throw new errors_1.UserError('RunConfig.sessionInputCallback must be provided when using session history with list inputs.');
|
|
223
|
-
}
|
|
224
|
-
const prepared = await (0, runImplementation_1.prepareInputItemsWithSession)(preparedInput, session, sessionInputCallback, {
|
|
120
|
+
const prepared = await (0, sessionPersistence_1.prepareInputItemsWithSession)(preparedInput, session, sessionInputCallback, {
|
|
225
121
|
// When the server tracks conversation state we only send the new turn inputs;
|
|
226
122
|
// previous messages are recovered via conversationId/previousResponseId.
|
|
227
123
|
includeHistoryInPreparedInput: !serverManagesConversation,
|
|
@@ -241,48 +137,21 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
241
137
|
else {
|
|
242
138
|
preparedInput = prepared.preparedInput;
|
|
243
139
|
}
|
|
244
|
-
|
|
245
|
-
const items = prepared.sessionItems ?? [];
|
|
246
|
-
// Clone the items that will be persisted so later mutations (filters, hooks) cannot desync history.
|
|
247
|
-
sessionInputOriginalSnapshot = items.map((item) => structuredClone(item));
|
|
248
|
-
// Reset pending counts so each prepared item reserves exactly one write slot until filters resolve matches.
|
|
249
|
-
sessionInputPendingWriteCounts = new Map();
|
|
250
|
-
for (const item of items) {
|
|
251
|
-
const key = getAgentInputItemKey(item);
|
|
252
|
-
sessionInputPendingWriteCounts.set(key, (sessionInputPendingWriteCounts.get(key) ?? 0) + 1);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
140
|
+
sessionPersistence?.setPreparedItems(prepared.sessionItems);
|
|
255
141
|
}
|
|
256
142
|
// Streaming runs persist the input asynchronously, so track a one-shot helper
|
|
257
143
|
// that can be awaited from multiple branches without double-writing.
|
|
258
|
-
|
|
259
|
-
// Sessions remain usable alongside server-managed conversations (e.g., OpenAIConversationsSession)
|
|
260
|
-
// so callers can reuse callbacks, resume-from-state logic, and other helpers without duplicating
|
|
261
|
-
// remote history, so persistence is gated on serverManagesConversation.
|
|
262
|
-
if (session && !serverManagesConversation) {
|
|
263
|
-
let persisted = false;
|
|
264
|
-
ensureStreamInputPersisted = async () => {
|
|
265
|
-
if (persisted) {
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
const itemsToPersist = resolveSessionItemsForPersistence();
|
|
269
|
-
if (!itemsToPersist || itemsToPersist.length === 0) {
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
persisted = true;
|
|
273
|
-
await (0, runImplementation_1.saveStreamInputToSession)(session, itemsToPersist);
|
|
274
|
-
};
|
|
275
|
-
}
|
|
144
|
+
const ensureStreamInputPersisted = sessionPersistence?.buildPersistInputOnce(serverManagesConversation);
|
|
276
145
|
const executeRun = async () => {
|
|
277
146
|
if (effectiveOptions.stream) {
|
|
278
|
-
const streamResult = await this.#runIndividualStream(agent, preparedInput, effectiveOptions, ensureStreamInputPersisted,
|
|
147
|
+
const streamResult = await this.#runIndividualStream(agent, preparedInput, effectiveOptions, ensureStreamInputPersisted, sessionPersistence?.recordTurnItems, preserveTurnPersistenceOnResume);
|
|
279
148
|
return streamResult;
|
|
280
149
|
}
|
|
281
|
-
const runResult = await this.#runIndividualNonStream(agent, preparedInput, effectiveOptions,
|
|
150
|
+
const runResult = await this.#runIndividualNonStream(agent, preparedInput, effectiveOptions, sessionPersistence?.recordTurnItems, preserveTurnPersistenceOnResume);
|
|
282
151
|
// See note above: allow sessions to run for callbacks/state but skip writes when the server
|
|
283
152
|
// is the source of truth for transcript history.
|
|
284
|
-
if (
|
|
285
|
-
await (0,
|
|
153
|
+
if (sessionPersistence && !serverManagesConversation) {
|
|
154
|
+
await (0, sessionPersistence_1.saveToSession)(session, sessionPersistence.getItemsForPersistence(), runResult);
|
|
286
155
|
}
|
|
287
156
|
return runResult;
|
|
288
157
|
};
|
|
@@ -299,6 +168,8 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
299
168
|
name: this.config.workflowName,
|
|
300
169
|
groupId: this.config.groupId,
|
|
301
170
|
metadata: this.config.traceMetadata,
|
|
171
|
+
// Per-run tracing config overrides exporter defaults such as environment API key.
|
|
172
|
+
tracingApiKey: tracingConfig?.apiKey,
|
|
302
173
|
});
|
|
303
174
|
}
|
|
304
175
|
// --------------------------------------------------------------
|
|
@@ -306,23 +177,6 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
306
177
|
// --------------------------------------------------------------
|
|
307
178
|
inputGuardrailDefs;
|
|
308
179
|
outputGuardrailDefs;
|
|
309
|
-
#getInputGuardrailDefinitions(state) {
|
|
310
|
-
return this.inputGuardrailDefs.concat(state._currentAgent.inputGuardrails.map(guardrail_1.defineInputGuardrail));
|
|
311
|
-
}
|
|
312
|
-
#splitInputGuardrails(state) {
|
|
313
|
-
const guardrails = this.#getInputGuardrailDefinitions(state);
|
|
314
|
-
const blocking = [];
|
|
315
|
-
const parallel = [];
|
|
316
|
-
for (const guardrail of guardrails) {
|
|
317
|
-
if (guardrail.runInParallel === false) {
|
|
318
|
-
blocking.push(guardrail);
|
|
319
|
-
}
|
|
320
|
-
else {
|
|
321
|
-
parallel.push(guardrail);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return { blocking, parallel };
|
|
325
|
-
}
|
|
326
180
|
/**
|
|
327
181
|
* @internal
|
|
328
182
|
* Resolves the effective model once so both run loops obey the same precedence rules.
|
|
@@ -332,11 +186,12 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
332
186
|
agent.model !== agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER) ||
|
|
333
187
|
(this.config.model !== undefined &&
|
|
334
188
|
this.config.model !== agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
189
|
+
const selectedModel = (0, modelSettings_1.selectModel)(agent.model, this.config.model);
|
|
190
|
+
const resolvedModelName = typeof selectedModel === 'string' ? selectedModel : undefined;
|
|
191
|
+
const resolvedModel = typeof selectedModel === 'string'
|
|
192
|
+
? await this.config.modelProvider.getModel(selectedModel)
|
|
193
|
+
: selectedModel;
|
|
194
|
+
return { model: resolvedModel, explictlyModelSet, resolvedModelName };
|
|
340
195
|
}
|
|
341
196
|
/**
|
|
342
197
|
* @internal
|
|
@@ -344,7 +199,7 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
344
199
|
async #runIndividualNonStream(startingAgent, input, options,
|
|
345
200
|
// sessionInputUpdate lets the caller adjust queued session items after filters run so we
|
|
346
201
|
// persist exactly what we send to the model (e.g., after redactions or truncation).
|
|
347
|
-
sessionInputUpdate) {
|
|
202
|
+
sessionInputUpdate, preserveTurnPersistenceOnResume) {
|
|
348
203
|
return (0, context_1.withNewSpanContext)(async () => {
|
|
349
204
|
// if we have a saved state we use that one, otherwise we create a new one
|
|
350
205
|
const isResumedState = input instanceof runState_1.RunState;
|
|
@@ -352,11 +207,18 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
352
207
|
? input
|
|
353
208
|
: new runState_1.RunState(options.context instanceof runContext_1.RunContext
|
|
354
209
|
? options.context
|
|
355
|
-
: new runContext_1.RunContext(options.context), input, startingAgent, options.maxTurns ?? DEFAULT_MAX_TURNS);
|
|
356
|
-
const
|
|
357
|
-
?
|
|
358
|
-
|
|
359
|
-
|
|
210
|
+
: new runContext_1.RunContext(options.context), input, startingAgent, options.maxTurns ?? constants_1.DEFAULT_MAX_TURNS);
|
|
211
|
+
const resolvedConversationId = options.conversationId ??
|
|
212
|
+
(isResumedState ? state._conversationId : undefined);
|
|
213
|
+
const resolvedPreviousResponseId = options.previousResponseId ??
|
|
214
|
+
(isResumedState ? state._previousResponseId : undefined);
|
|
215
|
+
if (!isResumedState) {
|
|
216
|
+
state.setConversationContext(resolvedConversationId, resolvedPreviousResponseId);
|
|
217
|
+
}
|
|
218
|
+
const serverConversationTracker = resolvedConversationId || resolvedPreviousResponseId
|
|
219
|
+
? new conversation_1.ServerConversationTracker({
|
|
220
|
+
conversationId: resolvedConversationId,
|
|
221
|
+
previousResponseId: resolvedPreviousResponseId,
|
|
360
222
|
})
|
|
361
223
|
: undefined;
|
|
362
224
|
if (serverConversationTracker && isResumedState) {
|
|
@@ -365,7 +227,9 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
365
227
|
generatedItems: state._generatedItems,
|
|
366
228
|
modelResponses: state._modelResponses,
|
|
367
229
|
});
|
|
230
|
+
state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
|
|
368
231
|
}
|
|
232
|
+
// Tracks when we resume an approval interruption so the next run-again step stays in the same turn.
|
|
369
233
|
let continuingInterruptedTurn = false;
|
|
370
234
|
try {
|
|
371
235
|
while (true) {
|
|
@@ -378,66 +242,60 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
378
242
|
if (!state._lastTurnResponse || !state._lastProcessedResponse) {
|
|
379
243
|
throw new errors_1.UserError('No model response found in previous state', state);
|
|
380
244
|
}
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
245
|
+
const interruptedOutcome = await (0, runLoop_1.resumeInterruptedTurn)({
|
|
246
|
+
state,
|
|
247
|
+
runner: this,
|
|
248
|
+
});
|
|
385
249
|
// Don't reset counter here - resolveInterruptedTurn already adjusted it via rewind logic
|
|
386
250
|
// The counter will be reset when _currentTurn is incremented (starting a new turn)
|
|
387
|
-
|
|
251
|
+
const { shouldReturn, shouldContinue } = (0, runLoop_1.handleInterruptedOutcome)({
|
|
252
|
+
state,
|
|
253
|
+
outcome: interruptedOutcome,
|
|
254
|
+
setContinuingInterruptedTurn: (value) => {
|
|
255
|
+
continuingInterruptedTurn = value;
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
if (shouldReturn) {
|
|
388
259
|
// we are still in an interruption, so we need to avoid an infinite loop
|
|
389
|
-
state._currentStep = turnResult.nextStep;
|
|
390
260
|
return new result_1.RunResult(state);
|
|
391
261
|
}
|
|
392
|
-
|
|
393
|
-
// so the loop treats it as a new step without incrementing the turn.
|
|
394
|
-
// The counter has already been adjusted by resolveInterruptedTurn's rewind logic.
|
|
395
|
-
if (turnResult.nextStep.type === 'next_step_run_again') {
|
|
396
|
-
continuingInterruptedTurn = true;
|
|
397
|
-
state._currentStep = undefined;
|
|
262
|
+
if (shouldContinue) {
|
|
398
263
|
continue;
|
|
399
264
|
}
|
|
400
|
-
continuingInterruptedTurn = false;
|
|
401
|
-
state._currentStep = turnResult.nextStep;
|
|
402
265
|
}
|
|
403
266
|
if (state._currentStep.type === 'next_step_run_again') {
|
|
404
|
-
const
|
|
405
|
-
const isResumingFromInterruption = isResumedState && continuingInterruptedTurn;
|
|
267
|
+
const wasContinuingInterruptedTurn = continuingInterruptedTurn;
|
|
406
268
|
continuingInterruptedTurn = false;
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
state.
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const turnInput = serverConversationTracker
|
|
434
|
-
? serverConversationTracker.prepareInput(state._originalInput, state._generatedItems)
|
|
435
|
-
: getTurnInput(state._originalInput, state._generatedItems);
|
|
436
|
-
if (state._noActiveAgentRun) {
|
|
437
|
-
state._currentAgent.emit('agent_start', state._context, state._currentAgent, turnInput);
|
|
438
|
-
this.emit('agent_start', state._context, state._currentAgent, turnInput);
|
|
269
|
+
const guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
|
|
270
|
+
const previousTurn = state._currentTurn;
|
|
271
|
+
const previousPersistedCount = state._currentTurnPersistedItemCount;
|
|
272
|
+
const previousGeneratedCount = state._generatedItems.length;
|
|
273
|
+
const { artifacts, turnInput, parallelGuardrailPromise } = await (0, turnPreparation_1.prepareTurn)({
|
|
274
|
+
state,
|
|
275
|
+
input: state._originalInput,
|
|
276
|
+
generatedItems: state._generatedItems,
|
|
277
|
+
isResumedState,
|
|
278
|
+
preserveTurnPersistenceOnResume,
|
|
279
|
+
continuingInterruptedTurn: wasContinuingInterruptedTurn,
|
|
280
|
+
serverConversationTracker,
|
|
281
|
+
inputGuardrailDefs: this.inputGuardrailDefs,
|
|
282
|
+
guardrailHandlers: {
|
|
283
|
+
onParallelStart: guardrailTracker.markPending,
|
|
284
|
+
onParallelError: guardrailTracker.setError,
|
|
285
|
+
},
|
|
286
|
+
emitAgentStart: (context, agent, inputItems) => {
|
|
287
|
+
this.emit('agent_start', context, agent, inputItems);
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
if (preserveTurnPersistenceOnResume &&
|
|
291
|
+
state._currentTurn > previousTurn &&
|
|
292
|
+
previousPersistedCount <= previousGeneratedCount) {
|
|
293
|
+
// Preserve persisted offsets from a resumed run to avoid re-saving prior items.
|
|
294
|
+
state._currentTurnPersistedItemCount = previousPersistedCount;
|
|
439
295
|
}
|
|
296
|
+
guardrailTracker.setPromise(parallelGuardrailPromise);
|
|
440
297
|
const preparedCall = await this.#prepareModelCall(state, options, artifacts, turnInput, serverConversationTracker, sessionInputUpdate);
|
|
298
|
+
guardrailTracker.throwIfError();
|
|
441
299
|
state._lastTurnResponse = await preparedCall.model.getResponse({
|
|
442
300
|
systemInstructions: preparedCall.modelInput.instructions,
|
|
443
301
|
prompt: preparedCall.prompt,
|
|
@@ -453,59 +311,74 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
453
311
|
toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
|
|
454
312
|
outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(state._currentAgent.outputType),
|
|
455
313
|
handoffs: preparedCall.serializedHandoffs,
|
|
456
|
-
tracing: getTracing(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
|
|
314
|
+
tracing: (0, tracing_1.getTracing)(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
|
|
457
315
|
signal: options.signal,
|
|
458
316
|
});
|
|
317
|
+
if (serverConversationTracker) {
|
|
318
|
+
serverConversationTracker.markInputAsSent(preparedCall.sourceItems, {
|
|
319
|
+
filterApplied: preparedCall.filterApplied,
|
|
320
|
+
allTurnItems: preparedCall.turnInput,
|
|
321
|
+
});
|
|
322
|
+
}
|
|
459
323
|
state._modelResponses.push(state._lastTurnResponse);
|
|
460
324
|
state._context.usage.add(state._lastTurnResponse.usage);
|
|
461
325
|
state._noActiveAgentRun = false;
|
|
462
326
|
// After each turn record the items echoed by the server so future requests only
|
|
463
327
|
// include the incremental inputs that have not yet been acknowledged.
|
|
464
328
|
serverConversationTracker?.trackServerItems(state._lastTurnResponse);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
const turnResult = await (0, runImplementation_1.resolveTurnAfterModelResponse)(state._currentAgent, state._originalInput, state._generatedItems, state._lastTurnResponse, state._lastProcessedResponse, this, state);
|
|
468
|
-
state._toolUseTracker.addToolUse(state._currentAgent, state._lastProcessedResponse.toolsUsed);
|
|
469
|
-
state._originalInput = turnResult.originalInput;
|
|
470
|
-
state._generatedItems = turnResult.generatedItems;
|
|
471
|
-
if (turnResult.nextStep.type === 'next_step_run_again') {
|
|
472
|
-
state._currentTurnPersistedItemCount = 0;
|
|
473
|
-
}
|
|
474
|
-
state._currentStep = turnResult.nextStep;
|
|
475
|
-
if (parallelGuardrailPromise) {
|
|
476
|
-
await parallelGuardrailPromise;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
if (state._currentStep &&
|
|
480
|
-
state._currentStep.type === 'next_step_final_output') {
|
|
481
|
-
await this.#runOutputGuardrails(state, state._currentStep.output);
|
|
482
|
-
this.emit('agent_end', state._context, state._currentAgent, state._currentStep.output);
|
|
483
|
-
state._currentAgent.emit('agent_end', state._context, state._currentStep.output);
|
|
484
|
-
return new result_1.RunResult(state);
|
|
485
|
-
}
|
|
486
|
-
else if (state._currentStep &&
|
|
487
|
-
state._currentStep.type === 'next_step_handoff') {
|
|
488
|
-
state._currentAgent = state._currentStep.newAgent;
|
|
489
|
-
if (state._currentAgentSpan) {
|
|
490
|
-
state._currentAgentSpan.end();
|
|
491
|
-
(0, context_1.resetCurrentSpan)();
|
|
492
|
-
state._currentAgentSpan = undefined;
|
|
329
|
+
if (serverConversationTracker) {
|
|
330
|
+
state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
|
|
493
331
|
}
|
|
494
|
-
state.
|
|
495
|
-
|
|
496
|
-
state.
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
332
|
+
const processedResponse = (0, modelOutputs_1.processModelResponse)(state._lastTurnResponse, state._currentAgent, preparedCall.tools, preparedCall.handoffs);
|
|
333
|
+
state._lastProcessedResponse = processedResponse;
|
|
334
|
+
const turnResult = await (0, turnResolution_1.resolveTurnAfterModelResponse)(state._currentAgent, state._originalInput, state._generatedItems, state._lastTurnResponse, state._lastProcessedResponse, this, state);
|
|
335
|
+
(0, runLoop_1.applyTurnResult)({
|
|
336
|
+
state,
|
|
337
|
+
turnResult,
|
|
338
|
+
agent: state._currentAgent,
|
|
339
|
+
toolsUsed: state._lastProcessedResponse?.toolsUsed ?? [],
|
|
340
|
+
resetTurnPersistence: !isResumedState,
|
|
341
|
+
});
|
|
342
|
+
await guardrailTracker.awaitCompletion();
|
|
502
343
|
}
|
|
503
|
-
|
|
344
|
+
const currentStep = state._currentStep;
|
|
345
|
+
if (!currentStep) {
|
|
504
346
|
logger_1.default.debug('Running next loop');
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
switch (currentStep.type) {
|
|
350
|
+
case 'next_step_final_output':
|
|
351
|
+
await (0, guardrails_1.runOutputGuardrails)(state, this.outputGuardrailDefs, currentStep.output);
|
|
352
|
+
state._currentTurnInProgress = false;
|
|
353
|
+
this.emit('agent_end', state._context, state._currentAgent, currentStep.output);
|
|
354
|
+
state._currentAgent.emit('agent_end', state._context, currentStep.output);
|
|
355
|
+
return new result_1.RunResult(state);
|
|
356
|
+
case 'next_step_handoff':
|
|
357
|
+
state.setCurrentAgent(currentStep.newAgent);
|
|
358
|
+
if (state._currentAgentSpan) {
|
|
359
|
+
state._currentAgentSpan.end();
|
|
360
|
+
(0, context_1.resetCurrentSpan)();
|
|
361
|
+
state.setCurrentAgentSpan(undefined);
|
|
362
|
+
}
|
|
363
|
+
state._noActiveAgentRun = true;
|
|
364
|
+
state._currentTurnInProgress = false;
|
|
365
|
+
// We've processed the handoff, so we need to run the loop again.
|
|
366
|
+
state._currentStep = { type: 'next_step_run_again' };
|
|
367
|
+
break;
|
|
368
|
+
case 'next_step_interruption':
|
|
369
|
+
// Interrupted. Don't run any guardrails.
|
|
370
|
+
return new result_1.RunResult(state);
|
|
371
|
+
case 'next_step_run_again':
|
|
372
|
+
state._currentTurnInProgress = false;
|
|
373
|
+
logger_1.default.debug('Running next loop');
|
|
374
|
+
break;
|
|
375
|
+
default:
|
|
376
|
+
logger_1.default.debug('Running next loop');
|
|
505
377
|
}
|
|
506
378
|
}
|
|
507
379
|
}
|
|
508
380
|
catch (err) {
|
|
381
|
+
state._currentTurnInProgress = false;
|
|
509
382
|
if (state._currentAgentSpan) {
|
|
510
383
|
state._currentAgentSpan.setError({
|
|
511
384
|
message: 'Error in agent run',
|
|
@@ -536,16 +409,22 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
536
409
|
/**
|
|
537
410
|
* @internal
|
|
538
411
|
*/
|
|
539
|
-
async #runStreamLoop(result, options, isResumedState, ensureStreamInputPersisted, sessionInputUpdate) {
|
|
540
|
-
const
|
|
412
|
+
async #runStreamLoop(result, options, isResumedState, ensureStreamInputPersisted, sessionInputUpdate, preserveTurnPersistenceOnResume) {
|
|
413
|
+
const resolvedConversationId = options.conversationId ?? result.state._conversationId;
|
|
414
|
+
const resolvedPreviousResponseId = options.previousResponseId ?? result.state._previousResponseId;
|
|
415
|
+
const serverManagesConversation = Boolean(resolvedConversationId) || Boolean(resolvedPreviousResponseId);
|
|
541
416
|
const serverConversationTracker = serverManagesConversation
|
|
542
|
-
? new ServerConversationTracker({
|
|
543
|
-
conversationId:
|
|
544
|
-
previousResponseId:
|
|
417
|
+
? new conversation_1.ServerConversationTracker({
|
|
418
|
+
conversationId: resolvedConversationId,
|
|
419
|
+
previousResponseId: resolvedPreviousResponseId,
|
|
545
420
|
})
|
|
546
421
|
: undefined;
|
|
547
|
-
|
|
422
|
+
if (serverConversationTracker) {
|
|
423
|
+
result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
|
|
424
|
+
}
|
|
425
|
+
let sentInputToModel = false;
|
|
548
426
|
let streamInputPersisted = false;
|
|
427
|
+
let guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
|
|
549
428
|
const persistStreamInputIfNeeded = async () => {
|
|
550
429
|
if (streamInputPersisted || !ensureStreamInputPersisted) {
|
|
551
430
|
return;
|
|
@@ -554,13 +433,27 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
554
433
|
await ensureStreamInputPersisted();
|
|
555
434
|
streamInputPersisted = true;
|
|
556
435
|
};
|
|
436
|
+
let parallelGuardrailPromise;
|
|
437
|
+
const awaitGuardrailsAndPersistInput = async () => {
|
|
438
|
+
await guardrailTracker.awaitCompletion();
|
|
439
|
+
if (guardrailTracker.failed) {
|
|
440
|
+
throw guardrailTracker.error;
|
|
441
|
+
}
|
|
442
|
+
if (sentInputToModel &&
|
|
443
|
+
!streamInputPersisted &&
|
|
444
|
+
!guardrailTracker.failed) {
|
|
445
|
+
await persistStreamInputIfNeeded();
|
|
446
|
+
}
|
|
447
|
+
};
|
|
557
448
|
if (serverConversationTracker && isResumedState) {
|
|
558
449
|
serverConversationTracker.primeFromState({
|
|
559
450
|
originalInput: result.state._originalInput,
|
|
560
451
|
generatedItems: result.state._generatedItems,
|
|
561
452
|
modelResponses: result.state._modelResponses,
|
|
562
453
|
});
|
|
454
|
+
result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
|
|
563
455
|
}
|
|
456
|
+
// Tracks when we resume an approval interruption so the next run-again step stays in the same turn.
|
|
564
457
|
let continuingInterruptedTurn = false;
|
|
565
458
|
try {
|
|
566
459
|
while (true) {
|
|
@@ -574,119 +467,149 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
574
467
|
!result.state._lastProcessedResponse) {
|
|
575
468
|
throw new errors_1.UserError('No model response found in previous state', result.state);
|
|
576
469
|
}
|
|
577
|
-
const
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
470
|
+
const interruptedOutcome = await (0, runLoop_1.resumeInterruptedTurn)({
|
|
471
|
+
state: result.state,
|
|
472
|
+
runner: this,
|
|
473
|
+
onStepItems: (turnResult) => {
|
|
474
|
+
(0, streaming_1.addStepToRunResult)(result, turnResult);
|
|
475
|
+
},
|
|
476
|
+
});
|
|
582
477
|
// Don't reset counter here - resolveInterruptedTurn already adjusted it via rewind logic
|
|
583
478
|
// The counter will be reset when _currentTurn is incremented (starting a new turn)
|
|
584
|
-
|
|
479
|
+
const { shouldReturn, shouldContinue } = (0, runLoop_1.handleInterruptedOutcome)({
|
|
480
|
+
state: result.state,
|
|
481
|
+
outcome: interruptedOutcome,
|
|
482
|
+
setContinuingInterruptedTurn: (value) => {
|
|
483
|
+
continuingInterruptedTurn = value;
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
if (shouldReturn) {
|
|
585
487
|
// we are still in an interruption, so we need to avoid an infinite loop
|
|
586
|
-
result.state._currentStep = turnResult.nextStep;
|
|
587
488
|
return;
|
|
588
489
|
}
|
|
589
|
-
|
|
590
|
-
// so the loop treats it as a new step without incrementing the turn.
|
|
591
|
-
// The counter has already been adjusted by resolveInterruptedTurn's rewind logic.
|
|
592
|
-
if (turnResult.nextStep.type === 'next_step_run_again') {
|
|
593
|
-
continuingInterruptedTurn = true;
|
|
594
|
-
result.state._currentStep = undefined;
|
|
490
|
+
if (shouldContinue) {
|
|
595
491
|
continue;
|
|
596
492
|
}
|
|
597
|
-
continuingInterruptedTurn = false;
|
|
598
|
-
result.state._currentStep = turnResult.nextStep;
|
|
599
493
|
}
|
|
600
494
|
if (result.state._currentStep.type === 'next_step_run_again') {
|
|
601
|
-
|
|
602
|
-
|
|
495
|
+
parallelGuardrailPromise = undefined;
|
|
496
|
+
guardrailTracker = (0, guardrails_1.createGuardrailTracker)();
|
|
497
|
+
const wasContinuingInterruptedTurn = continuingInterruptedTurn;
|
|
603
498
|
continuingInterruptedTurn = false;
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
result.state
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
499
|
+
const previousTurn = result.state._currentTurn;
|
|
500
|
+
const previousPersistedCount = result.state._currentTurnPersistedItemCount;
|
|
501
|
+
const previousGeneratedCount = result.state._generatedItems.length;
|
|
502
|
+
const preparedTurn = await (0, turnPreparation_1.prepareTurn)({
|
|
503
|
+
state: result.state,
|
|
504
|
+
input: result.input,
|
|
505
|
+
generatedItems: result.newItems,
|
|
506
|
+
isResumedState,
|
|
507
|
+
preserveTurnPersistenceOnResume,
|
|
508
|
+
continuingInterruptedTurn: wasContinuingInterruptedTurn,
|
|
509
|
+
serverConversationTracker,
|
|
510
|
+
inputGuardrailDefs: this.inputGuardrailDefs,
|
|
511
|
+
guardrailHandlers: {
|
|
512
|
+
onParallelStart: () => {
|
|
513
|
+
guardrailTracker.markPending();
|
|
514
|
+
},
|
|
515
|
+
onParallelError: (err) => {
|
|
516
|
+
guardrailTracker.setError(err);
|
|
517
|
+
},
|
|
518
|
+
},
|
|
519
|
+
emitAgentStart: (context, agent, inputItems) => {
|
|
520
|
+
this.emit('agent_start', context, agent, inputItems);
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
if (preserveTurnPersistenceOnResume &&
|
|
524
|
+
result.state._currentTurn > previousTurn &&
|
|
525
|
+
previousPersistedCount <= previousGeneratedCount) {
|
|
526
|
+
// Preserve persisted offsets from a resumed run to avoid re-saving prior items.
|
|
527
|
+
result.state._currentTurnPersistedItemCount =
|
|
528
|
+
previousPersistedCount;
|
|
529
|
+
}
|
|
530
|
+
const { artifacts, turnInput } = preparedTurn;
|
|
531
|
+
parallelGuardrailPromise = preparedTurn.parallelGuardrailPromise;
|
|
532
|
+
guardrailTracker.setPromise(parallelGuardrailPromise);
|
|
533
|
+
// If guardrails are still running, defer input persistence until they finish.
|
|
534
|
+
const delayStreamInputPersistence = guardrailTracker.pending;
|
|
535
|
+
const preparedCall = await this.#prepareModelCall(result.state, options, artifacts, turnInput, serverConversationTracker, sessionInputUpdate);
|
|
536
|
+
guardrailTracker.throwIfError();
|
|
537
|
+
let finalResponse = undefined;
|
|
538
|
+
let inputMarked = false;
|
|
539
|
+
const markInputOnce = () => {
|
|
540
|
+
if (inputMarked || !serverConversationTracker) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
// We only mark inputs as sent after receiving the first stream event,
|
|
544
|
+
// which is the earliest reliable confirmation that the server accepted
|
|
545
|
+
// the request. If the stream fails before any events, leave inputs
|
|
546
|
+
// unmarked so a retry can resend safely.
|
|
547
|
+
// Record the exact input that was sent so the server tracker can advance safely.
|
|
548
|
+
serverConversationTracker.markInputAsSent(preparedCall.sourceItems, {
|
|
549
|
+
filterApplied: preparedCall.filterApplied,
|
|
550
|
+
allTurnItems: preparedCall.turnInput,
|
|
614
551
|
});
|
|
615
|
-
|
|
552
|
+
inputMarked = true;
|
|
553
|
+
};
|
|
554
|
+
sentInputToModel = true;
|
|
555
|
+
if (!delayStreamInputPersistence) {
|
|
556
|
+
await persistStreamInputIfNeeded();
|
|
616
557
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
558
|
+
try {
|
|
559
|
+
for await (const event of preparedCall.model.getStreamedResponse({
|
|
560
|
+
systemInstructions: preparedCall.modelInput.instructions,
|
|
561
|
+
prompt: preparedCall.prompt,
|
|
562
|
+
// Streaming requests should also honor explicitly chosen models.
|
|
563
|
+
...(preparedCall.explictlyModelSet
|
|
564
|
+
? { overridePromptModel: true }
|
|
565
|
+
: {}),
|
|
566
|
+
input: preparedCall.modelInput.input,
|
|
567
|
+
previousResponseId: preparedCall.previousResponseId,
|
|
568
|
+
conversationId: preparedCall.conversationId,
|
|
569
|
+
modelSettings: preparedCall.modelSettings,
|
|
570
|
+
tools: preparedCall.serializedTools,
|
|
571
|
+
toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
|
|
572
|
+
handoffs: preparedCall.serializedHandoffs,
|
|
573
|
+
outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(currentAgent.outputType),
|
|
574
|
+
tracing: (0, tracing_1.getTracing)(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
|
|
575
|
+
signal: options.signal,
|
|
576
|
+
})) {
|
|
577
|
+
guardrailTracker.throwIfError();
|
|
578
|
+
markInputOnce();
|
|
579
|
+
if (event.type === 'response_done') {
|
|
580
|
+
const parsed = protocol_1.StreamEventResponseCompleted.parse(event);
|
|
581
|
+
finalResponse = {
|
|
582
|
+
usage: new usage_1.Usage(parsed.response.usage),
|
|
583
|
+
output: parsed.response.output,
|
|
584
|
+
responseId: parsed.response.id,
|
|
585
|
+
};
|
|
586
|
+
result.state._context.usage.add(finalResponse.usage);
|
|
587
|
+
}
|
|
588
|
+
if (result.cancelled) {
|
|
589
|
+
// When the user's code exits a loop to consume the stream, we need to break
|
|
590
|
+
// this loop to prevent internal false errors and unnecessary processing
|
|
591
|
+
await awaitGuardrailsAndPersistInput();
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
result._addItem(new events_1.RunRawModelStreamEvent(event));
|
|
632
595
|
}
|
|
633
596
|
}
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
}
|
|
641
|
-
let finalResponse = undefined;
|
|
642
|
-
const preparedCall = await this.#prepareModelCall(result.state, options, artifacts, turnInput, serverConversationTracker, sessionInputUpdate);
|
|
643
|
-
if (guardrailError) {
|
|
644
|
-
throw guardrailError;
|
|
645
|
-
}
|
|
646
|
-
handedInputToModel = true;
|
|
647
|
-
await persistStreamInputIfNeeded();
|
|
648
|
-
for await (const event of preparedCall.model.getStreamedResponse({
|
|
649
|
-
systemInstructions: preparedCall.modelInput.instructions,
|
|
650
|
-
prompt: preparedCall.prompt,
|
|
651
|
-
// Streaming requests should also honor explicitly chosen models.
|
|
652
|
-
...(preparedCall.explictlyModelSet
|
|
653
|
-
? { overridePromptModel: true }
|
|
654
|
-
: {}),
|
|
655
|
-
input: preparedCall.modelInput.input,
|
|
656
|
-
previousResponseId: preparedCall.previousResponseId,
|
|
657
|
-
conversationId: preparedCall.conversationId,
|
|
658
|
-
modelSettings: preparedCall.modelSettings,
|
|
659
|
-
tools: preparedCall.serializedTools,
|
|
660
|
-
toolsExplicitlyProvided: preparedCall.toolsExplicitlyProvided,
|
|
661
|
-
handoffs: preparedCall.serializedHandoffs,
|
|
662
|
-
outputType: (0, tools_1.convertAgentOutputTypeToSerializable)(currentAgent.outputType),
|
|
663
|
-
tracing: getTracing(this.config.tracingDisabled, this.config.traceIncludeSensitiveData),
|
|
664
|
-
signal: options.signal,
|
|
665
|
-
})) {
|
|
666
|
-
if (guardrailError) {
|
|
667
|
-
throw guardrailError;
|
|
668
|
-
}
|
|
669
|
-
if (event.type === 'response_done') {
|
|
670
|
-
const parsed = protocol_1.StreamEventResponseCompleted.parse(event);
|
|
671
|
-
finalResponse = {
|
|
672
|
-
usage: new usage_1.Usage(parsed.response.usage),
|
|
673
|
-
output: parsed.response.output,
|
|
674
|
-
responseId: parsed.response.id,
|
|
675
|
-
};
|
|
676
|
-
result.state._context.usage.add(finalResponse.usage);
|
|
677
|
-
}
|
|
678
|
-
if (result.cancelled) {
|
|
679
|
-
// When the user's code exits a loop to consume the stream, we need to break
|
|
680
|
-
// this loop to prevent internal false errors and unnecessary processing
|
|
597
|
+
catch (error) {
|
|
598
|
+
if ((0, streaming_1.isAbortError)(error)) {
|
|
599
|
+
if (sentInputToModel) {
|
|
600
|
+
markInputOnce();
|
|
601
|
+
}
|
|
602
|
+
await awaitGuardrailsAndPersistInput();
|
|
681
603
|
return;
|
|
682
604
|
}
|
|
683
|
-
|
|
605
|
+
throw error;
|
|
684
606
|
}
|
|
685
|
-
if (
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
607
|
+
if (finalResponse) {
|
|
608
|
+
markInputOnce();
|
|
609
|
+
}
|
|
610
|
+
await awaitGuardrailsAndPersistInput();
|
|
611
|
+
if (result.cancelled) {
|
|
612
|
+
return;
|
|
690
613
|
}
|
|
691
614
|
result.state._noActiveAgentRun = false;
|
|
692
615
|
if (!finalResponse) {
|
|
@@ -695,68 +618,82 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
695
618
|
result.state._lastTurnResponse = finalResponse;
|
|
696
619
|
// Keep the tracker in sync with the streamed response so reconnections remain accurate.
|
|
697
620
|
serverConversationTracker?.trackServerItems(finalResponse);
|
|
621
|
+
if (serverConversationTracker) {
|
|
622
|
+
result.state.setConversationContext(serverConversationTracker.conversationId, serverConversationTracker.previousResponseId);
|
|
623
|
+
}
|
|
698
624
|
result.state._modelResponses.push(result.state._lastTurnResponse);
|
|
699
|
-
const processedResponse = (0,
|
|
625
|
+
const processedResponse = (0, modelOutputs_1.processModelResponse)(result.state._lastTurnResponse, currentAgent, preparedCall.tools, preparedCall.handoffs);
|
|
700
626
|
result.state._lastProcessedResponse = processedResponse;
|
|
701
627
|
// Record the items emitted directly from the model response so we do not
|
|
702
628
|
// stream them again after tools and other side effects finish.
|
|
703
629
|
const preToolItems = new Set(processedResponse.newItems);
|
|
704
630
|
if (preToolItems.size > 0) {
|
|
705
|
-
(0,
|
|
706
|
-
}
|
|
707
|
-
const turnResult = await (0,
|
|
708
|
-
(0,
|
|
709
|
-
|
|
631
|
+
(0, streaming_1.streamStepItemsToRunResult)(result, processedResponse.newItems);
|
|
632
|
+
}
|
|
633
|
+
const turnResult = await (0, turnResolution_1.resolveTurnAfterModelResponse)(currentAgent, result.state._originalInput, result.state._generatedItems, result.state._lastTurnResponse, result.state._lastProcessedResponse, this, result.state);
|
|
634
|
+
(0, runLoop_1.applyTurnResult)({
|
|
635
|
+
state: result.state,
|
|
636
|
+
turnResult,
|
|
637
|
+
agent: currentAgent,
|
|
638
|
+
toolsUsed: processedResponse.toolsUsed,
|
|
639
|
+
resetTurnPersistence: !isResumedState,
|
|
640
|
+
onStepItems: (step) => {
|
|
641
|
+
(0, streaming_1.addStepToRunResult)(result, step, { skipItems: preToolItems });
|
|
642
|
+
},
|
|
710
643
|
});
|
|
711
|
-
result.state._toolUseTracker.addToolUse(currentAgent, processedResponse.toolsUsed);
|
|
712
|
-
result.state._originalInput = turnResult.originalInput;
|
|
713
|
-
result.state._generatedItems = turnResult.generatedItems;
|
|
714
|
-
if (turnResult.nextStep.type === 'next_step_run_again') {
|
|
715
|
-
result.state._currentTurnPersistedItemCount = 0;
|
|
716
|
-
}
|
|
717
|
-
result.state._currentStep = turnResult.nextStep;
|
|
718
644
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
await (
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
await (
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
645
|
+
const currentStep = result.state._currentStep;
|
|
646
|
+
switch (currentStep.type) {
|
|
647
|
+
case 'next_step_final_output':
|
|
648
|
+
await (0, guardrails_1.runOutputGuardrails)(result.state, this.outputGuardrailDefs, currentStep.output);
|
|
649
|
+
result.state._currentTurnInProgress = false;
|
|
650
|
+
await persistStreamInputIfNeeded();
|
|
651
|
+
// Guardrails must succeed before persisting session memory to avoid storing blocked outputs.
|
|
652
|
+
if (!serverManagesConversation) {
|
|
653
|
+
await (0, sessionPersistence_1.saveStreamResultToSession)(options.session, result);
|
|
654
|
+
}
|
|
655
|
+
this.emit('agent_end', result.state._context, currentAgent, currentStep.output);
|
|
656
|
+
currentAgent.emit('agent_end', result.state._context, currentStep.output);
|
|
657
|
+
return;
|
|
658
|
+
case 'next_step_interruption':
|
|
659
|
+
// We are done for now. Don't run any output guardrails.
|
|
660
|
+
await persistStreamInputIfNeeded();
|
|
661
|
+
if (!serverManagesConversation) {
|
|
662
|
+
await (0, sessionPersistence_1.saveStreamResultToSession)(options.session, result);
|
|
663
|
+
}
|
|
664
|
+
return;
|
|
665
|
+
case 'next_step_handoff':
|
|
666
|
+
result.state.setCurrentAgent(currentStep.newAgent);
|
|
667
|
+
if (result.state._currentAgentSpan) {
|
|
668
|
+
result.state._currentAgentSpan.end();
|
|
669
|
+
(0, context_1.resetCurrentSpan)();
|
|
670
|
+
}
|
|
671
|
+
result.state.setCurrentAgentSpan(undefined);
|
|
672
|
+
result._addItem(new events_1.RunAgentUpdatedStreamEvent(result.state._currentAgent));
|
|
673
|
+
result.state._noActiveAgentRun = true;
|
|
674
|
+
result.state._currentTurnInProgress = false;
|
|
675
|
+
// We've processed the handoff, so we need to run the loop again.
|
|
676
|
+
result.state._currentStep = {
|
|
677
|
+
type: 'next_step_run_again',
|
|
678
|
+
};
|
|
679
|
+
break;
|
|
680
|
+
case 'next_step_run_again':
|
|
681
|
+
result.state._currentTurnInProgress = false;
|
|
682
|
+
logger_1.default.debug('Running next loop');
|
|
683
|
+
break;
|
|
684
|
+
default:
|
|
685
|
+
logger_1.default.debug('Running next loop');
|
|
755
686
|
}
|
|
756
687
|
}
|
|
757
688
|
}
|
|
758
689
|
catch (error) {
|
|
759
|
-
|
|
690
|
+
result.state._currentTurnInProgress = false;
|
|
691
|
+
if (guardrailTracker.pending) {
|
|
692
|
+
await guardrailTracker.awaitCompletion({ suppressErrors: true });
|
|
693
|
+
}
|
|
694
|
+
if (sentInputToModel &&
|
|
695
|
+
!streamInputPersisted &&
|
|
696
|
+
!guardrailTracker.failed) {
|
|
760
697
|
await persistStreamInputIfNeeded();
|
|
761
698
|
}
|
|
762
699
|
if (result.state._currentAgentSpan) {
|
|
@@ -768,6 +705,14 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
768
705
|
throw error;
|
|
769
706
|
}
|
|
770
707
|
finally {
|
|
708
|
+
if (guardrailTracker.pending) {
|
|
709
|
+
await guardrailTracker.awaitCompletion({ suppressErrors: true });
|
|
710
|
+
}
|
|
711
|
+
if (sentInputToModel &&
|
|
712
|
+
!streamInputPersisted &&
|
|
713
|
+
!guardrailTracker.failed) {
|
|
714
|
+
await persistStreamInputIfNeeded();
|
|
715
|
+
}
|
|
771
716
|
if (result.state._currentStep?.type !== 'next_step_interruption') {
|
|
772
717
|
try {
|
|
773
718
|
await (0, tool_1.disposeResolvedComputers)({ runContext: result.state._context });
|
|
@@ -787,7 +732,7 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
787
732
|
/**
|
|
788
733
|
* @internal
|
|
789
734
|
*/
|
|
790
|
-
async #runIndividualStream(agent, input, options, ensureStreamInputPersisted, sessionInputUpdate) {
|
|
735
|
+
async #runIndividualStream(agent, input, options, ensureStreamInputPersisted, sessionInputUpdate, preserveTurnPersistenceOnResume) {
|
|
791
736
|
options = options ?? {};
|
|
792
737
|
return (0, context_1.withNewSpanContext)(async () => {
|
|
793
738
|
// Initialize or reuse existing state
|
|
@@ -796,16 +741,27 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
796
741
|
? input
|
|
797
742
|
: new runState_1.RunState(options.context instanceof runContext_1.RunContext
|
|
798
743
|
? options.context
|
|
799
|
-
: new runContext_1.RunContext(options.context), input, agent, options.maxTurns ?? DEFAULT_MAX_TURNS);
|
|
744
|
+
: new runContext_1.RunContext(options.context), input, agent, options.maxTurns ?? constants_1.DEFAULT_MAX_TURNS);
|
|
745
|
+
const resolvedConversationId = options.conversationId ??
|
|
746
|
+
(isResumedState ? state._conversationId : undefined);
|
|
747
|
+
const resolvedPreviousResponseId = options.previousResponseId ??
|
|
748
|
+
(isResumedState ? state._previousResponseId : undefined);
|
|
749
|
+
if (!isResumedState) {
|
|
750
|
+
state.setConversationContext(resolvedConversationId, resolvedPreviousResponseId);
|
|
751
|
+
}
|
|
800
752
|
// Initialize the streamed result with existing state
|
|
801
753
|
const result = new result_1.StreamedRunResult({
|
|
802
754
|
signal: options.signal,
|
|
803
755
|
state,
|
|
804
756
|
});
|
|
757
|
+
const streamOptions = {
|
|
758
|
+
...options,
|
|
759
|
+
signal: result._getAbortSignal(),
|
|
760
|
+
};
|
|
805
761
|
// Setup defaults
|
|
806
|
-
result.maxTurns =
|
|
762
|
+
result.maxTurns = streamOptions.maxTurns ?? state._maxTurns;
|
|
807
763
|
// Continue the stream loop without blocking
|
|
808
|
-
const streamLoopPromise = this.#runStreamLoop(result,
|
|
764
|
+
const streamLoopPromise = this.#runStreamLoop(result, streamOptions, isResumedState, ensureStreamInputPersisted, sessionInputUpdate, preserveTurnPersistenceOnResume).then(() => {
|
|
809
765
|
result._done();
|
|
810
766
|
}, (err) => {
|
|
811
767
|
result._raiseError(err);
|
|
@@ -815,108 +771,22 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
815
771
|
return result;
|
|
816
772
|
});
|
|
817
773
|
}
|
|
818
|
-
async #runInputGuardrails(state, guardrailsOverride) {
|
|
819
|
-
const guardrails = guardrailsOverride ?? this.#getInputGuardrailDefinitions(state);
|
|
820
|
-
if (guardrails.length > 0) {
|
|
821
|
-
const guardrailArgs = {
|
|
822
|
-
agent: state._currentAgent,
|
|
823
|
-
input: state._originalInput,
|
|
824
|
-
context: state._context,
|
|
825
|
-
};
|
|
826
|
-
try {
|
|
827
|
-
const results = await Promise.all(guardrails.map(async (guardrail) => {
|
|
828
|
-
return (0, tracing_1.withGuardrailSpan)(async (span) => {
|
|
829
|
-
const result = await guardrail.run(guardrailArgs);
|
|
830
|
-
span.spanData.triggered = result.output.tripwireTriggered;
|
|
831
|
-
return result;
|
|
832
|
-
}, { data: { name: guardrail.name } }, state._currentAgentSpan);
|
|
833
|
-
}));
|
|
834
|
-
state._inputGuardrailResults.push(...results);
|
|
835
|
-
for (const result of results) {
|
|
836
|
-
if (result.output.tripwireTriggered) {
|
|
837
|
-
if (state._currentAgentSpan) {
|
|
838
|
-
state._currentAgentSpan.setError({
|
|
839
|
-
message: 'Guardrail tripwire triggered',
|
|
840
|
-
data: { guardrail: result.guardrail.name },
|
|
841
|
-
});
|
|
842
|
-
}
|
|
843
|
-
throw new errors_1.InputGuardrailTripwireTriggered(`Input guardrail triggered: ${JSON.stringify(result.output.outputInfo)}`, result, state);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
return results;
|
|
847
|
-
}
|
|
848
|
-
catch (e) {
|
|
849
|
-
if (e instanceof errors_1.InputGuardrailTripwireTriggered) {
|
|
850
|
-
throw e;
|
|
851
|
-
}
|
|
852
|
-
// roll back the current turn to enable reruns
|
|
853
|
-
state._currentTurn--;
|
|
854
|
-
throw new errors_1.GuardrailExecutionError(`Input guardrail failed to complete: ${e}`, e, state);
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
return [];
|
|
858
|
-
}
|
|
859
|
-
async #runOutputGuardrails(state, output) {
|
|
860
|
-
const guardrails = this.outputGuardrailDefs.concat(state._currentAgent.outputGuardrails.map(guardrail_1.defineOutputGuardrail));
|
|
861
|
-
if (guardrails.length > 0) {
|
|
862
|
-
const agentOutput = state._currentAgent.processFinalOutput(output);
|
|
863
|
-
const runOutput = getTurnInput([], state._generatedItems);
|
|
864
|
-
const guardrailArgs = {
|
|
865
|
-
agent: state._currentAgent,
|
|
866
|
-
agentOutput,
|
|
867
|
-
context: state._context,
|
|
868
|
-
details: {
|
|
869
|
-
modelResponse: state._lastTurnResponse,
|
|
870
|
-
output: runOutput,
|
|
871
|
-
},
|
|
872
|
-
};
|
|
873
|
-
try {
|
|
874
|
-
const results = await Promise.all(guardrails.map(async (guardrail) => {
|
|
875
|
-
return (0, tracing_1.withGuardrailSpan)(async (span) => {
|
|
876
|
-
const result = await guardrail.run(guardrailArgs);
|
|
877
|
-
span.spanData.triggered = result.output.tripwireTriggered;
|
|
878
|
-
return result;
|
|
879
|
-
}, { data: { name: guardrail.name } }, state._currentAgentSpan);
|
|
880
|
-
}));
|
|
881
|
-
for (const result of results) {
|
|
882
|
-
if (result.output.tripwireTriggered) {
|
|
883
|
-
if (state._currentAgentSpan) {
|
|
884
|
-
state._currentAgentSpan.setError({
|
|
885
|
-
message: 'Guardrail tripwire triggered',
|
|
886
|
-
data: { guardrail: result.guardrail.name },
|
|
887
|
-
});
|
|
888
|
-
}
|
|
889
|
-
throw new errors_1.OutputGuardrailTripwireTriggered(`Output guardrail triggered: ${JSON.stringify(result.output.outputInfo)}`, result, state);
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
}
|
|
893
|
-
catch (e) {
|
|
894
|
-
if (e instanceof errors_1.OutputGuardrailTripwireTriggered) {
|
|
895
|
-
throw e;
|
|
896
|
-
}
|
|
897
|
-
throw new errors_1.GuardrailExecutionError(`Output guardrail failed to complete: ${e}`, e, state);
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
774
|
/**
|
|
902
775
|
* @internal
|
|
903
776
|
* Applies call-level filters and merges session updates so the model request mirrors exactly
|
|
904
777
|
* what we persisted for history.
|
|
905
778
|
*/
|
|
906
779
|
async #prepareModelCall(state, options, artifacts, turnInput, serverConversationTracker, sessionInputUpdate) {
|
|
907
|
-
const { model, explictlyModelSet } = await this.#resolveModelForAgent(state._currentAgent);
|
|
780
|
+
const { model, explictlyModelSet, resolvedModelName } = await this.#resolveModelForAgent(state._currentAgent);
|
|
908
781
|
let modelSettings = {
|
|
909
782
|
...this.config.modelSettings,
|
|
910
783
|
...state._currentAgent.modelSettings,
|
|
911
784
|
};
|
|
912
|
-
modelSettings = adjustModelSettingsForNonGPT5RunnerModel(explictlyModelSet, state._currentAgent.modelSettings, model, modelSettings);
|
|
913
|
-
modelSettings = (0,
|
|
785
|
+
modelSettings = (0, modelSettings_1.adjustModelSettingsForNonGPT5RunnerModel)(explictlyModelSet, state._currentAgent.modelSettings, model, modelSettings, resolvedModelName);
|
|
786
|
+
modelSettings = (0, modelSettings_1.maybeResetToolChoice)(state._currentAgent, state._toolUseTracker, modelSettings);
|
|
914
787
|
const systemInstructions = await state._currentAgent.getSystemPrompt(state._context);
|
|
915
788
|
const prompt = await state._currentAgent.getPrompt(state._context);
|
|
916
|
-
const { modelInput, sourceItems, persistedItems, filterApplied } = await applyCallModelInputFilter(state._currentAgent, options.callModelInputFilter, state._context, turnInput, systemInstructions);
|
|
917
|
-
// Inform the tracker which exact original objects made it to the provider so future turns
|
|
918
|
-
// only send the delta that has not yet been acknowledged by the server.
|
|
919
|
-
serverConversationTracker?.markInputAsSent(sourceItems);
|
|
789
|
+
const { modelInput, sourceItems, persistedItems, filterApplied } = await (0, conversation_1.applyCallModelInputFilter)(state._currentAgent, options.callModelInputFilter, state._context, turnInput, systemInstructions);
|
|
920
790
|
// Provide filtered clones whenever filters run so session history mirrors the model payload.
|
|
921
791
|
// Returning an empty array is intentional: it tells the session layer to persist "nothing"
|
|
922
792
|
// instead of falling back to the unfiltered originals when the filter redacts everything.
|
|
@@ -933,462 +803,19 @@ class Runner extends lifecycle_1.RunHooks {
|
|
|
933
803
|
prompt,
|
|
934
804
|
previousResponseId,
|
|
935
805
|
conversationId,
|
|
936
|
-
};
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
exports.Runner = Runner;
|
|
940
|
-
/**
|
|
941
|
-
* Constructs the model input array for the current turn by combining the original turn input with
|
|
942
|
-
* any new run items (excluding tool approval placeholders). This helps ensure that repeated calls
|
|
943
|
-
* to the Responses API only send newly generated content.
|
|
944
|
-
*
|
|
945
|
-
* See: https://platform.openai.com/docs/guides/conversation-state?api-mode=responses.
|
|
946
|
-
*/
|
|
947
|
-
function getTurnInput(originalInput, generatedItems) {
|
|
948
|
-
const rawItems = generatedItems
|
|
949
|
-
.filter((item) => item.type !== 'tool_approval_item') // don't include approval items to avoid double function calls
|
|
950
|
-
.map((item) => item.rawItem);
|
|
951
|
-
return [...toAgentInputList(originalInput), ...rawItems];
|
|
952
|
-
}
|
|
953
|
-
// --------------------------------------------------------------
|
|
954
|
-
// Internal helpers
|
|
955
|
-
// --------------------------------------------------------------
|
|
956
|
-
const DEFAULT_MAX_TURNS = 10;
|
|
957
|
-
let _defaultRunner = undefined;
|
|
958
|
-
function getDefaultRunner() {
|
|
959
|
-
if (_defaultRunner) {
|
|
960
|
-
return _defaultRunner;
|
|
961
|
-
}
|
|
962
|
-
_defaultRunner = new Runner();
|
|
963
|
-
return _defaultRunner;
|
|
964
|
-
}
|
|
965
|
-
/**
|
|
966
|
-
* Resolves the effective model for the next turn by giving precedence to the agent-specific
|
|
967
|
-
* configuration when present, otherwise falling back to the runner-level default.
|
|
968
|
-
*/
|
|
969
|
-
function selectModel(agentModel, runConfigModel) {
|
|
970
|
-
// When initializing an agent without model name, the model property is set to an empty string. So,
|
|
971
|
-
// * agentModel === Agent.DEFAULT_MODEL_PLACEHOLDER & runConfigModel exists, runConfigModel will be used
|
|
972
|
-
// * agentModel is set, the agentModel will be used over runConfigModel
|
|
973
|
-
if ((typeof agentModel === 'string' &&
|
|
974
|
-
agentModel !== agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER) ||
|
|
975
|
-
agentModel // any truthy value
|
|
976
|
-
) {
|
|
977
|
-
return agentModel;
|
|
978
|
-
}
|
|
979
|
-
return runConfigModel ?? agentModel ?? agent_1.Agent.DEFAULT_MODEL_PLACEHOLDER;
|
|
980
|
-
}
|
|
981
|
-
/**
|
|
982
|
-
* Normalizes tracing configuration into the format expected by model providers.
|
|
983
|
-
* Returns `false` to disable tracing, `true` to include full payload data, or
|
|
984
|
-
* `'enabled_without_data'` to omit sensitive content while still emitting spans.
|
|
985
|
-
*/
|
|
986
|
-
function getTracing(tracingDisabled, traceIncludeSensitiveData) {
|
|
987
|
-
if (tracingDisabled) {
|
|
988
|
-
return false;
|
|
989
|
-
}
|
|
990
|
-
if (traceIncludeSensitiveData) {
|
|
991
|
-
return true;
|
|
992
|
-
}
|
|
993
|
-
return 'enabled_without_data';
|
|
994
|
-
}
|
|
995
|
-
/**
|
|
996
|
-
* @internal
|
|
997
|
-
*/
|
|
998
|
-
async function applyCallModelInputFilter(agent, callModelInputFilter, context, inputItems, systemInstructions) {
|
|
999
|
-
const cloneInputItems = (items, map) => items.map((item) => {
|
|
1000
|
-
const cloned = structuredClone(item);
|
|
1001
|
-
if (map && cloned && typeof cloned === 'object') {
|
|
1002
|
-
map.set(cloned, item);
|
|
1003
|
-
}
|
|
1004
|
-
return cloned;
|
|
1005
|
-
});
|
|
1006
|
-
// Record the relationship between the cloned array passed to filters and the original inputs.
|
|
1007
|
-
const cloneMap = new WeakMap();
|
|
1008
|
-
const originalPool = buildAgentInputPool(inputItems);
|
|
1009
|
-
const fallbackOriginals = [];
|
|
1010
|
-
// Track any original object inputs so filtered replacements can still mark them as delivered.
|
|
1011
|
-
for (const item of inputItems) {
|
|
1012
|
-
if (item && typeof item === 'object') {
|
|
1013
|
-
fallbackOriginals.push(item);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
const removeFromFallback = (candidate) => {
|
|
1017
|
-
if (!candidate || typeof candidate !== 'object') {
|
|
1018
|
-
return;
|
|
1019
|
-
}
|
|
1020
|
-
const index = fallbackOriginals.findIndex((original) => original === candidate);
|
|
1021
|
-
if (index !== -1) {
|
|
1022
|
-
fallbackOriginals.splice(index, 1);
|
|
1023
|
-
}
|
|
1024
|
-
};
|
|
1025
|
-
const takeFallbackOriginal = () => {
|
|
1026
|
-
const next = fallbackOriginals.shift();
|
|
1027
|
-
if (next) {
|
|
1028
|
-
removeAgentInputFromPool(originalPool, next);
|
|
1029
|
-
}
|
|
1030
|
-
return next;
|
|
1031
|
-
};
|
|
1032
|
-
// Always create a deep copy so downstream mutations inside filters cannot affect
|
|
1033
|
-
// the cached turn state.
|
|
1034
|
-
const clonedBaseInput = cloneInputItems(inputItems, cloneMap);
|
|
1035
|
-
const base = {
|
|
1036
|
-
input: clonedBaseInput,
|
|
1037
|
-
instructions: systemInstructions,
|
|
1038
|
-
};
|
|
1039
|
-
if (!callModelInputFilter) {
|
|
1040
|
-
return {
|
|
1041
|
-
modelInput: base,
|
|
1042
|
-
sourceItems: [...inputItems],
|
|
1043
|
-
persistedItems: [],
|
|
1044
|
-
filterApplied: false,
|
|
1045
|
-
};
|
|
1046
|
-
}
|
|
1047
|
-
try {
|
|
1048
|
-
const result = await callModelInputFilter({
|
|
1049
|
-
modelData: base,
|
|
1050
|
-
agent,
|
|
1051
|
-
context: context.context,
|
|
1052
|
-
});
|
|
1053
|
-
if (!result || !Array.isArray(result.input)) {
|
|
1054
|
-
throw new errors_1.UserError('callModelInputFilter must return a ModelInputData object with an input array.');
|
|
1055
|
-
}
|
|
1056
|
-
// Preserve a pointer to the original object backing each filtered clone so downstream
|
|
1057
|
-
// trackers can keep their bookkeeping consistent even after redaction.
|
|
1058
|
-
const sourceItems = result.input.map((item) => {
|
|
1059
|
-
if (!item || typeof item !== 'object') {
|
|
1060
|
-
return undefined;
|
|
1061
|
-
}
|
|
1062
|
-
const original = cloneMap.get(item);
|
|
1063
|
-
if (original) {
|
|
1064
|
-
removeFromFallback(original);
|
|
1065
|
-
removeAgentInputFromPool(originalPool, original);
|
|
1066
|
-
return original;
|
|
1067
|
-
}
|
|
1068
|
-
const key = getAgentInputItemKey(item);
|
|
1069
|
-
const matchedByContent = takeAgentInputFromPool(originalPool, key);
|
|
1070
|
-
if (matchedByContent) {
|
|
1071
|
-
removeFromFallback(matchedByContent);
|
|
1072
|
-
return matchedByContent;
|
|
1073
|
-
}
|
|
1074
|
-
const fallback = takeFallbackOriginal();
|
|
1075
|
-
if (fallback) {
|
|
1076
|
-
return fallback;
|
|
1077
|
-
}
|
|
1078
|
-
return undefined;
|
|
1079
|
-
});
|
|
1080
|
-
const clonedFilteredInput = cloneInputItems(result.input);
|
|
1081
|
-
return {
|
|
1082
|
-
modelInput: {
|
|
1083
|
-
input: clonedFilteredInput,
|
|
1084
|
-
instructions: typeof result.instructions === 'undefined'
|
|
1085
|
-
? systemInstructions
|
|
1086
|
-
: result.instructions,
|
|
1087
|
-
},
|
|
1088
806
|
sourceItems,
|
|
1089
|
-
|
|
1090
|
-
|
|
807
|
+
filterApplied,
|
|
808
|
+
turnInput,
|
|
1091
809
|
};
|
|
1092
810
|
}
|
|
1093
|
-
catch (error) {
|
|
1094
|
-
(0, context_1.addErrorToCurrentSpan)({
|
|
1095
|
-
message: 'Error in callModelInputFilter',
|
|
1096
|
-
data: { error: String(error) },
|
|
1097
|
-
});
|
|
1098
|
-
throw error;
|
|
1099
|
-
}
|
|
1100
811
|
}
|
|
1101
|
-
|
|
1102
|
-
//
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
conversationId;
|
|
1108
|
-
// Previous Response ID:
|
|
1109
|
-
// https://platform.openai.com/docs/guides/conversation-state?api-mode=responses#passing-context-from-the-previous-response
|
|
1110
|
-
previousResponseId;
|
|
1111
|
-
// Using this flag because WeakSet does not provide a way to check its size
|
|
1112
|
-
sentInitialInput = false;
|
|
1113
|
-
// The items already sent to the model; using WeakSet for memory efficiency
|
|
1114
|
-
sentItems = new WeakSet();
|
|
1115
|
-
// The items received from the server; using WeakSet for memory efficiency
|
|
1116
|
-
serverItems = new WeakSet();
|
|
1117
|
-
// Track initial input items that have not yet been sent so they can be retried on later turns.
|
|
1118
|
-
remainingInitialInput = null;
|
|
1119
|
-
constructor({ conversationId, previousResponseId, }) {
|
|
1120
|
-
this.conversationId = conversationId ?? undefined;
|
|
1121
|
-
this.previousResponseId = previousResponseId ?? undefined;
|
|
1122
|
-
}
|
|
1123
|
-
/**
|
|
1124
|
-
* Pre-populates tracker caches from an existing RunState when resuming server-managed runs.
|
|
1125
|
-
*/
|
|
1126
|
-
primeFromState({ originalInput, generatedItems, modelResponses, }) {
|
|
1127
|
-
if (this.sentInitialInput) {
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
for (const item of toAgentInputList(originalInput)) {
|
|
1131
|
-
if (item && typeof item === 'object') {
|
|
1132
|
-
this.sentItems.add(item);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
this.sentInitialInput = true;
|
|
1136
|
-
this.remainingInitialInput = null;
|
|
1137
|
-
const latestResponse = modelResponses[modelResponses.length - 1];
|
|
1138
|
-
for (const response of modelResponses) {
|
|
1139
|
-
for (const item of response.output) {
|
|
1140
|
-
if (item && typeof item === 'object') {
|
|
1141
|
-
this.serverItems.add(item);
|
|
1142
|
-
}
|
|
1143
|
-
}
|
|
1144
|
-
}
|
|
1145
|
-
if (!this.conversationId && latestResponse?.responseId) {
|
|
1146
|
-
this.previousResponseId = latestResponse.responseId;
|
|
1147
|
-
}
|
|
1148
|
-
for (const item of generatedItems) {
|
|
1149
|
-
const rawItem = item.rawItem;
|
|
1150
|
-
if (!rawItem || typeof rawItem !== 'object') {
|
|
1151
|
-
continue;
|
|
1152
|
-
}
|
|
1153
|
-
if (this.serverItems.has(rawItem)) {
|
|
1154
|
-
this.sentItems.add(rawItem);
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
/**
|
|
1159
|
-
* Records the raw items returned by the server so future delta calculations skip them.
|
|
1160
|
-
* Also captures the latest response identifier to chain follow-up calls when possible.
|
|
1161
|
-
*/
|
|
1162
|
-
trackServerItems(modelResponse) {
|
|
1163
|
-
if (!modelResponse) {
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
for (const item of modelResponse.output) {
|
|
1167
|
-
if (item && typeof item === 'object') {
|
|
1168
|
-
this.serverItems.add(item);
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
|
-
if (!this.conversationId && modelResponse.responseId) {
|
|
1172
|
-
this.previousResponseId = modelResponse.responseId;
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
/**
|
|
1176
|
-
* Returns the minimum set of items that still need to be delivered to the server for the
|
|
1177
|
-
* current turn. This includes the original turn inputs (until acknowledged) plus any
|
|
1178
|
-
* newly generated items that have not yet been echoed back by the API.
|
|
1179
|
-
*/
|
|
1180
|
-
prepareInput(originalInput, generatedItems) {
|
|
1181
|
-
const inputItems = [];
|
|
1182
|
-
if (!this.sentInitialInput) {
|
|
1183
|
-
const initialItems = toAgentInputList(originalInput);
|
|
1184
|
-
// Preserve the full initial payload so a filter can drop items without losing their originals.
|
|
1185
|
-
inputItems.push(...initialItems);
|
|
1186
|
-
this.remainingInitialInput = initialItems.filter((item) => Boolean(item) && typeof item === 'object');
|
|
1187
|
-
this.sentInitialInput = true;
|
|
1188
|
-
}
|
|
1189
|
-
else if (this.remainingInitialInput &&
|
|
1190
|
-
this.remainingInitialInput.length > 0) {
|
|
1191
|
-
// Re-queue prior initial items until the tracker confirms they were delivered to the API.
|
|
1192
|
-
inputItems.push(...this.remainingInitialInput);
|
|
1193
|
-
}
|
|
1194
|
-
for (const item of generatedItems) {
|
|
1195
|
-
if (item.type === 'tool_approval_item') {
|
|
1196
|
-
continue;
|
|
1197
|
-
}
|
|
1198
|
-
const rawItem = item.rawItem;
|
|
1199
|
-
if (!rawItem || typeof rawItem !== 'object') {
|
|
1200
|
-
continue;
|
|
1201
|
-
}
|
|
1202
|
-
if (this.sentItems.has(rawItem) || this.serverItems.has(rawItem)) {
|
|
1203
|
-
continue;
|
|
1204
|
-
}
|
|
1205
|
-
inputItems.push(rawItem);
|
|
1206
|
-
}
|
|
1207
|
-
return inputItems;
|
|
1208
|
-
}
|
|
1209
|
-
/**
|
|
1210
|
-
* Marks the provided originals as delivered so future turns do not resend them and any
|
|
1211
|
-
* pending initial inputs can be dropped once the server acknowledges receipt.
|
|
1212
|
-
*/
|
|
1213
|
-
markInputAsSent(items) {
|
|
1214
|
-
if (!items.length) {
|
|
1215
|
-
return;
|
|
1216
|
-
}
|
|
1217
|
-
const delivered = new Set();
|
|
1218
|
-
for (const item of items) {
|
|
1219
|
-
if (!item || typeof item !== 'object' || delivered.has(item)) {
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
// Some inputs may be repeated in the filtered list; only mark unique originals once.
|
|
1223
|
-
delivered.add(item);
|
|
1224
|
-
this.sentItems.add(item);
|
|
1225
|
-
}
|
|
1226
|
-
if (!this.remainingInitialInput ||
|
|
1227
|
-
this.remainingInitialInput.length === 0) {
|
|
1228
|
-
return;
|
|
1229
|
-
}
|
|
1230
|
-
this.remainingInitialInput = this.remainingInitialInput.filter((item) => !delivered.has(item));
|
|
1231
|
-
if (this.remainingInitialInput.length === 0) {
|
|
1232
|
-
this.remainingInitialInput = null;
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
/**
|
|
1237
|
-
* When the default model is a GPT-5 variant, agents may carry GPT-5-specific providerData
|
|
1238
|
-
* (e.g., reasoning effort, text verbosity). If a run resolves to a non-GPT-5 model and the
|
|
1239
|
-
* agent relied on the default model (i.e., no explicit model set), these GPT-5-only settings
|
|
1240
|
-
* are incompatible and should be stripped to avoid runtime errors.
|
|
1241
|
-
*/
|
|
1242
|
-
function adjustModelSettingsForNonGPT5RunnerModel(explictlyModelSet, agentModelSettings, runnerModel, modelSettings) {
|
|
1243
|
-
if (
|
|
1244
|
-
// gpt-5 is enabled for the default model for agents
|
|
1245
|
-
(0, defaultModel_1.isGpt5Default)() &&
|
|
1246
|
-
// explicitly set model for the agent
|
|
1247
|
-
explictlyModelSet &&
|
|
1248
|
-
// this runner uses a non-gpt-5 model
|
|
1249
|
-
(typeof runnerModel !== 'string' ||
|
|
1250
|
-
!(0, defaultModel_1.gpt5ReasoningSettingsRequired)(runnerModel)) &&
|
|
1251
|
-
(agentModelSettings.providerData?.reasoning ||
|
|
1252
|
-
agentModelSettings.providerData?.text?.verbosity ||
|
|
1253
|
-
agentModelSettings.providerData?.reasoning_effort)) {
|
|
1254
|
-
const copiedModelSettings = { ...modelSettings };
|
|
1255
|
-
// the incompatible parameters should be removed to avoid runtime errors
|
|
1256
|
-
delete copiedModelSettings.providerData?.reasoning;
|
|
1257
|
-
delete copiedModelSettings.providerData?.text?.verbosity;
|
|
1258
|
-
delete copiedModelSettings.providerData?.reasoning_effort;
|
|
1259
|
-
if (copiedModelSettings.reasoning) {
|
|
1260
|
-
delete copiedModelSettings.reasoning.effort;
|
|
1261
|
-
delete copiedModelSettings.reasoning.summary;
|
|
1262
|
-
}
|
|
1263
|
-
if (copiedModelSettings.text) {
|
|
1264
|
-
delete copiedModelSettings.text.verbosity;
|
|
1265
|
-
}
|
|
1266
|
-
return copiedModelSettings;
|
|
1267
|
-
}
|
|
1268
|
-
return modelSettings;
|
|
1269
|
-
}
|
|
1270
|
-
/**
|
|
1271
|
-
* @internal
|
|
1272
|
-
* Collects tools/handoffs early so we can annotate spans before model execution begins.
|
|
1273
|
-
*/
|
|
1274
|
-
async function prepareAgentArtifacts(state) {
|
|
1275
|
-
const handoffs = await state._currentAgent.getEnabledHandoffs(state._context);
|
|
1276
|
-
const tools = await state._currentAgent.getAllTools(state._context);
|
|
1277
|
-
const computerTools = tools.filter((tool) => tool.type === 'computer');
|
|
1278
|
-
if (computerTools.length > 0) {
|
|
1279
|
-
await Promise.all(computerTools.map(async (tool) => {
|
|
1280
|
-
await (0, tool_1.resolveComputer)({ tool, runContext: state._context });
|
|
1281
|
-
}));
|
|
1282
|
-
}
|
|
1283
|
-
if (!state._currentAgentSpan) {
|
|
1284
|
-
const handoffNames = handoffs.map((h) => h.agentName);
|
|
1285
|
-
state._currentAgentSpan = (0, tracing_1.createAgentSpan)({
|
|
1286
|
-
data: {
|
|
1287
|
-
name: state._currentAgent.name,
|
|
1288
|
-
handoffs: handoffNames,
|
|
1289
|
-
tools: tools.map((t) => t.name),
|
|
1290
|
-
output_type: state._currentAgent.outputSchemaName,
|
|
1291
|
-
},
|
|
1292
|
-
});
|
|
1293
|
-
state._currentAgentSpan.start();
|
|
1294
|
-
(0, context_1.setCurrentSpan)(state._currentAgentSpan);
|
|
1295
|
-
}
|
|
1296
|
-
else {
|
|
1297
|
-
state._currentAgentSpan.spanData.tools = tools.map((t) => t.name);
|
|
1298
|
-
}
|
|
1299
|
-
return {
|
|
1300
|
-
handoffs,
|
|
1301
|
-
tools,
|
|
1302
|
-
serializedHandoffs: handoffs.map((handoff) => (0, serialize_1.serializeHandoff)(handoff)),
|
|
1303
|
-
serializedTools: tools.map((tool) => (0, serialize_1.serializeTool)(tool)),
|
|
1304
|
-
toolsExplicitlyProvided: state._currentAgent.hasExplicitToolConfig(),
|
|
1305
|
-
};
|
|
1306
|
-
}
|
|
1307
|
-
function getAgentInputItemKey(item) {
|
|
1308
|
-
// Deep serialization keeps binary inputs comparable after filters clone them.
|
|
1309
|
-
return JSON.stringify(item, agentInputSerializationReplacer);
|
|
1310
|
-
}
|
|
1311
|
-
function buildAgentInputPool(items) {
|
|
1312
|
-
// Track every original object so filters can safely return cloned copies.
|
|
1313
|
-
const pool = new Map();
|
|
1314
|
-
for (const item of items) {
|
|
1315
|
-
const key = getAgentInputItemKey(item);
|
|
1316
|
-
const existing = pool.get(key);
|
|
1317
|
-
if (existing) {
|
|
1318
|
-
existing.push(item);
|
|
1319
|
-
}
|
|
1320
|
-
else {
|
|
1321
|
-
pool.set(key, [item]);
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
return pool;
|
|
1325
|
-
}
|
|
1326
|
-
function takeAgentInputFromPool(pool, key) {
|
|
1327
|
-
// Prefer reusing the earliest untouched original to keep ordering stable.
|
|
1328
|
-
const candidates = pool.get(key);
|
|
1329
|
-
if (!candidates || candidates.length === 0) {
|
|
1330
|
-
return undefined;
|
|
1331
|
-
}
|
|
1332
|
-
const [first] = candidates;
|
|
1333
|
-
candidates.shift();
|
|
1334
|
-
if (candidates.length === 0) {
|
|
1335
|
-
pool.delete(key);
|
|
1336
|
-
}
|
|
1337
|
-
return first;
|
|
1338
|
-
}
|
|
1339
|
-
function removeAgentInputFromPool(pool, item) {
|
|
1340
|
-
// Remove exactly the matched instance so duplicate payloads remain available.
|
|
1341
|
-
const key = getAgentInputItemKey(item);
|
|
1342
|
-
const candidates = pool.get(key);
|
|
1343
|
-
if (!candidates || candidates.length === 0) {
|
|
1344
|
-
return;
|
|
1345
|
-
}
|
|
1346
|
-
const index = candidates.findIndex((candidate) => candidate === item);
|
|
1347
|
-
if (index === -1) {
|
|
1348
|
-
return;
|
|
1349
|
-
}
|
|
1350
|
-
candidates.splice(index, 1);
|
|
1351
|
-
if (candidates.length === 0) {
|
|
1352
|
-
pool.delete(key);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
function agentInputSerializationReplacer(_key, value) {
|
|
1356
|
-
// Mirror runImplementation serialization so buffer snapshots round-trip.
|
|
1357
|
-
if (value instanceof ArrayBuffer) {
|
|
1358
|
-
return {
|
|
1359
|
-
__type: 'ArrayBuffer',
|
|
1360
|
-
data: (0, base64_1.encodeUint8ArrayToBase64)(new Uint8Array(value)),
|
|
1361
|
-
};
|
|
1362
|
-
}
|
|
1363
|
-
if ((0, smartString_1.isArrayBufferView)(value)) {
|
|
1364
|
-
const view = value;
|
|
1365
|
-
return {
|
|
1366
|
-
__type: view.constructor.name,
|
|
1367
|
-
data: (0, base64_1.encodeUint8ArrayToBase64)(new Uint8Array(view.buffer, view.byteOffset, view.byteLength)),
|
|
1368
|
-
};
|
|
1369
|
-
}
|
|
1370
|
-
if ((0, smartString_1.isNodeBuffer)(value)) {
|
|
1371
|
-
const view = value;
|
|
1372
|
-
return {
|
|
1373
|
-
__type: 'Buffer',
|
|
1374
|
-
data: (0, base64_1.encodeUint8ArrayToBase64)(new Uint8Array(view.buffer, view.byteOffset, view.byteLength)),
|
|
1375
|
-
};
|
|
1376
|
-
}
|
|
1377
|
-
if ((0, smartString_1.isSerializedBufferSnapshot)(value)) {
|
|
1378
|
-
return {
|
|
1379
|
-
__type: 'Buffer',
|
|
1380
|
-
data: (0, base64_1.encodeUint8ArrayToBase64)(Uint8Array.from(value.data)),
|
|
1381
|
-
};
|
|
1382
|
-
}
|
|
1383
|
-
return value;
|
|
1384
|
-
}
|
|
1385
|
-
// Normalizes user-provided input into the structure the model expects. Strings become user messages,
|
|
1386
|
-
// arrays are kept as-is so downstream loops can treat both scenarios uniformly.
|
|
1387
|
-
function toAgentInputList(originalInput) {
|
|
1388
|
-
// Allow callers to pass plain strings while preserving original item order.
|
|
1389
|
-
if (typeof originalInput === 'string') {
|
|
1390
|
-
return [{ type: 'message', role: 'user', content: originalInput }];
|
|
812
|
+
exports.Runner = Runner;
|
|
813
|
+
// internal helpers and constants
|
|
814
|
+
let defaultRunner;
|
|
815
|
+
const getDefaultRunner = () => {
|
|
816
|
+
if (!defaultRunner) {
|
|
817
|
+
defaultRunner = new Runner();
|
|
1391
818
|
}
|
|
1392
|
-
return
|
|
1393
|
-
}
|
|
819
|
+
return defaultRunner;
|
|
820
|
+
};
|
|
1394
821
|
//# sourceMappingURL=run.js.map
|