@opengeni/worker-bundle 1.2.1-canary.37222177070001 → 1.3.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/codemode-dispatcher.d.ts +6 -2
- package/dist/activities/open-suffix-resume.d.ts +2 -0
- package/dist/activities/programmatic-approvals.d.ts +10 -0
- package/dist/activities/run-input.d.ts +2 -0
- package/dist/{activities-control-QSDPXLLD.js → activities-control-PEXBWKQJ.js} +2 -2
- package/dist/{activities-turn-BMY3CDKL.js → activities-turn-W27A2SBO.js} +273 -97
- package/dist/activities-turn-W27A2SBO.js.map +1 -0
- package/dist/{chunk-JKMG5ZHH.js → chunk-QUX5LT2B.js} +3 -2
- package/dist/{chunk-JKMG5ZHH.js.map → chunk-QUX5LT2B.js.map} +1 -1
- package/dist/index.js +1 -1
- package/package.json +21 -21
- package/src/activities/agent-turn/agent-build.ts +2 -2
- package/src/activities/agent-turn/stream-attempt.ts +66 -21
- package/src/activities/agent-turn/tool-environment.ts +1 -0
- package/src/activities/agent-turn/tool-policy.ts +1 -5
- package/src/activities/codemode-dispatcher.ts +145 -7
- package/src/activities/open-suffix-resume.ts +107 -86
- package/src/activities/programmatic-approvals.ts +26 -0
- package/src/activities/run-input.ts +4 -1
- package/dist/activities-turn-BMY3CDKL.js.map +0 -1
- /package/dist/{activities-control-QSDPXLLD.js.map → activities-control-PEXBWKQJ.js.map} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AttemptToolCatalogEntry, type AttemptToolEnvironment } from "@opengeni/codemode";
|
|
2
|
-
import { type ToolDisplayMetadata, type ToolFamily } from "@opengeni/contracts";
|
|
2
|
+
import { CodemodeOperation, type ToolDisplayMetadata, type ToolFamily } from "@opengeni/contracts";
|
|
3
3
|
import { type Database } from "@opengeni/db";
|
|
4
4
|
import { type EventBus } from "@opengeni/events";
|
|
5
5
|
export type CodemodeDispatcherScope = {
|
|
@@ -29,6 +29,7 @@ export declare class CodemodeAttemptDispatcher {
|
|
|
29
29
|
private readonly toolDisplayMetadata?;
|
|
30
30
|
/** Content-free analytics family for a catalog entry; event enrichment only. */
|
|
31
31
|
private readonly toolFamily?;
|
|
32
|
+
private readonly approvalWait?;
|
|
32
33
|
private readonly stopController;
|
|
33
34
|
private readonly inFlight;
|
|
34
35
|
private pendingClaims;
|
|
@@ -38,8 +39,11 @@ export declare class CodemodeAttemptDispatcher {
|
|
|
38
39
|
private readonly claimHeartbeatMs;
|
|
39
40
|
constructor(db: Database, bus: EventBus, environment: AttemptToolEnvironment, scope: CodemodeDispatcherScope, turnSignal?: AbortSignal | undefined, maxConcurrentCalls?: number, timings?: CodemodeDispatcherTimings, toolDisplayMetadata?: ((modelName: string) => ToolDisplayMetadata | undefined) | undefined,
|
|
40
41
|
/** Content-free analytics family for a catalog entry; event enrichment only. */
|
|
41
|
-
toolFamily?: ((entry: AttemptToolCatalogEntry) => ToolFamily | null) | undefined
|
|
42
|
+
toolFamily?: ((entry: AttemptToolCatalogEntry) => ToolFamily | null) | undefined, approvalWait?: {
|
|
43
|
+
beginWait(): (accepted: boolean) => void;
|
|
44
|
+
} | undefined);
|
|
42
45
|
start(): void;
|
|
46
|
+
resumeApproved(callerSubjectId: string, decisionOperationId?: string): Promise<CodemodeOperation[]>;
|
|
43
47
|
close(reason?: string): Promise<void>;
|
|
44
48
|
private execute;
|
|
45
49
|
private executeClaimed;
|
|
@@ -54,6 +54,8 @@ export declare function resultItemForOpenSuffixMember(input: {
|
|
|
54
54
|
eventOutput: unknown;
|
|
55
55
|
}>;
|
|
56
56
|
export declare function settleOpenSuffixResumeIfNeeded(input: {
|
|
57
|
+
additionalApprovals?: unknown[];
|
|
58
|
+
programmaticApprovalAcknowledged?: boolean;
|
|
57
59
|
db: Database;
|
|
58
60
|
agent: Agent<any, any>;
|
|
59
61
|
accountId: string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { CodemodeOperation } from "@opengeni/contracts";
|
|
2
|
+
/** Programmatic receipts are not open SDK calls. Exact arguments stay in protected storage. */
|
|
3
|
+
export declare function programmaticApproval(operation: CodemodeOperation): {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
source: "codemode";
|
|
7
|
+
operationId: string;
|
|
8
|
+
requestId: string | undefined;
|
|
9
|
+
};
|
|
10
|
+
export declare function programmaticContinuationNote(operations: readonly CodemodeOperation[]): string | undefined;
|
|
@@ -32,6 +32,8 @@ export type TurnInputOptions = {
|
|
|
32
32
|
unavailableSandboxFilesNote?: string;
|
|
33
33
|
runCredentialsNote?: string;
|
|
34
34
|
mcpAvailabilityNote?: string;
|
|
35
|
+
codemodeContinuationNote?: string;
|
|
36
|
+
programmaticApprovalAcknowledged?: boolean;
|
|
35
37
|
knowledgeSourcePreparationNote?: string;
|
|
36
38
|
providerApi: HistoryProviderApi;
|
|
37
39
|
projectCanonicalHistory?: ModelHistoryAttachmentProjector;
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
warnDrainSnapshotFailure,
|
|
35
35
|
withFirstPartyTools,
|
|
36
36
|
workflowIdForSession
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-QUX5LT2B.js";
|
|
38
38
|
import {
|
|
39
39
|
inspectOpenSandboxKubernetesInventory,
|
|
40
40
|
recordActiveUserGauges,
|
|
@@ -8813,4 +8813,4 @@ export {
|
|
|
8813
8813
|
createControlActivities,
|
|
8814
8814
|
createControlActivitiesFromServices
|
|
8815
8815
|
};
|
|
8816
|
-
//# sourceMappingURL=activities-control-
|
|
8816
|
+
//# sourceMappingURL=activities-control-PEXBWKQJ.js.map
|
|
@@ -99,7 +99,7 @@ import {
|
|
|
99
99
|
withFirstPartyTools,
|
|
100
100
|
wrapLazyTurnBoxWithRouting,
|
|
101
101
|
wrapTurnBoxWithRouting
|
|
102
|
-
} from "./chunk-
|
|
102
|
+
} from "./chunk-QUX5LT2B.js";
|
|
103
103
|
import {
|
|
104
104
|
StreamTimingMetrics,
|
|
105
105
|
makeMachineOpObserver,
|
|
@@ -7654,6 +7654,7 @@ import {
|
|
|
7654
7654
|
sessionTurnHasFinalReplyNudge,
|
|
7655
7655
|
getSessionHumanInputRequest,
|
|
7656
7656
|
getWorkspace,
|
|
7657
|
+
listTurnCodemodeApprovals,
|
|
7657
7658
|
recordUsageEvent as recordUsageEvent3,
|
|
7658
7659
|
registerPendingSessionToolCall,
|
|
7659
7660
|
recordPendingSessionToolCallResult as recordPendingSessionToolCallResult2,
|
|
@@ -8080,6 +8081,27 @@ async function retentionTokenCounts(items, project2) {
|
|
|
8080
8081
|
return counts;
|
|
8081
8082
|
}
|
|
8082
8083
|
|
|
8084
|
+
// src/activities/programmatic-approvals.ts
|
|
8085
|
+
function programmaticApproval(operation) {
|
|
8086
|
+
return {
|
|
8087
|
+
id: operation.operationId,
|
|
8088
|
+
name: operation.identity.toolName,
|
|
8089
|
+
source: "codemode",
|
|
8090
|
+
operationId: operation.operationId,
|
|
8091
|
+
requestId: operation.approvalRequestId
|
|
8092
|
+
};
|
|
8093
|
+
}
|
|
8094
|
+
function programmaticContinuationNote(operations) {
|
|
8095
|
+
if (operations.length === 0) return void 0;
|
|
8096
|
+
return [
|
|
8097
|
+
"Stored programmatic operations (durable server receipts):",
|
|
8098
|
+
...operations.map(
|
|
8099
|
+
(operation) => `${operation.operationId}: ${operation.state}${operation.errorCode ? ` (${operation.errorCode})` : ""}`
|
|
8100
|
+
),
|
|
8101
|
+
"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."
|
|
8102
|
+
].join("\n");
|
|
8103
|
+
}
|
|
8104
|
+
|
|
8083
8105
|
// src/activities/agent-turn/turn-sandbox-access.ts
|
|
8084
8106
|
function ownedTurnSandboxForAgent(sandboxState) {
|
|
8085
8107
|
return sandboxState.lazyOwnedSandbox ?? sandboxState.resolvedSandbox?.established;
|
|
@@ -8263,7 +8285,7 @@ async function resultItemForOpenSuffixMember(input) {
|
|
|
8263
8285
|
}
|
|
8264
8286
|
}
|
|
8265
8287
|
async function settleOpenSuffixResumeIfNeeded(input) {
|
|
8266
|
-
if (input.trigger.type !== "user.approvalDecision" && input.trigger.type !== "user.humanInputResponse") {
|
|
8288
|
+
if (input.trigger.type !== "user.approvalDecision" && input.trigger.type !== "user.humanInputResponse" && !input.additionalApprovals?.length) {
|
|
8267
8289
|
return { action: "continue" };
|
|
8268
8290
|
}
|
|
8269
8291
|
const rows = await listTurnOpenSuffixToolCalls(
|
|
@@ -8272,7 +8294,7 @@ async function settleOpenSuffixResumeIfNeeded(input) {
|
|
|
8272
8294
|
input.sessionId,
|
|
8273
8295
|
input.turnId
|
|
8274
8296
|
);
|
|
8275
|
-
if (rows.length === 0) {
|
|
8297
|
+
if (rows.length === 0 && !input.additionalApprovals?.length) {
|
|
8276
8298
|
return { action: "continue" };
|
|
8277
8299
|
}
|
|
8278
8300
|
const callId = matchingOpenSuffixCallId({
|
|
@@ -8280,96 +8302,108 @@ async function settleOpenSuffixResumeIfNeeded(input) {
|
|
|
8280
8302
|
humanInputToolCallId: input.humanInputResume?.toolCallId
|
|
8281
8303
|
});
|
|
8282
8304
|
const target = resolveOpenSuffixResumeTarget(rows, callId);
|
|
8283
|
-
if (!target || !callId) {
|
|
8305
|
+
if ((!target || !callId) && !input.programmaticApprovalAcknowledged && (input.trigger.type === "user.approvalDecision" || input.trigger.type === "user.humanInputResponse" || !input.additionalApprovals?.length)) {
|
|
8284
8306
|
throw new Error("Open suffix resume event does not match an interruption");
|
|
8285
8307
|
}
|
|
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
|
-
|
|
8308
|
+
if (target && callId) {
|
|
8309
|
+
const truncationTokens = input.modelToolOutputTruncationTokens ?? target.modelToolOutputTruncationTokens ?? void 0;
|
|
8310
|
+
let resultItem = target.resultItem;
|
|
8311
|
+
let eventOutput = resultItem?.output;
|
|
8312
|
+
if (!resultItem) {
|
|
8313
|
+
const member = await resultItemForOpenSuffixMember({
|
|
8314
|
+
agent: input.agent,
|
|
8315
|
+
row: target,
|
|
8316
|
+
trigger: input.trigger,
|
|
8317
|
+
humanInputResume: input.humanInputResume
|
|
8318
|
+
});
|
|
8319
|
+
resultItem = member.resultItem;
|
|
8320
|
+
eventOutput = member.eventOutput;
|
|
8321
|
+
const recorded = await recordPendingSessionToolCallResult(input.db, {
|
|
8322
|
+
accountId: input.accountId,
|
|
8323
|
+
workspaceId: input.workspaceId,
|
|
8324
|
+
sessionId: input.sessionId,
|
|
8325
|
+
turnId: input.turnId,
|
|
8326
|
+
executionGeneration: input.executionGeneration,
|
|
8327
|
+
attemptId: input.attemptId,
|
|
8328
|
+
callId: target.callId,
|
|
8329
|
+
...truncationTokens !== void 0 ? { modelToolOutputTruncationTokens: truncationTokens } : {},
|
|
8330
|
+
resultItem,
|
|
8331
|
+
eventOutput
|
|
8332
|
+
});
|
|
8333
|
+
if (!recorded.accepted) {
|
|
8334
|
+
return { action: "cancelled" };
|
|
8335
|
+
}
|
|
8336
|
+
if (!recorded.recorded) {
|
|
8337
|
+
const latest = resolveOpenSuffixResumeTarget(
|
|
8338
|
+
await listTurnOpenSuffixToolCalls(
|
|
8339
|
+
input.db,
|
|
8340
|
+
input.workspaceId,
|
|
8341
|
+
input.sessionId,
|
|
8342
|
+
input.turnId
|
|
8343
|
+
),
|
|
8344
|
+
callId
|
|
8345
|
+
);
|
|
8346
|
+
resultItem = latest?.resultItem ?? resultItem;
|
|
8347
|
+
} else if (input.publish) {
|
|
8348
|
+
await input.publish([
|
|
8349
|
+
{
|
|
8350
|
+
type: "agent.toolCall.output",
|
|
8351
|
+
payload: { id: target.callId, output: eventOutput }
|
|
8352
|
+
}
|
|
8353
|
+
]);
|
|
8354
|
+
}
|
|
8331
8355
|
}
|
|
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`);
|
|
8356
|
+
if (!resultItem) {
|
|
8357
|
+
throw new Error(`Open suffix resume for ${target.callId} has no result item`);
|
|
8344
8358
|
}
|
|
8345
|
-
const
|
|
8359
|
+
const history = await getActiveSessionHistoryItems(
|
|
8346
8360
|
input.db,
|
|
8347
8361
|
input.workspaceId,
|
|
8348
8362
|
input.sessionId
|
|
8349
8363
|
);
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
|
|
8353
|
-
|
|
8354
|
-
|
|
8355
|
-
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8364
|
+
if (!openSuffixPairPresentInHistory(
|
|
8365
|
+
history.map((row) => row.item),
|
|
8366
|
+
callId
|
|
8367
|
+
)) {
|
|
8368
|
+
const historyItems = openSuffixHistoryItems(target, resultItem);
|
|
8369
|
+
if (historyItems.length === 0) {
|
|
8370
|
+
throw new Error(`Open suffix resume for ${target.callId} produced no paired history`);
|
|
8371
|
+
}
|
|
8372
|
+
const nextPosition = await nextSessionHistoryPosition(
|
|
8373
|
+
input.db,
|
|
8374
|
+
input.workspaceId,
|
|
8375
|
+
input.sessionId
|
|
8376
|
+
);
|
|
8377
|
+
const appended = await appendSessionHistoryItems2(input.db, {
|
|
8378
|
+
accountId: input.accountId,
|
|
8379
|
+
workspaceId: input.workspaceId,
|
|
8380
|
+
sessionId: input.sessionId,
|
|
8381
|
+
turnId: input.turnId,
|
|
8382
|
+
expectedExecutionGeneration: input.executionGeneration,
|
|
8383
|
+
expectedAttemptId: input.attemptId,
|
|
8384
|
+
...truncationTokens !== void 0 ? { modelToolOutputTruncationTokens: truncationTokens } : {},
|
|
8385
|
+
items: historyItems.map((item, offset) => ({
|
|
8386
|
+
position: nextPosition + offset,
|
|
8387
|
+
item
|
|
8388
|
+
}))
|
|
8389
|
+
});
|
|
8390
|
+
if (!appended) {
|
|
8391
|
+
return { action: "cancelled" };
|
|
8392
|
+
}
|
|
8365
8393
|
}
|
|
8366
8394
|
}
|
|
8367
8395
|
const remaining = (await listTurnOpenSuffixToolCalls(input.db, input.workspaceId, input.sessionId, input.turnId)).filter((row) => row.resultItem == null);
|
|
8368
|
-
if (remaining.length === 0) {
|
|
8396
|
+
if (remaining.length === 0 && !input.additionalApprovals?.length) {
|
|
8369
8397
|
return { action: "continue" };
|
|
8370
8398
|
}
|
|
8371
|
-
const requiresActionApprovals =
|
|
8372
|
-
|
|
8399
|
+
const requiresActionApprovals = [
|
|
8400
|
+
...remainingPendingApprovalsFromSuffix(remaining),
|
|
8401
|
+
...input.additionalApprovals ?? []
|
|
8402
|
+
];
|
|
8403
|
+
const pendingApprovals = [
|
|
8404
|
+
...remainingRunStatePendingApprovalsFromSuffix(remaining),
|
|
8405
|
+
...input.additionalApprovals ?? []
|
|
8406
|
+
];
|
|
8373
8407
|
const settled = await input.settle({
|
|
8374
8408
|
events: [
|
|
8375
8409
|
...requiresActionApprovals.length > 0 ? [
|
|
@@ -8997,6 +9031,8 @@ async function runTurnStreamAttempt(deps) {
|
|
|
8997
9031
|
await parallelSessionTitle?.cancel();
|
|
8998
9032
|
};
|
|
8999
9033
|
let runInput = null;
|
|
9034
|
+
let codemodeContinuationNote;
|
|
9035
|
+
let programmaticApprovalAcknowledged = false;
|
|
9000
9036
|
const prepareRunAttemptInput = async () => {
|
|
9001
9037
|
const historyPreparationStartedAt = performance.now();
|
|
9002
9038
|
let historyPreparationOutcome = "completed";
|
|
@@ -9009,6 +9045,8 @@ async function runTurnStreamAttempt(deps) {
|
|
|
9009
9045
|
subjectId: fileAuthoritySubjectId
|
|
9010
9046
|
},
|
|
9011
9047
|
recovering: turn.executionGeneration > 1,
|
|
9048
|
+
programmaticApprovalAcknowledged,
|
|
9049
|
+
...codemodeContinuationNote ? { codemodeContinuationNote } : {},
|
|
9012
9050
|
...unavailableSandboxFilesNote ? { unavailableSandboxFilesNote } : {},
|
|
9013
9051
|
...runCredentialsNote ? { runCredentialsNote } : {},
|
|
9014
9052
|
...mcpAvailabilityNote ? { mcpAvailabilityNote } : {},
|
|
@@ -9967,10 +10005,17 @@ async function runTurnStreamAttempt(deps) {
|
|
|
9967
10005
|
});
|
|
9968
10006
|
}
|
|
9969
10007
|
}
|
|
9970
|
-
|
|
10008
|
+
const programmaticPending = (await listTurnCodemodeApprovals(db, {
|
|
10009
|
+
accountId: input.accountId,
|
|
10010
|
+
workspaceId: input.workspaceId,
|
|
10011
|
+
sessionId: input.sessionId,
|
|
10012
|
+
turnId: activeTurnId
|
|
10013
|
+
})).filter((operation) => operation.state === "waiting_for_approval").map(programmaticApproval);
|
|
10014
|
+
if (eventing.stream.interruptions.length > 0 || programmaticPending.length > 0) {
|
|
9971
10015
|
await eventing.preparedTools?.inputWaitYield?.sealForSettlement(runtimeCancellationSignal);
|
|
9972
10016
|
await historySink.reconcileConversationTruth({ requireDurable: true });
|
|
9973
|
-
const
|
|
10017
|
+
const sdkApprovals = runtime.serializeApprovals(eventing.stream.interruptions);
|
|
10018
|
+
const approvals = [...sdkApprovals, ...programmaticPending];
|
|
9974
10019
|
const humanInputInterruptions = runtime.serializeHumanInputRequests?.(eventing.stream.interruptions) ?? [];
|
|
9975
10020
|
const interactionInterventionInterruptions = runtime.serializeInteractionInterventionRequests?.(eventing.stream.interruptions) ?? [];
|
|
9976
10021
|
const latestWorkspace = await getWorkspace(db, input.workspaceId);
|
|
@@ -10042,11 +10087,14 @@ async function runTurnStreamAttempt(deps) {
|
|
|
10042
10087
|
const interruptionCallIds = interruptionCallIdsFromPause({
|
|
10043
10088
|
humanInputRequests,
|
|
10044
10089
|
interactionInterventionRequests,
|
|
10045
|
-
pendingApprovals
|
|
10090
|
+
pendingApprovals: [
|
|
10091
|
+
...sdkApprovals,
|
|
10092
|
+
...interactionInterventionInterruptions.map((interruption) => interruption.approval)
|
|
10093
|
+
]
|
|
10046
10094
|
});
|
|
10047
10095
|
assertOpenSuffixResumable(suffixMembers, interruptionCallIds);
|
|
10048
10096
|
const suffixByCallId = new Map(suffixMembers.map((member) => [member.callId, member]));
|
|
10049
|
-
const attached = await attachOpenSuffixToPendingToolCalls(db, {
|
|
10097
|
+
const attached = interruptionCallIds.length === 0 ? { accepted: true } : await attachOpenSuffixToPendingToolCalls(db, {
|
|
10050
10098
|
accountId: input.accountId,
|
|
10051
10099
|
workspaceId: input.workspaceId,
|
|
10052
10100
|
sessionId: input.sessionId,
|
|
@@ -10203,7 +10251,19 @@ async function runTurnStreamAttempt(deps) {
|
|
|
10203
10251
|
control.activityStatus = "idle";
|
|
10204
10252
|
return claimedResult({ status: "idle" });
|
|
10205
10253
|
};
|
|
10254
|
+
await eventing.toolPreparationReady;
|
|
10255
|
+
const codemodeOperations = await eventing.codemodeDispatcher?.resumeApproved(
|
|
10256
|
+
`sandbox:${input.attemptId}`,
|
|
10257
|
+
trigger.type === "user.approvalDecision" ? trigger.payload.approvalId : void 0
|
|
10258
|
+
) ?? [];
|
|
10259
|
+
codemodeContinuationNote = programmaticContinuationNote(codemodeOperations);
|
|
10260
|
+
programmaticApprovalAcknowledged = trigger.type === "user.approvalDecision" && codemodeOperations.some(
|
|
10261
|
+
(operation) => operation.operationId === trigger.payload.approvalId
|
|
10262
|
+
);
|
|
10263
|
+
const pendingProgrammaticApprovals = codemodeOperations.filter((operation) => operation.state === "waiting_for_approval").map(programmaticApproval);
|
|
10206
10264
|
const openSuffixResume = await settleOpenSuffixResumeIfNeeded({
|
|
10265
|
+
additionalApprovals: pendingProgrammaticApprovals,
|
|
10266
|
+
programmaticApprovalAcknowledged,
|
|
10207
10267
|
db,
|
|
10208
10268
|
agent,
|
|
10209
10269
|
accountId: input.accountId,
|
|
@@ -12486,9 +12546,8 @@ function modelSupportsImageInputForTurn(resolvedModel) {
|
|
|
12486
12546
|
return resolvedModel === null || resolvedModel.configured.capabilities?.inputModalities.includes("image") !== false;
|
|
12487
12547
|
}
|
|
12488
12548
|
function modelAttachmentInputPolicyForTurn(resolvedModel) {
|
|
12489
|
-
const typedTransport = resolvedModel === null || resolvedModel.provider.api === "responses" || resolvedModel.provider.api === "anthropic-messages";
|
|
12490
12549
|
return {
|
|
12491
|
-
supportsImageInput:
|
|
12550
|
+
supportsImageInput: modelSupportsImageInputForTurn(resolvedModel),
|
|
12492
12551
|
inputFileMediaTypes: []
|
|
12493
12552
|
};
|
|
12494
12553
|
}
|
|
@@ -32894,7 +32953,12 @@ import { allowedFirstPartyMcpToolsForSession } from "@opengeni/config";
|
|
|
32894
32953
|
|
|
32895
32954
|
// src/activities/codemode-dispatcher.ts
|
|
32896
32955
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
32897
|
-
import {
|
|
32956
|
+
import {
|
|
32957
|
+
bindMcpTelemetry,
|
|
32958
|
+
measureMcpPhase as measureMcpPhase2,
|
|
32959
|
+
withMcpCallIdentity as withMcpCallIdentity2,
|
|
32960
|
+
recordToolApproval
|
|
32961
|
+
} from "@opengeni/observability";
|
|
32898
32962
|
import {
|
|
32899
32963
|
AttemptToolApprovalRequiredError,
|
|
32900
32964
|
AttemptToolCatalogStaleError,
|
|
@@ -32907,10 +32971,16 @@ import {
|
|
|
32907
32971
|
import {
|
|
32908
32972
|
CODEMODE_CLAIM_LEASE_MS,
|
|
32909
32973
|
CODEMODE_CLAIM_HEARTBEAT_MS,
|
|
32910
|
-
CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT
|
|
32974
|
+
CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT,
|
|
32975
|
+
CodemodeOperation
|
|
32911
32976
|
} from "@opengeni/contracts";
|
|
32912
32977
|
import {
|
|
32913
32978
|
cancelQueuedCodemodeOperationsForAttempt,
|
|
32979
|
+
waitForCodemodeApproval,
|
|
32980
|
+
bindCodemodePreparation,
|
|
32981
|
+
listTurnCodemodeApprovals as listTurnCodemodeApprovals2,
|
|
32982
|
+
adoptCodemodeApprovalWithOutput,
|
|
32983
|
+
readTurnCodemodeOperation,
|
|
32914
32984
|
claimCodemodeOperation,
|
|
32915
32985
|
failCodemodeOperation,
|
|
32916
32986
|
getSessionEventByClientEventId,
|
|
@@ -32924,7 +32994,7 @@ import {
|
|
|
32924
32994
|
publishDurableSessionEvents as publishDurableSessionEvents8
|
|
32925
32995
|
} from "@opengeni/events";
|
|
32926
32996
|
var CodemodeAttemptDispatcher = class {
|
|
32927
|
-
constructor(db, bus, environment, scope, turnSignal, maxConcurrentCalls = CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT, timings = {}, toolDisplayMetadata, toolFamily) {
|
|
32997
|
+
constructor(db, bus, environment, scope, turnSignal, maxConcurrentCalls = CODEMODE_MAX_CONCURRENT_CALLS_PER_ATTEMPT, timings = {}, toolDisplayMetadata, toolFamily, approvalWait) {
|
|
32928
32998
|
this.db = db;
|
|
32929
32999
|
this.bus = bus;
|
|
32930
33000
|
this.environment = environment;
|
|
@@ -32933,6 +33003,7 @@ var CodemodeAttemptDispatcher = class {
|
|
|
32933
33003
|
this.maxConcurrentCalls = maxConcurrentCalls;
|
|
32934
33004
|
this.toolDisplayMetadata = toolDisplayMetadata;
|
|
32935
33005
|
this.toolFamily = toolFamily;
|
|
33006
|
+
this.approvalWait = approvalWait;
|
|
32936
33007
|
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
33008
|
throw new Error("Codemode dispatcher scope does not match its tool environment");
|
|
32938
33009
|
}
|
|
@@ -33022,6 +33093,76 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33022
33093
|
})
|
|
33023
33094
|
);
|
|
33024
33095
|
}
|
|
33096
|
+
async resumeApproved(callerSubjectId, decisionOperationId) {
|
|
33097
|
+
const operations = await listTurnCodemodeApprovals2(this.db, this.scope);
|
|
33098
|
+
if (decisionOperationId && // Model-tool approval IDs are opaque strings. Only programmatic UUIDs
|
|
33099
|
+
// can address the Codemode operation journal.
|
|
33100
|
+
CodemodeOperation.shape.operationId.safeParse(decisionOperationId).success && !operations.some((operation) => operation.operationId === decisionOperationId)) {
|
|
33101
|
+
const decided = await readTurnCodemodeOperation(this.db, {
|
|
33102
|
+
...this.scope,
|
|
33103
|
+
callerSubjectId,
|
|
33104
|
+
operationId: decisionOperationId
|
|
33105
|
+
});
|
|
33106
|
+
if (decided) operations.push(decided);
|
|
33107
|
+
}
|
|
33108
|
+
for (const operation of operations) {
|
|
33109
|
+
if (!["waiting_for_approval", "queued", "running"].includes(operation.state)) continue;
|
|
33110
|
+
let effectDigest = null;
|
|
33111
|
+
try {
|
|
33112
|
+
effectDigest = this.environment.effectDigest(operation.identity);
|
|
33113
|
+
} catch {
|
|
33114
|
+
}
|
|
33115
|
+
const continuation = await adoptCodemodeApprovalWithOutput(this.db, {
|
|
33116
|
+
...this.scope,
|
|
33117
|
+
operationId: operation.operationId,
|
|
33118
|
+
callerSubjectId,
|
|
33119
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33120
|
+
effectDigest
|
|
33121
|
+
});
|
|
33122
|
+
await publishDurableSessionEvents8(
|
|
33123
|
+
this.bus,
|
|
33124
|
+
this.scope.workspaceId,
|
|
33125
|
+
this.scope.sessionId,
|
|
33126
|
+
continuation.events
|
|
33127
|
+
);
|
|
33128
|
+
const adopted = continuation.operation;
|
|
33129
|
+
if (adopted && adopted.state !== operation.state) {
|
|
33130
|
+
const outcome = adopted.state === "queued" ? "resumed" : adopted.state === "outcome_unknown" ? "unknown" : adopted.errorCode === "approval_stale" ? "stale" : "rejected";
|
|
33131
|
+
recordToolApproval(
|
|
33132
|
+
outcome,
|
|
33133
|
+
"continuation",
|
|
33134
|
+
operation.state === "waiting_for_approval" ? Math.max(0, Date.now() - Date.parse(operation.updatedAt)) : void 0
|
|
33135
|
+
);
|
|
33136
|
+
}
|
|
33137
|
+
if (adopted?.state !== "queued") continue;
|
|
33138
|
+
const claim = await claimCodemodeOperation(this.db, {
|
|
33139
|
+
...this.scope,
|
|
33140
|
+
operationId: adopted.operationId,
|
|
33141
|
+
claimId: randomUUID3(),
|
|
33142
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33143
|
+
claimLeaseMs: this.claimLeaseMs
|
|
33144
|
+
});
|
|
33145
|
+
if (claim.status === "claimed") {
|
|
33146
|
+
const execution = this.execute(claim.operation, claim.claimId, true);
|
|
33147
|
+
this.inFlight.set(adopted.operationId, execution);
|
|
33148
|
+
try {
|
|
33149
|
+
await execution;
|
|
33150
|
+
} finally {
|
|
33151
|
+
this.inFlight.delete(adopted.operationId);
|
|
33152
|
+
}
|
|
33153
|
+
}
|
|
33154
|
+
}
|
|
33155
|
+
const receipts = [];
|
|
33156
|
+
for (const operation of operations) {
|
|
33157
|
+
const receipt = await readTurnCodemodeOperation(this.db, {
|
|
33158
|
+
...this.scope,
|
|
33159
|
+
callerSubjectId,
|
|
33160
|
+
operationId: operation.operationId
|
|
33161
|
+
});
|
|
33162
|
+
if (receipt) receipts.push(receipt);
|
|
33163
|
+
}
|
|
33164
|
+
return receipts;
|
|
33165
|
+
}
|
|
33025
33166
|
async close(reason = "Execution attempt ended") {
|
|
33026
33167
|
if (this.closing) {
|
|
33027
33168
|
await Promise.allSettled([...this.inFlight.values()]);
|
|
@@ -33102,18 +33243,51 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33102
33243
|
return;
|
|
33103
33244
|
}
|
|
33104
33245
|
let preparedCall;
|
|
33246
|
+
let releaseWait;
|
|
33105
33247
|
try {
|
|
33248
|
+
if (operation.durableApproval) {
|
|
33249
|
+
if (!this.approvalWait) throw new Error("Durable approval yield is unavailable");
|
|
33250
|
+
releaseWait = this.approvalWait.beginWait();
|
|
33251
|
+
if (!await bindCodemodePreparation(this.db, {
|
|
33252
|
+
...this.scope,
|
|
33253
|
+
operationId: operation.operationId,
|
|
33254
|
+
claimId,
|
|
33255
|
+
effectDigest: this.environment.effectDigest(operation.identity)
|
|
33256
|
+
}))
|
|
33257
|
+
throw new Error("Operation preparation is stale");
|
|
33258
|
+
}
|
|
33106
33259
|
preparedCall = await this.environment.prepareCall(
|
|
33107
33260
|
{
|
|
33108
33261
|
operationId: operation.operationId,
|
|
33109
|
-
catalogDigest:
|
|
33262
|
+
catalogDigest: this.environment.catalog.digest,
|
|
33110
33263
|
identity: operation.identity,
|
|
33111
33264
|
arguments: operation.arguments,
|
|
33112
|
-
caller:
|
|
33265
|
+
caller: {
|
|
33266
|
+
kind: "codemode",
|
|
33267
|
+
subjectId: operation.caller.subjectId === `sandbox:${operation.attemptId}` ? `sandbox:${this.scope.attemptId}` : operation.caller.subjectId
|
|
33268
|
+
}
|
|
33113
33269
|
},
|
|
33114
|
-
{
|
|
33270
|
+
{
|
|
33271
|
+
signal,
|
|
33272
|
+
...operation.durableApproval ? { transportMeta: { durableApproval: true } } : {}
|
|
33273
|
+
}
|
|
33115
33274
|
);
|
|
33275
|
+
if (preparedCall.waitingForApproval) {
|
|
33276
|
+
const waiting = await waitForCodemodeApproval(this.db, {
|
|
33277
|
+
...this.scope,
|
|
33278
|
+
operationId: operation.operationId,
|
|
33279
|
+
claimId,
|
|
33280
|
+
...preparedCall.waitingForApproval,
|
|
33281
|
+
effectDigest: preparedCall.effectDigest
|
|
33282
|
+
});
|
|
33283
|
+
if (!waiting) throw new Error("Approval could not be bound to the operation");
|
|
33284
|
+
recordToolApproval("waiting");
|
|
33285
|
+
releaseWait?.(true);
|
|
33286
|
+
return;
|
|
33287
|
+
}
|
|
33288
|
+
releaseWait?.(false);
|
|
33116
33289
|
} catch (error51) {
|
|
33290
|
+
releaseWait?.(false);
|
|
33117
33291
|
await this.settleWithOutput(operation, claimId, {
|
|
33118
33292
|
state: "failed",
|
|
33119
33293
|
errorCode: errorCode(error51, signal, false),
|
|
@@ -33244,6 +33418,7 @@ var CodemodeAttemptDispatcher = class {
|
|
|
33244
33418
|
settlement
|
|
33245
33419
|
});
|
|
33246
33420
|
if (!result.committed || result.events.length === 0) return;
|
|
33421
|
+
recordToolApproval(settlement.state === "outcome_unknown" ? "unknown" : settlement.state);
|
|
33247
33422
|
await publishDurableSessionEvents8(
|
|
33248
33423
|
this.bus,
|
|
33249
33424
|
this.scope.workspaceId,
|
|
@@ -33270,7 +33445,7 @@ function codemodeToolCallCreatedClientEventId(operationId) {
|
|
|
33270
33445
|
function assertMatchingCodemodeToolCallCreated(event, operation, entry, scope) {
|
|
33271
33446
|
const payload = recordValue(event.payload);
|
|
33272
33447
|
const raw = recordValue(payload?.raw);
|
|
33273
|
-
if (event.type !== "agent.toolCall.created" || event.turnId !== scope.turnId || event.turnGeneration !==
|
|
33448
|
+
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
33449
|
throw new Error("Codemode tool-call creation id is bound to incompatible durable evidence");
|
|
33275
33450
|
}
|
|
33276
33451
|
}
|
|
@@ -35634,7 +35809,8 @@ async function prepareTurnToolRuntime(deps) {
|
|
|
35634
35809
|
void 0,
|
|
35635
35810
|
{},
|
|
35636
35811
|
(name) => mcpToolDisplayMetadata(tools.mcpServers, name),
|
|
35637
|
-
(entry) => toolFamilyForCatalogIdentity(entry, runSettings.mcpServers)
|
|
35812
|
+
(entry) => toolFamilyForCatalogIdentity(entry, runSettings.mcpServers),
|
|
35813
|
+
tools.inputWaitYield
|
|
35638
35814
|
);
|
|
35639
35815
|
eventing.codemodeDispatcher.start();
|
|
35640
35816
|
};
|
|
@@ -37668,8 +37844,8 @@ async function buildTurnAgent(deps) {
|
|
|
37668
37844
|
// tool. Gateway Responses routes likewise expose ordinary function
|
|
37669
37845
|
// tools, not OpenAI-hosted sandbox tools. Tell buildAgent to use
|
|
37670
37846
|
// function apply_patch and wrap successful view_image results as
|
|
37671
|
-
// typed input_image content. Chat
|
|
37672
|
-
//
|
|
37847
|
+
// typed input_image content. The Chat adapter projects tool images
|
|
37848
|
+
// into a labelled image envelope after the paired tool results.
|
|
37673
37849
|
structuredToolTransport: structuredToolTransportForTurn(resolvedModel),
|
|
37674
37850
|
...promptCacheKey ? { promptCacheKey } : {}
|
|
37675
37851
|
} : (
|
|
@@ -40507,4 +40683,4 @@ export {
|
|
|
40507
40683
|
createTurnActivities,
|
|
40508
40684
|
createTurnActivitiesFromServices
|
|
40509
40685
|
};
|
|
40510
|
-
//# sourceMappingURL=activities-turn-
|
|
40686
|
+
//# sourceMappingURL=activities-turn-W27A2SBO.js.map
|