@opengeni/worker-bundle 1.2.1-canary.37222965366001 → 1.4.0
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/activities/agent-turn/errors.d.ts +1 -13
- package/dist/activities/agent-turn/subscription-lease.d.ts +1 -0
- package/dist/activities/agent-turn/tool-policy.d.ts +10 -1
- package/dist/activities/agent-turn/web-search.d.ts +33 -0
- package/dist/activities/codemode-dispatcher.d.ts +6 -2
- package/dist/activities/open-suffix-resume.d.ts +2 -0
- package/dist/activities/programmatic-approvals.d.ts +27 -0
- package/dist/activities/run-input.d.ts +2 -0
- package/dist/{activities-control-QSDPXLLD.js → activities-control-D5KVEPHI.js} +3 -3
- package/dist/{activities-turn-BMY3CDKL.js → activities-turn-4Z3M7Z3F.js} +554 -113
- package/dist/activities-turn-4Z3M7Z3F.js.map +1 -0
- package/dist/{chunk-JKMG5ZHH.js → chunk-BMTWULF7.js} +115 -31
- package/dist/chunk-BMTWULF7.js.map +1 -0
- package/dist/{chunk-XONQEVAD.js → chunk-FF4HPY7L.js} +1 -1
- package/dist/chunk-FF4HPY7L.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/observability-metrics.d.ts +1 -1
- package/package.json +21 -21
- package/src/activities/agent-turn/agent-build.ts +6 -4
- package/src/activities/agent-turn/errors.ts +82 -3
- package/src/activities/agent-turn/governance-model.ts +8 -8
- package/src/activities/agent-turn/sandbox-runtime.ts +16 -0
- package/src/activities/agent-turn/stream-attempt.ts +100 -21
- package/src/activities/agent-turn/subscription-lease.ts +10 -1
- package/src/activities/agent-turn/tool-environment.ts +20 -0
- package/src/activities/agent-turn/tool-policy.ts +26 -5
- package/src/activities/agent-turn/web-search.ts +252 -0
- package/src/activities/codemode-dispatcher.ts +145 -7
- package/src/activities/connector-attachments.ts +3 -1
- package/src/activities/open-suffix-resume.ts +107 -86
- package/src/activities/programmatic-approvals.ts +52 -0
- package/src/activities/run-input.ts +4 -1
- package/src/activity-services.ts +8 -0
- package/src/observability-metrics.ts +1 -0
- package/src/sandbox-routing.ts +58 -24
- package/dist/activities-turn-BMY3CDKL.js.map +0 -1
- package/dist/chunk-JKMG5ZHH.js.map +0 -1
- package/dist/chunk-XONQEVAD.js.map +0 -1
- /package/dist/{activities-control-QSDPXLLD.js.map → activities-control-D5KVEPHI.js.map} +0 -0
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
withFirstPartyTools,
|
|
100
100
|
wrapLazyTurnBoxWithRouting,
|
|
101
101
|
wrapTurnBoxWithRouting
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-BMTWULF7.js";
|
|
103
103
|
import {
|
|
104
104
|
StreamTimingMetrics,
|
|
105
105
|
makeMachineOpObserver,
|
|
@@ -132,7 +132,7 @@ import {
|
|
|
132
132
|
runtimeMetricsHooksForObservability,
|
|
133
133
|
sandboxAutomaticRecoveryOutcome,
|
|
134
134
|
turnLifecycleMetricsFor
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-FF4HPY7L.js";
|
|
136
136
|
import {
|
|
137
137
|
__export
|
|
138
138
|
} from "./chunk-PZ5AY32C.js";
|
|
@@ -1193,12 +1193,14 @@ import {
|
|
|
1193
1193
|
} from "@opengeni/db";
|
|
1194
1194
|
|
|
1195
1195
|
// src/activities/agent-turn/subscription-lease.ts
|
|
1196
|
+
var HEARTBEAT_INTERVAL_MS = 6e4;
|
|
1196
1197
|
var SubscriptionTurnLease = class {
|
|
1197
1198
|
constructor(leaseDeps) {
|
|
1198
1199
|
this.leaseDeps = leaseDeps;
|
|
1199
1200
|
if (!Number.isFinite(leaseDeps.ttlMs) || leaseDeps.ttlMs <= 0)
|
|
1200
1201
|
throw new Error("Subscription lease TTL must be positive");
|
|
1201
1202
|
this.now = leaseDeps.now ?? (() => performance.now());
|
|
1203
|
+
this.renewalIntervalMs = Math.min(HEARTBEAT_INTERVAL_MS, leaseDeps.ttlMs / 5);
|
|
1202
1204
|
}
|
|
1203
1205
|
held = false;
|
|
1204
1206
|
lost = false;
|
|
@@ -1209,6 +1211,7 @@ var SubscriptionTurnLease = class {
|
|
|
1209
1211
|
heartbeatInFlight = false;
|
|
1210
1212
|
heartbeatTimer;
|
|
1211
1213
|
now;
|
|
1214
|
+
renewalIntervalMs;
|
|
1212
1215
|
expired = (deadline) => deadline === null || !Number.isFinite(deadline) || this.now() >= deadline;
|
|
1213
1216
|
markLost = (reason) => {
|
|
1214
1217
|
if (this.lost) return;
|
|
@@ -1231,6 +1234,8 @@ var SubscriptionTurnLease = class {
|
|
|
1231
1234
|
return;
|
|
1232
1235
|
}
|
|
1233
1236
|
if (this.heartbeatInFlight) return;
|
|
1237
|
+
const renewAt = this.confirmedUntilMs - this.leaseDeps.ttlMs + this.renewalIntervalMs;
|
|
1238
|
+
if (this.now() < renewAt) return;
|
|
1234
1239
|
this.heartbeatInFlight = true;
|
|
1235
1240
|
const priorDeadline = this.confirmedUntilMs;
|
|
1236
1241
|
const startedAt = this.now();
|
|
@@ -1257,7 +1262,7 @@ var SubscriptionTurnLease = class {
|
|
|
1257
1262
|
};
|
|
1258
1263
|
startHeartbeat = () => {
|
|
1259
1264
|
if (!this.leaseDeps.getTurnId() || this.heartbeatTimer) return;
|
|
1260
|
-
this.heartbeatTimer = setInterval(() => void this.renew("timer"),
|
|
1265
|
+
this.heartbeatTimer = setInterval(() => void this.renew("timer"), HEARTBEAT_INTERVAL_MS);
|
|
1261
1266
|
this.heartbeatTimer.unref?.();
|
|
1262
1267
|
};
|
|
1263
1268
|
stopHeartbeat = () => {
|
|
@@ -7654,6 +7659,7 @@ import {
|
|
|
7654
7659
|
sessionTurnHasFinalReplyNudge,
|
|
7655
7660
|
getSessionHumanInputRequest,
|
|
7656
7661
|
getWorkspace,
|
|
7662
|
+
listTurnCodemodeApprovals,
|
|
7657
7663
|
recordUsageEvent as recordUsageEvent3,
|
|
7658
7664
|
registerPendingSessionToolCall,
|
|
7659
7665
|
recordPendingSessionToolCallResult as recordPendingSessionToolCallResult2,
|
|
@@ -8080,6 +8086,34 @@ async function retentionTokenCounts(items, project2) {
|
|
|
8080
8086
|
return counts;
|
|
8081
8087
|
}
|
|
8082
8088
|
|
|
8089
|
+
// src/activities/programmatic-approvals.ts
|
|
8090
|
+
function programmaticApproval(operation) {
|
|
8091
|
+
return {
|
|
8092
|
+
id: operation.operationId,
|
|
8093
|
+
name: operation.identity.toolName,
|
|
8094
|
+
source: "codemode",
|
|
8095
|
+
operationId: operation.operationId,
|
|
8096
|
+
requestId: operation.approvalRequestId
|
|
8097
|
+
};
|
|
8098
|
+
}
|
|
8099
|
+
function programmaticContinuationNote(operations) {
|
|
8100
|
+
if (operations.length === 0) return void 0;
|
|
8101
|
+
return [
|
|
8102
|
+
"Stored programmatic operations (durable server receipts):",
|
|
8103
|
+
...operations.map(
|
|
8104
|
+
(operation) => `${operation.operationId}: ${operation.state}${operation.errorCode ? ` (${operation.errorCode})` : ""}`
|
|
8105
|
+
),
|
|
8106
|
+
"Approval resumes the stored operation, not the earlier program's JavaScript stack. Read results with the current Codemode client's status/resume handle. Do not resubmit arguments for completed, running, waiting, or uncertain operations."
|
|
8107
|
+
].join("\n");
|
|
8108
|
+
}
|
|
8109
|
+
async function recoverProgrammaticOperationsBeforeFirstRequest(input) {
|
|
8110
|
+
if (input.approvalDecisionId === void 0 && !await input.hasUnfinishedOperations()) {
|
|
8111
|
+
return [];
|
|
8112
|
+
}
|
|
8113
|
+
await input.toolPreparationReady;
|
|
8114
|
+
return await input.resumeApproved(input.approvalDecisionId) ?? [];
|
|
8115
|
+
}
|
|
8116
|
+
|
|
8083
8117
|
// src/activities/agent-turn/turn-sandbox-access.ts
|
|
8084
8118
|
function ownedTurnSandboxForAgent(sandboxState) {
|
|
8085
8119
|
return sandboxState.lazyOwnedSandbox ?? sandboxState.resolvedSandbox?.established;
|
|
@@ -8263,7 +8297,7 @@ async function resultItemForOpenSuffixMember(input) {
|
|
|
8263
8297
|
}
|
|
8264
8298
|
}
|
|
8265
8299
|
async function settleOpenSuffixResumeIfNeeded(input) {
|
|
8266
|
-
if (input.trigger.type !== "user.approvalDecision" && input.trigger.type !== "user.humanInputResponse") {
|
|
8300
|
+
if (input.trigger.type !== "user.approvalDecision" && input.trigger.type !== "user.humanInputResponse" && !input.additionalApprovals?.length) {
|
|
8267
8301
|
return { action: "continue" };
|
|
8268
8302
|
}
|
|
8269
8303
|
const rows = await listTurnOpenSuffixToolCalls(
|
|
@@ -8272,7 +8306,7 @@ async function settleOpenSuffixResumeIfNeeded(input) {
|
|
|
8272
8306
|
input.sessionId,
|
|
8273
8307
|
input.turnId
|
|
8274
8308
|
);
|
|
8275
|
-
if (rows.length === 0) {
|
|
8309
|
+
if (rows.length === 0 && !input.additionalApprovals?.length) {
|
|
8276
8310
|
return { action: "continue" };
|
|
8277
8311
|
}
|
|
8278
8312
|
const callId = matchingOpenSuffixCallId({
|
|
@@ -8280,96 +8314,108 @@ async function settleOpenSuffixResumeIfNeeded(input) {
|
|
|
8280
8314
|
humanInputToolCallId: input.humanInputResume?.toolCallId
|
|
8281
8315
|
});
|
|
8282
8316
|
const target = resolveOpenSuffixResumeTarget(rows, callId);
|
|
8283
|
-
if (!target || !callId) {
|
|
8317
|
+
if ((!target || !callId) && !input.programmaticApprovalAcknowledged && (input.trigger.type === "user.approvalDecision" || input.trigger.type === "user.humanInputResponse" || !input.additionalApprovals?.length)) {
|
|
8284
8318
|
throw new Error("Open suffix resume event does not match an interruption");
|
|
8285
8319
|
}
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8320
|
+
if (target && callId) {
|
|
8321
|
+
const truncationTokens = input.modelToolOutputTruncationTokens ?? target.modelToolOutputTruncationTokens ?? void 0;
|
|
8322
|
+
let resultItem = target.resultItem;
|
|
8323
|
+
let eventOutput = resultItem?.output;
|
|
8324
|
+
if (!resultItem) {
|
|
8325
|
+
const member = await resultItemForOpenSuffixMember({
|
|
8326
|
+
agent: input.agent,
|
|
8327
|
+
row: target,
|
|
8328
|
+
trigger: input.trigger,
|
|
8329
|
+
humanInputResume: input.humanInputResume
|
|
8330
|
+
});
|
|
8331
|
+
resultItem = member.resultItem;
|
|
8332
|
+
eventOutput = member.eventOutput;
|
|
8333
|
+
const recorded = await recordPendingSessionToolCallResult(input.db, {
|
|
8334
|
+
accountId: input.accountId,
|
|
8335
|
+
workspaceId: input.workspaceId,
|
|
8336
|
+
sessionId: input.sessionId,
|
|
8337
|
+
turnId: input.turnId,
|
|
8338
|
+
executionGeneration: input.executionGeneration,
|
|
8339
|
+
attemptId: input.attemptId,
|
|
8340
|
+
callId: target.callId,
|
|
8341
|
+
...truncationTokens !== void 0 ? { modelToolOutputTruncationTokens: truncationTokens } : {},
|
|
8342
|
+
resultItem,
|
|
8343
|
+
eventOutput
|
|
8344
|
+
});
|
|
8345
|
+
if (!recorded.accepted) {
|
|
8346
|
+
return { action: "cancelled" };
|
|
8347
|
+
}
|
|
8348
|
+
if (!recorded.recorded) {
|
|
8349
|
+
const latest = resolveOpenSuffixResumeTarget(
|
|
8350
|
+
await listTurnOpenSuffixToolCalls(
|
|
8351
|
+
input.db,
|
|
8352
|
+
input.workspaceId,
|
|
8353
|
+
input.sessionId,
|
|
8354
|
+
input.turnId
|
|
8355
|
+
),
|
|
8356
|
+
callId
|
|
8357
|
+
);
|
|
8358
|
+
resultItem = latest?.resultItem ?? resultItem;
|
|
8359
|
+
} else if (input.publish) {
|
|
8360
|
+
await input.publish([
|
|
8361
|
+
{
|
|
8362
|
+
type: "agent.toolCall.output",
|
|
8363
|
+
payload: { id: target.callId, output: eventOutput }
|
|
8364
|
+
}
|
|
8365
|
+
]);
|
|
8366
|
+
}
|
|
8331
8367
|
}
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
throw new Error(`Open suffix resume for ${target.callId} has no result item`);
|
|
8335
|
-
}
|
|
8336
|
-
const history = await getActiveSessionHistoryItems(input.db, input.workspaceId, input.sessionId);
|
|
8337
|
-
if (!openSuffixPairPresentInHistory(
|
|
8338
|
-
history.map((row) => row.item),
|
|
8339
|
-
callId
|
|
8340
|
-
)) {
|
|
8341
|
-
const historyItems = openSuffixHistoryItems(target, resultItem);
|
|
8342
|
-
if (historyItems.length === 0) {
|
|
8343
|
-
throw new Error(`Open suffix resume for ${target.callId} produced no paired history`);
|
|
8368
|
+
if (!resultItem) {
|
|
8369
|
+
throw new Error(`Open suffix resume for ${target.callId} has no result item`);
|
|
8344
8370
|
}
|
|
8345
|
-
const
|
|
8371
|
+
const history = await getActiveSessionHistoryItems(
|
|
8346
8372
|
input.db,
|
|
8347
8373
|
input.workspaceId,
|
|
8348
8374
|
input.sessionId
|
|
8349
8375
|
);
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8376
|
+
if (!openSuffixPairPresentInHistory(
|
|
8377
|
+
history.map((row) => row.item),
|
|
8378
|
+
callId
|
|
8379
|
+
)) {
|
|
8380
|
+
const historyItems = openSuffixHistoryItems(target, resultItem);
|
|
8381
|
+
if (historyItems.length === 0) {
|
|
8382
|
+
throw new Error(`Open suffix resume for ${target.callId} produced no paired history`);
|
|
8383
|
+
}
|
|
8384
|
+
const nextPosition = await nextSessionHistoryPosition(
|
|
8385
|
+
input.db,
|
|
8386
|
+
input.workspaceId,
|
|
8387
|
+
input.sessionId
|
|
8388
|
+
);
|
|
8389
|
+
const appended = await appendSessionHistoryItems2(input.db, {
|
|
8390
|
+
accountId: input.accountId,
|
|
8391
|
+
workspaceId: input.workspaceId,
|
|
8392
|
+
sessionId: input.sessionId,
|
|
8393
|
+
turnId: input.turnId,
|
|
8394
|
+
expectedExecutionGeneration: input.executionGeneration,
|
|
8395
|
+
expectedAttemptId: input.attemptId,
|
|
8396
|
+
...truncationTokens !== void 0 ? { modelToolOutputTruncationTokens: truncationTokens } : {},
|
|
8397
|
+
items: historyItems.map((item, offset) => ({
|
|
8398
|
+
position: nextPosition + offset,
|
|
8399
|
+
item
|
|
8400
|
+
}))
|
|
8401
|
+
});
|
|
8402
|
+
if (!appended) {
|
|
8403
|
+
return { action: "cancelled" };
|
|
8404
|
+
}
|
|
8365
8405
|
}
|
|
8366
8406
|
}
|
|
8367
8407
|
const remaining = (await listTurnOpenSuffixToolCalls(input.db, input.workspaceId, input.sessionId, input.turnId)).filter((row) => row.resultItem == null);
|
|
8368
|
-
if (remaining.length === 0) {
|
|
8408
|
+
if (remaining.length === 0 && !input.additionalApprovals?.length) {
|
|
8369
8409
|
return { action: "continue" };
|
|
8370
8410
|
}
|
|
8371
|
-
const requiresActionApprovals =
|
|
8372
|
-
|
|
8411
|
+
const requiresActionApprovals = [
|
|
8412
|
+
...remainingPendingApprovalsFromSuffix(remaining),
|
|
8413
|
+
...input.additionalApprovals ?? []
|
|
8414
|
+
];
|
|
8415
|
+
const pendingApprovals = [
|
|
8416
|
+
...remainingRunStatePendingApprovalsFromSuffix(remaining),
|
|
8417
|
+
...input.additionalApprovals ?? []
|
|
8418
|
+
];
|
|
8373
8419
|
const settled = await input.settle({
|
|
8374
8420
|
events: [
|
|
8375
8421
|
...requiresActionApprovals.length > 0 ? [
|
|
@@ -8997,6 +9043,8 @@ async function runTurnStreamAttempt(deps) {
|
|
|
8997
9043
|
await parallelSessionTitle?.cancel();
|
|
8998
9044
|
};
|
|
8999
9045
|
let runInput = null;
|
|
9046
|
+
let codemodeContinuationNote;
|
|
9047
|
+
let programmaticApprovalAcknowledged = false;
|
|
9000
9048
|
const prepareRunAttemptInput = async () => {
|
|
9001
9049
|
const historyPreparationStartedAt = performance.now();
|
|
9002
9050
|
let historyPreparationOutcome = "completed";
|
|
@@ -9009,6 +9057,8 @@ async function runTurnStreamAttempt(deps) {
|
|
|
9009
9057
|
subjectId: fileAuthoritySubjectId
|
|
9010
9058
|
},
|
|
9011
9059
|
recovering: turn.executionGeneration > 1,
|
|
9060
|
+
programmaticApprovalAcknowledged,
|
|
9061
|
+
...codemodeContinuationNote ? { codemodeContinuationNote } : {},
|
|
9012
9062
|
...unavailableSandboxFilesNote ? { unavailableSandboxFilesNote } : {},
|
|
9013
9063
|
...runCredentialsNote ? { runCredentialsNote } : {},
|
|
9014
9064
|
...mcpAvailabilityNote ? { mcpAvailabilityNote } : {},
|
|
@@ -9967,10 +10017,17 @@ async function runTurnStreamAttempt(deps) {
|
|
|
9967
10017
|
});
|
|
9968
10018
|
}
|
|
9969
10019
|
}
|
|
9970
|
-
|
|
10020
|
+
const programmaticPending = (await listTurnCodemodeApprovals(db, {
|
|
10021
|
+
accountId: input.accountId,
|
|
10022
|
+
workspaceId: input.workspaceId,
|
|
10023
|
+
sessionId: input.sessionId,
|
|
10024
|
+
turnId: activeTurnId
|
|
10025
|
+
})).filter((operation) => operation.state === "waiting_for_approval").map(programmaticApproval);
|
|
10026
|
+
if (eventing.stream.interruptions.length > 0 || programmaticPending.length > 0) {
|
|
9971
10027
|
await eventing.preparedTools?.inputWaitYield?.sealForSettlement(runtimeCancellationSignal);
|
|
9972
10028
|
await historySink.reconcileConversationTruth({ requireDurable: true });
|
|
9973
|
-
const
|
|
10029
|
+
const sdkApprovals = runtime.serializeApprovals(eventing.stream.interruptions);
|
|
10030
|
+
const approvals = [...sdkApprovals, ...programmaticPending];
|
|
9974
10031
|
const humanInputInterruptions = runtime.serializeHumanInputRequests?.(eventing.stream.interruptions) ?? [];
|
|
9975
10032
|
const interactionInterventionInterruptions = runtime.serializeInteractionInterventionRequests?.(eventing.stream.interruptions) ?? [];
|
|
9976
10033
|
const latestWorkspace = await getWorkspace(db, input.workspaceId);
|
|
@@ -10042,11 +10099,14 @@ async function runTurnStreamAttempt(deps) {
|
|
|
10042
10099
|
const interruptionCallIds = interruptionCallIdsFromPause({
|
|
10043
10100
|
humanInputRequests,
|
|
10044
10101
|
interactionInterventionRequests,
|
|
10045
|
-
pendingApprovals
|
|
10102
|
+
pendingApprovals: [
|
|
10103
|
+
...sdkApprovals,
|
|
10104
|
+
...interactionInterventionInterruptions.map((interruption) => interruption.approval)
|
|
10105
|
+
]
|
|
10046
10106
|
});
|
|
10047
10107
|
assertOpenSuffixResumable(suffixMembers, interruptionCallIds);
|
|
10048
10108
|
const suffixByCallId = new Map(suffixMembers.map((member) => [member.callId, member]));
|
|
10049
|
-
const attached = await attachOpenSuffixToPendingToolCalls(db, {
|
|
10109
|
+
const attached = interruptionCallIds.length === 0 ? { accepted: true } : await attachOpenSuffixToPendingToolCalls(db, {
|
|
10050
10110
|
accountId: input.accountId,
|
|
10051
10111
|
workspaceId: input.workspaceId,
|
|
10052
10112
|
sessionId: input.sessionId,
|
|
@@ -10203,7 +10263,41 @@ async function runTurnStreamAttempt(deps) {
|
|
|
10203
10263
|
control.activityStatus = "idle";
|
|
10204
10264
|
return claimedResult({ status: "idle" });
|
|
10205
10265
|
};
|
|
10266
|
+
const programmaticRecoveryStartedAt = performance.now();
|
|
10267
|
+
let programmaticRecoveryOutcome = "failed";
|
|
10268
|
+
const codemodeOperations = await recoverProgrammaticOperationsBeforeFirstRequest({
|
|
10269
|
+
approvalDecisionId: trigger.type === "user.approvalDecision" ? trigger.payload.approvalId : void 0,
|
|
10270
|
+
hasUnfinishedOperations: async () => (await listTurnCodemodeApprovals(db, {
|
|
10271
|
+
accountId: input.accountId,
|
|
10272
|
+
workspaceId: input.workspaceId,
|
|
10273
|
+
sessionId: input.sessionId,
|
|
10274
|
+
turnId: activeTurnId
|
|
10275
|
+
})).length > 0,
|
|
10276
|
+
toolPreparationReady: eventing.toolPreparationReady,
|
|
10277
|
+
resumeApproved: (decisionOperationId) => eventing.codemodeDispatcher?.resumeApproved(
|
|
10278
|
+
`sandbox:${input.attemptId}`,
|
|
10279
|
+
decisionOperationId
|
|
10280
|
+
)
|
|
10281
|
+
}).then((operations) => {
|
|
10282
|
+
programmaticRecoveryOutcome = "completed";
|
|
10283
|
+
return operations;
|
|
10284
|
+
}).finally(() => {
|
|
10285
|
+
recordTurnStartupPhase(observability, {
|
|
10286
|
+
phase: "programmatic_operation_recovery",
|
|
10287
|
+
provider: turnExecutionPolicy.providerId,
|
|
10288
|
+
backend: activeSandboxBackend ?? groupBoxBackend,
|
|
10289
|
+
outcome: programmaticRecoveryOutcome,
|
|
10290
|
+
durationSeconds: (performance.now() - programmaticRecoveryStartedAt) / 1e3
|
|
10291
|
+
});
|
|
10292
|
+
});
|
|
10293
|
+
codemodeContinuationNote = programmaticContinuationNote(codemodeOperations);
|
|
10294
|
+
programmaticApprovalAcknowledged = trigger.type === "user.approvalDecision" && codemodeOperations.some(
|
|
10295
|
+
(operation) => operation.operationId === trigger.payload.approvalId
|
|
10296
|
+
);
|
|
10297
|
+
const pendingProgrammaticApprovals = codemodeOperations.filter((operation) => operation.state === "waiting_for_approval").map(programmaticApproval);
|
|
10206
10298
|
const openSuffixResume = await settleOpenSuffixResumeIfNeeded({
|
|
10299
|
+
additionalApprovals: pendingProgrammaticApprovals,
|
|
10300
|
+
programmaticApprovalAcknowledged,
|
|
10207
10301
|
db,
|
|
10208
10302
|
agent,
|
|
10209
10303
|
accountId: input.accountId,
|
|
@@ -12187,6 +12281,7 @@ import {
|
|
|
12187
12281
|
desktopCapableBackend
|
|
12188
12282
|
} from "@opengeni/runtime";
|
|
12189
12283
|
import {
|
|
12284
|
+
configuredModelForAcceptedTurnExecutionPolicy,
|
|
12190
12285
|
isDirectOpenAiApiBaseUrl
|
|
12191
12286
|
} from "@opengeni/config";
|
|
12192
12287
|
|
|
@@ -12463,6 +12558,16 @@ function shouldDeferNonEagerToolPreparation(args) {
|
|
|
12463
12558
|
args.lazyToolTransport && args.progressiveDisclosureEnabled && args.triggerKind === "next" && (args.triggerType === "user.message" || args.triggerType === "system.update.delivered")
|
|
12464
12559
|
);
|
|
12465
12560
|
}
|
|
12561
|
+
function resolveAcceptedTurnModel(runtime, settings, policy) {
|
|
12562
|
+
const current = runtime.resolveTurnModel(settings, policy.productModelId);
|
|
12563
|
+
if (!current) return null;
|
|
12564
|
+
const configured = configuredModelForAcceptedTurnExecutionPolicy(
|
|
12565
|
+
current.configured,
|
|
12566
|
+
current.provider,
|
|
12567
|
+
policy
|
|
12568
|
+
);
|
|
12569
|
+
return configured === current.configured ? current : { ...current, configured };
|
|
12570
|
+
}
|
|
12466
12571
|
function hostedWebSearchForTurn(resolvedModel, deploymentWebSearchEnabled) {
|
|
12467
12572
|
return resolvedModel?.configured.hostedWebSearch ?? deploymentWebSearchEnabled;
|
|
12468
12573
|
}
|
|
@@ -12486,9 +12591,8 @@ function modelSupportsImageInputForTurn(resolvedModel) {
|
|
|
12486
12591
|
return resolvedModel === null || resolvedModel.configured.capabilities?.inputModalities.includes("image") !== false;
|
|
12487
12592
|
}
|
|
12488
12593
|
function modelAttachmentInputPolicyForTurn(resolvedModel) {
|
|
12489
|
-
const typedTransport = resolvedModel === null || resolvedModel.provider.api === "responses" || resolvedModel.provider.api === "anthropic-messages";
|
|
12490
12594
|
return {
|
|
12491
|
-
supportsImageInput:
|
|
12595
|
+
supportsImageInput: modelSupportsImageInputForTurn(resolvedModel),
|
|
12492
12596
|
inputFileMediaTypes: []
|
|
12493
12597
|
};
|
|
12494
12598
|
}
|
|
@@ -12654,10 +12758,7 @@ async function prepareGovernanceAndModel(deps) {
|
|
|
12654
12758
|
baseRunSettings
|
|
12655
12759
|
)
|
|
12656
12760
|
);
|
|
12657
|
-
const resolvedModel = runtime
|
|
12658
|
-
capabilitySettings,
|
|
12659
|
-
turnExecutionPolicy.productModelId
|
|
12660
|
-
);
|
|
12761
|
+
const resolvedModel = resolveAcceptedTurnModel(runtime, capabilitySettings, turnExecutionPolicy);
|
|
12661
12762
|
const providerApi = resolvedModel?.provider.api ?? "responses";
|
|
12662
12763
|
const nativeImageProviderBinding = providerApi === "responses" ? openAiHostedImageProviderBindingForTurn(capabilitySettings, resolvedModel) : null;
|
|
12663
12764
|
const lazyToolTransport = lazyToolTransportForTurn(resolvedModel);
|
|
@@ -13417,6 +13518,7 @@ import {
|
|
|
13417
13518
|
readLease as readLease2,
|
|
13418
13519
|
accrueWarmSeconds,
|
|
13419
13520
|
SandboxWorkspaceMutationFencedError,
|
|
13521
|
+
SandboxWorkspaceMutationOutputRejectedError,
|
|
13420
13522
|
retainWorkspaceMutationProcess,
|
|
13421
13523
|
retainedProviderCommandPersistence,
|
|
13422
13524
|
SandboxRetainedProcessPromotionFencedError
|
|
@@ -13424,6 +13526,7 @@ import {
|
|
|
13424
13526
|
import { createProviderCommandRetainer } from "@opengeni/db/retained-provider-commands";
|
|
13425
13527
|
import {
|
|
13426
13528
|
RoutingMutationOutcomeUnknownError,
|
|
13529
|
+
RoutingMutationOutputRejectedError,
|
|
13427
13530
|
ProviderCommandStartOutcomeUnknownError,
|
|
13428
13531
|
ProviderCommandObservationUnavailableError,
|
|
13429
13532
|
isModalCommandStartOutcomeUnknownError as isModalCommandStartOutcomeUnknownError2,
|
|
@@ -13836,6 +13939,17 @@ function createSandboxTurnRuntime(deps) {
|
|
|
13836
13939
|
try {
|
|
13837
13940
|
await settleMutation("resolved");
|
|
13838
13941
|
} catch (settlementError) {
|
|
13942
|
+
if (settlementError instanceof SandboxWorkspaceMutationOutputRejectedError && settlementError.matchesPhysicalSettlement({
|
|
13943
|
+
accountId: identity.accountId,
|
|
13944
|
+
workspaceId: identity.workspaceId,
|
|
13945
|
+
admission,
|
|
13946
|
+
operation,
|
|
13947
|
+
outcome: "resolved"
|
|
13948
|
+
})) {
|
|
13949
|
+
throw new RoutingMutationOutputRejectedError(operation, settlementError.code, {
|
|
13950
|
+
cause: settlementError
|
|
13951
|
+
});
|
|
13952
|
+
}
|
|
13839
13953
|
throw new RoutingMutationOutcomeUnknownError(
|
|
13840
13954
|
operation,
|
|
13841
13955
|
`Platform workspace mutation "${operation}" returned from the provider but lost its durable settlement fence; its outcome is unknown and it was not replayed`,
|
|
@@ -32710,7 +32824,8 @@ import {
|
|
|
32710
32824
|
} from "@opengeni/runtime";
|
|
32711
32825
|
import {
|
|
32712
32826
|
ChannelAPartialMutationError as ChannelAPartialMutationError2,
|
|
32713
|
-
RoutingMutationOutcomeUnknownError as RoutingMutationOutcomeUnknownError2
|
|
32827
|
+
RoutingMutationOutcomeUnknownError as RoutingMutationOutcomeUnknownError2,
|
|
32828
|
+
isRoutingMutationOutputRejectedError
|
|
32714
32829
|
} from "@opengeni/runtime/sandbox";
|
|
32715
32830
|
import { connectorAttachmentSandboxPath as connectorAttachmentSandboxPath2 } from "@opengeni/runtime";
|
|
32716
32831
|
var ConnectorAttachmentMaterializationError = class extends Error {
|
|
@@ -32819,7 +32934,7 @@ async function materializeConnectorAttachmentsInChannel(channel, request, option
|
|
|
32819
32934
|
attachments: receipts
|
|
32820
32935
|
});
|
|
32821
32936
|
} catch (error51) {
|
|
32822
|
-
if (error51 instanceof ChannelAPartialMutationError2 || error51 instanceof RoutingMutationOutcomeUnknownError2) {
|
|
32937
|
+
if (error51 instanceof ChannelAPartialMutationError2 || error51 instanceof RoutingMutationOutcomeUnknownError2 || isRoutingMutationOutputRejectedError(error51)) {
|
|
32823
32938
|
throw error51;
|
|
32824
32939
|
}
|
|
32825
32940
|
throw new ConnectorAttachmentMaterializationError();
|
|
@@ -32894,7 +33009,12 @@ import { allowedFirstPartyMcpToolsForSession } from "@opengeni/config";
|
|
|
32894
33009
|
|
|
32895
33010
|
// src/activities/codemode-dispatcher.ts
|
|
32896
33011
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
32897
|
-
import {
|
|
33012
|
+
import {
|
|
33013
|
+
bindMcpTelemetry,
|
|
33014
|
+
measureMcpPhase as measureMcpPhase2,
|
|
33015
|
+
withMcpCallIdentity as withMcpCallIdentity2,
|
|
33016
|
+
recordToolApproval
|
|
33017
|
+
} from "@opengeni/observability";
|
|
32898
33018
|
import {
|
|
32899
33019
|
AttemptToolApprovalRequiredError,
|
|
32900
33020
|
AttemptToolCatalogStaleError,
|
|
@@ -32907,10 +33027,16 @@ import {
|
|
|
32907
33027
|
import {
|
|
32908
33028
|
CODEMODE_CLAIM_LEASE_MS,
|
|
32909
33029
|
CODEMODE_CLAIM_HEARTBEAT_MS,
|
|
32910
|
-
CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT
|
|
33030
|
+
CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT,
|
|
33031
|
+
CodemodeOperation
|
|
32911
33032
|
} from "@opengeni/contracts";
|
|
32912
33033
|
import {
|
|
32913
33034
|
cancelQueuedCodemodeOperationsForAttempt,
|
|
33035
|
+
waitForCodemodeApproval,
|
|
33036
|
+
bindCodemodePreparation,
|
|
33037
|
+
listTurnCodemodeApprovals as listTurnCodemodeApprovals2,
|
|
33038
|
+
adoptCodemodeApprovalWithOutput,
|
|
33039
|
+
readTurnCodemodeOperation,
|
|
32914
33040
|
claimCodemodeOperation,
|
|
32915
33041
|
failCodemodeOperation,
|
|
32916
33042
|
getSessionEventByClientEventId,
|
|
@@ -32924,7 +33050,7 @@ import {
|
|
|
32924
33050
|
publishDurableSessionEvents as publishDurableSessionEvents8
|
|
32925
33051
|
} from "@opengeni/events";
|
|
32926
33052
|
var CodemodeAttemptDispatcher = class {
|
|
32927
|
-
constructor(db, bus, environment, scope, turnSignal, maxConcurrentCalls = CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT, timings = {}, toolDisplayMetadata, toolFamily) {
|
|
33053
|
+
constructor(db, bus, environment, scope, turnSignal, maxConcurrentCalls = CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT, timings = {}, toolDisplayMetadata, toolFamily, approvalWait) {
|
|
32928
33054
|
this.db = db;
|
|
32929
33055
|
this.bus = bus;
|
|
32930
33056
|
this.environment = environment;
|
|
@@ -32933,6 +33059,7 @@ var CodemodeAttemptDispatcher = class {
|
|
|
32933
33059
|
this.maxConcurrentCalls = maxConcurrentCalls;
|
|
32934
33060
|
this.toolDisplayMetadata = toolDisplayMetadata;
|
|
32935
33061
|
this.toolFamily = toolFamily;
|
|
33062
|
+
this.approvalWait = approvalWait;
|
|
32936
33063
|
if (environment.catalog.accountId !== scope.accountId || environment.catalog.workspaceId !== scope.workspaceId || environment.catalog.sessionId !== scope.sessionId || environment.catalog.turnId !== scope.turnId || environment.catalog.attemptId !== scope.attemptId || environment.catalog.executionGeneration !== scope.executionGeneration) {
|
|
32937
33064
|
throw new Error("Codemode dispatcher scope does not match its tool environment");
|
|
32938
33065
|
}
|
|
@@ -33022,6 +33149,76 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33022
33149
|
})
|
|
33023
33150
|
);
|
|
33024
33151
|
}
|
|
33152
|
+
async resumeApproved(callerSubjectId, decisionOperationId) {
|
|
33153
|
+
const operations = await listTurnCodemodeApprovals2(this.db, this.scope);
|
|
33154
|
+
if (decisionOperationId && // Model-tool approval IDs are opaque strings. Only programmatic UUIDs
|
|
33155
|
+
// can address the Codemode operation journal.
|
|
33156
|
+
CodemodeOperation.shape.operationId.safeParse(decisionOperationId).success && !operations.some((operation) => operation.operationId === decisionOperationId)) {
|
|
33157
|
+
const decided = await readTurnCodemodeOperation(this.db, {
|
|
33158
|
+
...this.scope,
|
|
33159
|
+
callerSubjectId,
|
|
33160
|
+
operationId: decisionOperationId
|
|
33161
|
+
});
|
|
33162
|
+
if (decided) operations.push(decided);
|
|
33163
|
+
}
|
|
33164
|
+
for (const operation of operations) {
|
|
33165
|
+
if (!["waiting_for_approval", "queued", "running"].includes(operation.state)) continue;
|
|
33166
|
+
let effectDigest = null;
|
|
33167
|
+
try {
|
|
33168
|
+
effectDigest = this.environment.effectDigest(operation.identity);
|
|
33169
|
+
} catch {
|
|
33170
|
+
}
|
|
33171
|
+
const continuation = await adoptCodemodeApprovalWithOutput(this.db, {
|
|
33172
|
+
...this.scope,
|
|
33173
|
+
operationId: operation.operationId,
|
|
33174
|
+
callerSubjectId,
|
|
33175
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33176
|
+
effectDigest
|
|
33177
|
+
});
|
|
33178
|
+
await publishDurableSessionEvents8(
|
|
33179
|
+
this.bus,
|
|
33180
|
+
this.scope.workspaceId,
|
|
33181
|
+
this.scope.sessionId,
|
|
33182
|
+
continuation.events
|
|
33183
|
+
);
|
|
33184
|
+
const adopted = continuation.operation;
|
|
33185
|
+
if (adopted && adopted.state !== operation.state) {
|
|
33186
|
+
const outcome = adopted.state === "queued" ? "resumed" : adopted.state === "outcome_unknown" ? "unknown" : adopted.errorCode === "approval_stale" ? "stale" : "rejected";
|
|
33187
|
+
recordToolApproval(
|
|
33188
|
+
outcome,
|
|
33189
|
+
"continuation",
|
|
33190
|
+
operation.state === "waiting_for_approval" ? Math.max(0, Date.now() - Date.parse(operation.updatedAt)) : void 0
|
|
33191
|
+
);
|
|
33192
|
+
}
|
|
33193
|
+
if (adopted?.state !== "queued") continue;
|
|
33194
|
+
const claim = await claimCodemodeOperation(this.db, {
|
|
33195
|
+
...this.scope,
|
|
33196
|
+
operationId: adopted.operationId,
|
|
33197
|
+
claimId: randomUUID3(),
|
|
33198
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33199
|
+
claimLeaseMs: this.claimLeaseMs
|
|
33200
|
+
});
|
|
33201
|
+
if (claim.status === "claimed") {
|
|
33202
|
+
const execution = this.execute(claim.operation, claim.claimId, true);
|
|
33203
|
+
this.inFlight.set(adopted.operationId, execution);
|
|
33204
|
+
try {
|
|
33205
|
+
await execution;
|
|
33206
|
+
} finally {
|
|
33207
|
+
this.inFlight.delete(adopted.operationId);
|
|
33208
|
+
}
|
|
33209
|
+
}
|
|
33210
|
+
}
|
|
33211
|
+
const receipts = [];
|
|
33212
|
+
for (const operation of operations) {
|
|
33213
|
+
const receipt = await readTurnCodemodeOperation(this.db, {
|
|
33214
|
+
...this.scope,
|
|
33215
|
+
callerSubjectId,
|
|
33216
|
+
operationId: operation.operationId
|
|
33217
|
+
});
|
|
33218
|
+
if (receipt) receipts.push(receipt);
|
|
33219
|
+
}
|
|
33220
|
+
return receipts;
|
|
33221
|
+
}
|
|
33025
33222
|
async close(reason = "Execution attempt ended") {
|
|
33026
33223
|
if (this.closing) {
|
|
33027
33224
|
await Promise.allSettled([...this.inFlight.values()]);
|
|
@@ -33102,18 +33299,51 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33102
33299
|
return;
|
|
33103
33300
|
}
|
|
33104
33301
|
let preparedCall;
|
|
33302
|
+
let releaseWait;
|
|
33105
33303
|
try {
|
|
33304
|
+
if (operation.durableApproval) {
|
|
33305
|
+
if (!this.approvalWait) throw new Error("Durable approval yield is unavailable");
|
|
33306
|
+
releaseWait = this.approvalWait.beginWait();
|
|
33307
|
+
if (!await bindCodemodePreparation(this.db, {
|
|
33308
|
+
...this.scope,
|
|
33309
|
+
operationId: operation.operationId,
|
|
33310
|
+
claimId,
|
|
33311
|
+
effectDigest: this.environment.effectDigest(operation.identity)
|
|
33312
|
+
}))
|
|
33313
|
+
throw new Error("Operation preparation is stale");
|
|
33314
|
+
}
|
|
33106
33315
|
preparedCall = await this.environment.prepareCall(
|
|
33107
33316
|
{
|
|
33108
33317
|
operationId: operation.operationId,
|
|
33109
|
-
catalogDigest:
|
|
33318
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33110
33319
|
identity: operation.identity,
|
|
33111
33320
|
arguments: operation.arguments,
|
|
33112
|
-
caller:
|
|
33321
|
+
caller: {
|
|
33322
|
+
kind: "codemode",
|
|
33323
|
+
subjectId: operation.caller.subjectId === `sandbox:${operation.attemptId}` ? `sandbox:${this.scope.attemptId}` : operation.caller.subjectId
|
|
33324
|
+
}
|
|
33113
33325
|
},
|
|
33114
|
-
{
|
|
33326
|
+
{
|
|
33327
|
+
signal,
|
|
33328
|
+
...operation.durableApproval ? { transportMeta: { durableApproval: true } } : {}
|
|
33329
|
+
}
|
|
33115
33330
|
);
|
|
33331
|
+
if (preparedCall.waitingForApproval) {
|
|
33332
|
+
const waiting = await waitForCodemodeApproval(this.db, {
|
|
33333
|
+
...this.scope,
|
|
33334
|
+
operationId: operation.operationId,
|
|
33335
|
+
claimId,
|
|
33336
|
+
...preparedCall.waitingForApproval,
|
|
33337
|
+
effectDigest: preparedCall.effectDigest
|
|
33338
|
+
});
|
|
33339
|
+
if (!waiting) throw new Error("Approval could not be bound to the operation");
|
|
33340
|
+
recordToolApproval("waiting");
|
|
33341
|
+
releaseWait?.(true);
|
|
33342
|
+
return;
|
|
33343
|
+
}
|
|
33344
|
+
releaseWait?.(false);
|
|
33116
33345
|
} catch (error51) {
|
|
33346
|
+
releaseWait?.(false);
|
|
33117
33347
|
await this.settleWithOutput(operation, claimId, {
|
|
33118
33348
|
state: "failed",
|
|
33119
33349
|
errorCode: errorCode(error51, signal, false),
|
|
@@ -33244,6 +33474,7 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33244
33474
|
settlement
|
|
33245
33475
|
});
|
|
33246
33476
|
if (!result.committed || result.events.length === 0) return;
|
|
33477
|
+
recordToolApproval(settlement.state === "outcome_unknown" ? "unknown" : settlement.state);
|
|
33247
33478
|
await publishDurableSessionEvents8(
|
|
33248
33479
|
this.bus,
|
|
33249
33480
|
this.scope.workspaceId,
|
|
@@ -33270,7 +33501,7 @@ function codemodeToolCallCreatedClientEventId(operationId) {
|
|
|
33270
33501
|
function assertMatchingCodemodeToolCallCreated(event, operation, entry, scope) {
|
|
33271
33502
|
const payload = recordValue(event.payload);
|
|
33272
33503
|
const raw = recordValue(payload?.raw);
|
|
33273
|
-
if (event.type !== "agent.toolCall.created" || event.turnId !== scope.turnId || event.turnGeneration !==
|
|
33504
|
+
if (event.type !== "agent.toolCall.created" || event.turnId !== scope.turnId || event.turnGeneration !== operation.executionGeneration || event.turnAttemptId !== operation.attemptId || event.turnAssociation !== "current" || payload?.id !== operation.operationId || payload?.name !== entry.modelName || payload?.origin !== "codemode" || payload?.subjectId !== operation.caller.subjectId || raw?.type !== "codemode_call" || raw?.serverId !== operation.identity.serverId || raw?.toolName !== operation.identity.toolName || raw?.catalogDigest !== operation.catalogDigest) {
|
|
33274
33505
|
throw new Error("Codemode tool-call creation id is bound to incompatible durable evidence");
|
|
33275
33506
|
}
|
|
33276
33507
|
}
|
|
@@ -33317,7 +33548,8 @@ import {
|
|
|
33317
33548
|
resolveTurnToolPolicy,
|
|
33318
33549
|
scheduledTurnMcpServerIds,
|
|
33319
33550
|
hasPermission as hasPermission2,
|
|
33320
|
-
requireExplicitPermissionDelegation
|
|
33551
|
+
requireExplicitPermissionDelegation,
|
|
33552
|
+
createWebSearchBilling
|
|
33321
33553
|
} from "@opengeni/core";
|
|
33322
33554
|
import { SandboxChannelAService as SandboxChannelAService3 } from "@opengeni/runtime/sandbox";
|
|
33323
33555
|
import { sandboxRunAs as sandboxRunAs4 } from "@opengeni/runtime";
|
|
@@ -33639,6 +33871,200 @@ function codeSearchToolDefinitions(input) {
|
|
|
33639
33871
|
];
|
|
33640
33872
|
}
|
|
33641
33873
|
|
|
33874
|
+
// src/activities/agent-turn/web-search.ts
|
|
33875
|
+
import {
|
|
33876
|
+
WEB_FETCH_TOOL_NAME,
|
|
33877
|
+
WEB_SEARCH_TOOL_NAME,
|
|
33878
|
+
webSearchCallPricing,
|
|
33879
|
+
webSearchCreditMicros,
|
|
33880
|
+
webSearchProviderConfig,
|
|
33881
|
+
webSearchToolPlan
|
|
33882
|
+
} from "@opengeni/config";
|
|
33883
|
+
import {
|
|
33884
|
+
WebSearchBillingRefusedError
|
|
33885
|
+
} from "@opengeni/core";
|
|
33886
|
+
import {
|
|
33887
|
+
WEB_FETCH_TOOL_DESCRIPTION,
|
|
33888
|
+
WEB_FETCH_RETAINED_MAX_CHARS,
|
|
33889
|
+
WEB_SEARCH_TOOL_DESCRIPTION,
|
|
33890
|
+
WebSearchProviderError,
|
|
33891
|
+
WebToolArgumentError,
|
|
33892
|
+
createWebFetchProvider,
|
|
33893
|
+
createWebSearchProvider,
|
|
33894
|
+
parseWebFetchArguments,
|
|
33895
|
+
parseWebSearchArguments,
|
|
33896
|
+
renderWebPageWindow,
|
|
33897
|
+
renderWebSearchResults,
|
|
33898
|
+
webFetchInputSchema,
|
|
33899
|
+
webSearchInputSchema
|
|
33900
|
+
} from "@opengeni/runtime/web-search";
|
|
33901
|
+
function turnWebSearchPlan(resolvedModel, settings) {
|
|
33902
|
+
return webSearchToolPlan(settings, {
|
|
33903
|
+
hostedWebSearch: hostedWebSearchForTurn(resolvedModel, settings.webSearchEnabled),
|
|
33904
|
+
// SuperGrok's native search is added by its transport, not as an agent
|
|
33905
|
+
// tool, so provider tools would only duplicate it.
|
|
33906
|
+
transportHostedSearch: resolvedModel?.provider.kind === "xai-subscription"
|
|
33907
|
+
});
|
|
33908
|
+
}
|
|
33909
|
+
var PAGE_CACHE_ENTRIES = 16;
|
|
33910
|
+
function textResult2(text, isError) {
|
|
33911
|
+
return { isError, content: [{ type: "text", text }] };
|
|
33912
|
+
}
|
|
33913
|
+
function settledCost(operationId, operation, provider, pricing, reportedCostMicros) {
|
|
33914
|
+
const basis = pricing.explicit ? "configured_price" : reportedCostMicros !== void 0 ? "provider_reported" : "list_price";
|
|
33915
|
+
const providerMicros = basis === "provider_reported" ? reportedCostMicros : pricing.providerMicros;
|
|
33916
|
+
return {
|
|
33917
|
+
operationId,
|
|
33918
|
+
operation,
|
|
33919
|
+
provider,
|
|
33920
|
+
providerMicros,
|
|
33921
|
+
creditMicros: webSearchCreditMicros(providerMicros, pricing.marginBps),
|
|
33922
|
+
marginBps: pricing.marginBps,
|
|
33923
|
+
basis
|
|
33924
|
+
};
|
|
33925
|
+
}
|
|
33926
|
+
function providerFailure(error51) {
|
|
33927
|
+
return `${error51.message}${error51.retryable ? ". You may retry shortly." : "."}`;
|
|
33928
|
+
}
|
|
33929
|
+
function webSearchToolDefinitions(input) {
|
|
33930
|
+
const config2 = webSearchProviderConfig(input.settings);
|
|
33931
|
+
if (!config2 || input.tools.length === 0) return [];
|
|
33932
|
+
const adapterInput = {
|
|
33933
|
+
timeoutMs: config2.timeoutMs,
|
|
33934
|
+
...input.fetch ? { fetch: input.fetch } : {}
|
|
33935
|
+
};
|
|
33936
|
+
const settle = async (cost) => {
|
|
33937
|
+
try {
|
|
33938
|
+
await input.billing.settle(input.scope, cost);
|
|
33939
|
+
} catch (error51) {
|
|
33940
|
+
input.observability.warn("web search usage settlement failed", {
|
|
33941
|
+
operation: cost.operation,
|
|
33942
|
+
provider: cost.provider,
|
|
33943
|
+
error: error51 instanceof Error ? error51.message : String(error51)
|
|
33944
|
+
});
|
|
33945
|
+
}
|
|
33946
|
+
};
|
|
33947
|
+
const definitions = [];
|
|
33948
|
+
if (input.tools.includes(WEB_SEARCH_TOOL_NAME)) {
|
|
33949
|
+
const provider = createWebSearchProvider({ ...adapterInput, endpoint: config2.search });
|
|
33950
|
+
const pricing = webSearchCallPricing(config2, "search");
|
|
33951
|
+
definitions.push({
|
|
33952
|
+
identity: { serverId: "opengeni", toolName: WEB_SEARCH_TOOL_NAME },
|
|
33953
|
+
modelName: WEB_SEARCH_TOOL_NAME,
|
|
33954
|
+
codemodePath: ["opengeni", WEB_SEARCH_TOOL_NAME],
|
|
33955
|
+
title: "Search the web",
|
|
33956
|
+
description: WEB_SEARCH_TOOL_DESCRIPTION,
|
|
33957
|
+
inputSchema: webSearchInputSchema,
|
|
33958
|
+
annotations: {
|
|
33959
|
+
title: "Search the web",
|
|
33960
|
+
readOnlyHint: true,
|
|
33961
|
+
destructiveHint: false,
|
|
33962
|
+
idempotentHint: true,
|
|
33963
|
+
openWorldHint: true
|
|
33964
|
+
},
|
|
33965
|
+
source: "opengeni",
|
|
33966
|
+
approval: "none",
|
|
33967
|
+
execute: async (args, context) => {
|
|
33968
|
+
let request;
|
|
33969
|
+
try {
|
|
33970
|
+
request = parseWebSearchArguments(args);
|
|
33971
|
+
await input.billing.admit(input.scope, pricing.providerMicros);
|
|
33972
|
+
} catch (error51) {
|
|
33973
|
+
if (error51 instanceof WebToolArgumentError || error51 instanceof WebSearchBillingRefusedError)
|
|
33974
|
+
return textResult2(error51.message, true);
|
|
33975
|
+
throw error51;
|
|
33976
|
+
}
|
|
33977
|
+
try {
|
|
33978
|
+
const response = await provider.search(request, { signal: context.signal });
|
|
33979
|
+
await settle(
|
|
33980
|
+
settledCost(
|
|
33981
|
+
context.operationId,
|
|
33982
|
+
"search",
|
|
33983
|
+
config2.search.provider,
|
|
33984
|
+
pricing,
|
|
33985
|
+
response.reportedCostMicros
|
|
33986
|
+
)
|
|
33987
|
+
);
|
|
33988
|
+
return textResult2(renderWebSearchResults(request.query, response.results), false);
|
|
33989
|
+
} catch (error51) {
|
|
33990
|
+
if (context.signal?.aborted) throw error51;
|
|
33991
|
+
if (error51 instanceof WebSearchProviderError) {
|
|
33992
|
+
return textResult2(`Web search failed: ${providerFailure(error51)}`, true);
|
|
33993
|
+
}
|
|
33994
|
+
throw error51;
|
|
33995
|
+
}
|
|
33996
|
+
}
|
|
33997
|
+
});
|
|
33998
|
+
}
|
|
33999
|
+
if (input.tools.includes(WEB_FETCH_TOOL_NAME) && config2.fetch) {
|
|
34000
|
+
const fetchEndpoint = config2.fetch;
|
|
34001
|
+
const provider = createWebFetchProvider({ ...adapterInput, endpoint: fetchEndpoint });
|
|
34002
|
+
const pricing = webSearchCallPricing(config2, "fetch");
|
|
34003
|
+
const pages = /* @__PURE__ */ new Map();
|
|
34004
|
+
definitions.push({
|
|
34005
|
+
identity: { serverId: "opengeni", toolName: WEB_FETCH_TOOL_NAME },
|
|
34006
|
+
modelName: WEB_FETCH_TOOL_NAME,
|
|
34007
|
+
codemodePath: ["opengeni", WEB_FETCH_TOOL_NAME],
|
|
34008
|
+
title: "Read a web page",
|
|
34009
|
+
description: WEB_FETCH_TOOL_DESCRIPTION,
|
|
34010
|
+
inputSchema: webFetchInputSchema,
|
|
34011
|
+
annotations: {
|
|
34012
|
+
title: "Read a web page",
|
|
34013
|
+
readOnlyHint: true,
|
|
34014
|
+
destructiveHint: false,
|
|
34015
|
+
idempotentHint: true,
|
|
34016
|
+
openWorldHint: true
|
|
34017
|
+
},
|
|
34018
|
+
source: "opengeni",
|
|
34019
|
+
approval: "none",
|
|
34020
|
+
execute: async (args, context) => {
|
|
34021
|
+
let request;
|
|
34022
|
+
try {
|
|
34023
|
+
request = parseWebFetchArguments(args);
|
|
34024
|
+
} catch (error51) {
|
|
34025
|
+
if (error51 instanceof WebToolArgumentError) return textResult2(error51.message, true);
|
|
34026
|
+
throw error51;
|
|
34027
|
+
}
|
|
34028
|
+
const cached2 = pages.get(request.url);
|
|
34029
|
+
if (cached2) return textResult2(renderWebPageWindow(cached2, request), false);
|
|
34030
|
+
try {
|
|
34031
|
+
await input.billing.admit(input.scope, pricing.providerMicros);
|
|
34032
|
+
} catch (error51) {
|
|
34033
|
+
if (error51 instanceof WebSearchBillingRefusedError) return textResult2(error51.message, true);
|
|
34034
|
+
throw error51;
|
|
34035
|
+
}
|
|
34036
|
+
try {
|
|
34037
|
+
const page = await provider.fetch({ url: request.url }, { signal: context.signal });
|
|
34038
|
+
await settle(
|
|
34039
|
+
settledCost(
|
|
34040
|
+
context.operationId,
|
|
34041
|
+
"fetch",
|
|
34042
|
+
fetchEndpoint.provider,
|
|
34043
|
+
pricing,
|
|
34044
|
+
page.reportedCostMicros
|
|
34045
|
+
)
|
|
34046
|
+
);
|
|
34047
|
+
if (pages.size >= PAGE_CACHE_ENTRIES) {
|
|
34048
|
+
pages.delete(pages.keys().next().value);
|
|
34049
|
+
}
|
|
34050
|
+
pages.set(request.url, {
|
|
34051
|
+
...page,
|
|
34052
|
+
content: page.content.slice(0, WEB_FETCH_RETAINED_MAX_CHARS + 1)
|
|
34053
|
+
});
|
|
34054
|
+
return textResult2(renderWebPageWindow(page, request), false);
|
|
34055
|
+
} catch (error51) {
|
|
34056
|
+
if (context.signal?.aborted) throw error51;
|
|
34057
|
+
if (error51 instanceof WebSearchProviderError) {
|
|
34058
|
+
return textResult2(`Web fetch failed: ${providerFailure(error51)}`, true);
|
|
34059
|
+
}
|
|
34060
|
+
throw error51;
|
|
34061
|
+
}
|
|
34062
|
+
}
|
|
34063
|
+
});
|
|
34064
|
+
}
|
|
34065
|
+
return definitions;
|
|
34066
|
+
}
|
|
34067
|
+
|
|
33642
34068
|
// src/activities/agent-turn/skill-tools.ts
|
|
33643
34069
|
import { createHash as createHash13 } from "crypto";
|
|
33644
34070
|
import {
|
|
@@ -33808,14 +34234,14 @@ async function readResult(files, identity, args, context, activeHistory) {
|
|
|
33808
34234
|
if (args.listFiles === true) {
|
|
33809
34235
|
return {
|
|
33810
34236
|
kind: "list",
|
|
33811
|
-
result:
|
|
34237
|
+
result: textResult3({ ...identity, ...listSkillPaths(files, PORTABLE_SKILL_MAX_FILES) })
|
|
33812
34238
|
};
|
|
33813
34239
|
}
|
|
33814
34240
|
const selected = readSkillFiles(files, args.paths);
|
|
33815
34241
|
if (args.paths === void 0 && context.caller.kind === "model" && activeHistory && await inActiveHistory(activeHistory, identity, selected.files[0])) {
|
|
33816
34242
|
return {
|
|
33817
34243
|
kind: "already_in_context",
|
|
33818
|
-
result:
|
|
34244
|
+
result: textResult3({
|
|
33819
34245
|
...identity,
|
|
33820
34246
|
alreadyInContext: true,
|
|
33821
34247
|
message: `Already in context: SKILL.md of ${JSON.stringify(args.skill)}${identity.revisionId ? ` revision ${identity.revisionId}` : ""} was returned earlier in this conversation and is unchanged. Use that copy. Re-read only if you need a fresh copy: call skill_read with paths ["SKILL.md"].`
|
|
@@ -33823,12 +34249,12 @@ async function readResult(files, identity, args, context, activeHistory) {
|
|
|
33823
34249
|
};
|
|
33824
34250
|
}
|
|
33825
34251
|
if (args.paths !== void 0) {
|
|
33826
|
-
return { kind: "files", result:
|
|
34252
|
+
return { kind: "files", result: textResult3({ ...identity, ...selected }) };
|
|
33827
34253
|
}
|
|
33828
34254
|
const scripts = skillScriptIndex(files);
|
|
33829
34255
|
return {
|
|
33830
34256
|
kind: "full",
|
|
33831
|
-
result:
|
|
34257
|
+
result: textResult3({ ...identity, ...selected, ...scripts ?? {} })
|
|
33832
34258
|
};
|
|
33833
34259
|
}
|
|
33834
34260
|
function observe(telemetry, read) {
|
|
@@ -33865,7 +34291,7 @@ function withSkillUse(read, origin, identity, telemetry) {
|
|
|
33865
34291
|
return read.result;
|
|
33866
34292
|
}
|
|
33867
34293
|
}
|
|
33868
|
-
function
|
|
34294
|
+
function textResult3(output) {
|
|
33869
34295
|
return {
|
|
33870
34296
|
isError: false,
|
|
33871
34297
|
content: [{ type: "text", text: JSON.stringify(output) }],
|
|
@@ -35329,6 +35755,19 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
35329
35755
|
const attemptToolFamilies = resolveAgentToolFamilies(session.agent, {
|
|
35330
35756
|
hasSkills: skillCatalog.length > 0
|
|
35331
35757
|
});
|
|
35758
|
+
const webSearchTools = webSearchToolDefinitions({
|
|
35759
|
+
settings: runSettings,
|
|
35760
|
+
tools: turnWebSearchPlan(resolvedModel, runSettings).providerTools,
|
|
35761
|
+
scope: {
|
|
35762
|
+
accountId: input.accountId,
|
|
35763
|
+
workspaceId: input.workspaceId,
|
|
35764
|
+
sessionId: input.sessionId,
|
|
35765
|
+
turnId: turn.id,
|
|
35766
|
+
attemptId: input.attemptId
|
|
35767
|
+
},
|
|
35768
|
+
billing: createWebSearchBilling({ db, settings: runSettings }),
|
|
35769
|
+
observability
|
|
35770
|
+
});
|
|
35332
35771
|
const attemptToolDefinitions = [
|
|
35333
35772
|
...operationReadStore ? [
|
|
35334
35773
|
createOperationReadAttemptToolDefinition({
|
|
@@ -35407,7 +35846,8 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
35407
35846
|
...interactionInterventionResume ? { interventionResume: interactionInterventionResume } : {}
|
|
35408
35847
|
}),
|
|
35409
35848
|
...googleDrivePublicationTool && googleDrivePublicationAllowed ? [googleDrivePublicationTool] : [],
|
|
35410
|
-
...codeSearchTools
|
|
35849
|
+
...codeSearchTools,
|
|
35850
|
+
...webSearchTools
|
|
35411
35851
|
].filter((tool) => attemptToolFamilies.allowsFunctionTool(tool.modelName));
|
|
35412
35852
|
recordTurnStartupPhase(observability, {
|
|
35413
35853
|
phase: "tool_context_preparation",
|
|
@@ -35634,7 +36074,8 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
35634
36074
|
void 0,
|
|
35635
36075
|
{},
|
|
35636
36076
|
(name) => mcpToolDisplayMetadata(tools.mcpServers, name),
|
|
35637
|
-
(entry) => toolFamilyForCatalogIdentity(entry, runSettings.mcpServers)
|
|
36077
|
+
(entry) => toolFamilyForCatalogIdentity(entry, runSettings.mcpServers),
|
|
36078
|
+
tools.inputWaitYield
|
|
35638
36079
|
);
|
|
35639
36080
|
eventing.codemodeDispatcher.start();
|
|
35640
36081
|
};
|
|
@@ -37225,7 +37666,7 @@ async function buildTurnAgent(deps) {
|
|
|
37225
37666
|
variableNames: Object.keys(workspaceVariableSet.values)
|
|
37226
37667
|
}
|
|
37227
37668
|
} : {};
|
|
37228
|
-
const hostedWebSearch =
|
|
37669
|
+
const hostedWebSearch = turnWebSearchPlan(resolvedModel, runSettings).hostedWebSearch;
|
|
37229
37670
|
const resolveImageReferences = async (references) => await resolveImageGenerationReferencesForTool({
|
|
37230
37671
|
db,
|
|
37231
37672
|
objectStorage,
|
|
@@ -37668,8 +38109,8 @@ async function buildTurnAgent(deps) {
|
|
|
37668
38109
|
// tool. Gateway Responses routes likewise expose ordinary function
|
|
37669
38110
|
// tools, not OpenAI-hosted sandbox tools. Tell buildAgent to use
|
|
37670
38111
|
// function apply_patch and wrap successful view_image results as
|
|
37671
|
-
// typed input_image content. Chat
|
|
37672
|
-
//
|
|
38112
|
+
// typed input_image content. The Chat adapter projects tool images
|
|
38113
|
+
// into a labelled image envelope after the paired tool results.
|
|
37673
38114
|
structuredToolTransport: structuredToolTransportForTurn(resolvedModel),
|
|
37674
38115
|
...promptCacheKey ? { promptCacheKey } : {}
|
|
37675
38116
|
} : (
|
|
@@ -40507,4 +40948,4 @@ export {
|
|
|
40507
40948
|
createTurnActivities,
|
|
40508
40949
|
createTurnActivitiesFromServices
|
|
40509
40950
|
};
|
|
40510
|
-
//# sourceMappingURL=activities-turn-
|
|
40951
|
+
//# sourceMappingURL=activities-turn-4Z3M7Z3F.js.map
|