@opengeni/worker-bundle 1.2.1-canary.37222965366001 → 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.
@@ -248,6 +248,8 @@ export async function resultItemForOpenSuffixMember(input: {
248
248
  }
249
249
 
250
250
  export async function settleOpenSuffixResumeIfNeeded(input: {
251
+ additionalApprovals?: unknown[];
252
+ programmaticApprovalAcknowledged?: boolean;
251
253
  db: Database;
252
254
  agent: Agent<any, any>;
253
255
  accountId: string;
@@ -270,7 +272,8 @@ export async function settleOpenSuffixResumeIfNeeded(input: {
270
272
  }): Promise<OpenSuffixResumeOutcome> {
271
273
  if (
272
274
  input.trigger.type !== "user.approvalDecision" &&
273
- input.trigger.type !== "user.humanInputResponse"
275
+ input.trigger.type !== "user.humanInputResponse" &&
276
+ !input.additionalApprovals?.length
274
277
  ) {
275
278
  return { action: "continue" };
276
279
  }
@@ -280,7 +283,7 @@ export async function settleOpenSuffixResumeIfNeeded(input: {
280
283
  input.sessionId,
281
284
  input.turnId,
282
285
  );
283
- if (rows.length === 0) {
286
+ if (rows.length === 0 && !input.additionalApprovals?.length) {
284
287
  return { action: "continue" };
285
288
  }
286
289
  const callId = matchingOpenSuffixCallId({
@@ -288,105 +291,123 @@ export async function settleOpenSuffixResumeIfNeeded(input: {
288
291
  humanInputToolCallId: input.humanInputResume?.toolCallId,
289
292
  });
290
293
  const target = resolveOpenSuffixResumeTarget(rows, callId);
291
- if (!target || !callId) {
294
+ if (
295
+ (!target || !callId) &&
296
+ !input.programmaticApprovalAcknowledged &&
297
+ (input.trigger.type === "user.approvalDecision" ||
298
+ input.trigger.type === "user.humanInputResponse" ||
299
+ !input.additionalApprovals?.length)
300
+ ) {
292
301
  throw new Error("Open suffix resume event does not match an interruption");
293
302
  }
294
- const truncationTokens =
295
- input.modelToolOutputTruncationTokens ?? target.modelToolOutputTruncationTokens ?? undefined;
296
- let resultItem = target.resultItem;
297
- let eventOutput: unknown = resultItem?.output;
298
- if (!resultItem) {
299
- const member = await resultItemForOpenSuffixMember({
300
- agent: input.agent,
301
- row: target,
302
- trigger: input.trigger,
303
- humanInputResume: input.humanInputResume,
304
- });
305
- resultItem = member.resultItem;
306
- eventOutput = member.eventOutput;
307
- const recorded = await recordPendingSessionToolCallResult(input.db, {
308
- accountId: input.accountId,
309
- workspaceId: input.workspaceId,
310
- sessionId: input.sessionId,
311
- turnId: input.turnId,
312
- executionGeneration: input.executionGeneration,
313
- attemptId: input.attemptId,
314
- callId: target.callId,
315
- ...(truncationTokens !== undefined
316
- ? { modelToolOutputTruncationTokens: truncationTokens }
317
- : {}),
318
- resultItem,
319
- eventOutput,
320
- });
321
- if (!recorded.accepted) {
322
- return { action: "cancelled" };
323
- }
324
- if (!recorded.recorded) {
325
- const latest = resolveOpenSuffixResumeTarget(
326
- await listTurnOpenSuffixToolCalls(
327
- input.db,
328
- input.workspaceId,
329
- input.sessionId,
330
- input.turnId,
331
- ),
332
- callId,
333
- );
334
- resultItem = latest?.resultItem ?? resultItem;
335
- } else if (input.publish) {
336
- await input.publish([
337
- {
338
- type: "agent.toolCall.output",
339
- payload: { id: target.callId, output: eventOutput },
340
- },
341
- ]);
303
+ if (target && callId) {
304
+ const truncationTokens =
305
+ input.modelToolOutputTruncationTokens ?? target.modelToolOutputTruncationTokens ?? undefined;
306
+ let resultItem = target.resultItem;
307
+ let eventOutput: unknown = resultItem?.output;
308
+ if (!resultItem) {
309
+ const member = await resultItemForOpenSuffixMember({
310
+ agent: input.agent,
311
+ row: target,
312
+ trigger: input.trigger,
313
+ humanInputResume: input.humanInputResume,
314
+ });
315
+ resultItem = member.resultItem;
316
+ eventOutput = member.eventOutput;
317
+ const recorded = await recordPendingSessionToolCallResult(input.db, {
318
+ accountId: input.accountId,
319
+ workspaceId: input.workspaceId,
320
+ sessionId: input.sessionId,
321
+ turnId: input.turnId,
322
+ executionGeneration: input.executionGeneration,
323
+ attemptId: input.attemptId,
324
+ callId: target.callId,
325
+ ...(truncationTokens !== undefined
326
+ ? { modelToolOutputTruncationTokens: truncationTokens }
327
+ : {}),
328
+ resultItem,
329
+ eventOutput,
330
+ });
331
+ if (!recorded.accepted) {
332
+ return { action: "cancelled" };
333
+ }
334
+ if (!recorded.recorded) {
335
+ const latest = resolveOpenSuffixResumeTarget(
336
+ await listTurnOpenSuffixToolCalls(
337
+ input.db,
338
+ input.workspaceId,
339
+ input.sessionId,
340
+ input.turnId,
341
+ ),
342
+ callId,
343
+ );
344
+ resultItem = latest?.resultItem ?? resultItem;
345
+ } else if (input.publish) {
346
+ await input.publish([
347
+ {
348
+ type: "agent.toolCall.output",
349
+ payload: { id: target.callId, output: eventOutput },
350
+ },
351
+ ]);
352
+ }
342
353
  }
343
- }
344
- if (!resultItem) {
345
- throw new Error(`Open suffix resume for ${target.callId} has no result item`);
346
- }
347
- const history = await getActiveSessionHistoryItems(input.db, input.workspaceId, input.sessionId);
348
- if (
349
- !openSuffixPairPresentInHistory(
350
- history.map((row) => row.item),
351
- callId,
352
- )
353
- ) {
354
- const historyItems = openSuffixHistoryItems(target, resultItem);
355
- if (historyItems.length === 0) {
356
- throw new Error(`Open suffix resume for ${target.callId} produced no paired history`);
354
+ if (!resultItem) {
355
+ throw new Error(`Open suffix resume for ${target.callId} has no result item`);
357
356
  }
358
- const nextPosition = await nextSessionHistoryPosition(
357
+ const history = await getActiveSessionHistoryItems(
359
358
  input.db,
360
359
  input.workspaceId,
361
360
  input.sessionId,
362
361
  );
363
- const appended = await appendSessionHistoryItems(input.db, {
364
- accountId: input.accountId,
365
- workspaceId: input.workspaceId,
366
- sessionId: input.sessionId,
367
- turnId: input.turnId,
368
- expectedExecutionGeneration: input.executionGeneration,
369
- expectedAttemptId: input.attemptId,
370
- ...(truncationTokens !== undefined
371
- ? { modelToolOutputTruncationTokens: truncationTokens }
372
- : {}),
373
- items: historyItems.map((item, offset) => ({
374
- position: nextPosition + offset,
375
- item,
376
- })),
377
- });
378
- if (!appended) {
379
- return { action: "cancelled" };
362
+ if (
363
+ !openSuffixPairPresentInHistory(
364
+ history.map((row) => row.item),
365
+ callId,
366
+ )
367
+ ) {
368
+ const historyItems = openSuffixHistoryItems(target, resultItem);
369
+ if (historyItems.length === 0) {
370
+ throw new Error(`Open suffix resume for ${target.callId} produced no paired history`);
371
+ }
372
+ const nextPosition = await nextSessionHistoryPosition(
373
+ input.db,
374
+ input.workspaceId,
375
+ input.sessionId,
376
+ );
377
+ const appended = await appendSessionHistoryItems(input.db, {
378
+ accountId: input.accountId,
379
+ workspaceId: input.workspaceId,
380
+ sessionId: input.sessionId,
381
+ turnId: input.turnId,
382
+ expectedExecutionGeneration: input.executionGeneration,
383
+ expectedAttemptId: input.attemptId,
384
+ ...(truncationTokens !== undefined
385
+ ? { modelToolOutputTruncationTokens: truncationTokens }
386
+ : {}),
387
+ items: historyItems.map((item, offset) => ({
388
+ position: nextPosition + offset,
389
+ item,
390
+ })),
391
+ });
392
+ if (!appended) {
393
+ return { action: "cancelled" };
394
+ }
380
395
  }
381
396
  }
382
397
  const remaining = (
383
398
  await listTurnOpenSuffixToolCalls(input.db, input.workspaceId, input.sessionId, input.turnId)
384
399
  ).filter((row) => row.resultItem == null);
385
- if (remaining.length === 0) {
400
+ if (remaining.length === 0 && !input.additionalApprovals?.length) {
386
401
  return { action: "continue" };
387
402
  }
388
- const requiresActionApprovals = remainingPendingApprovalsFromSuffix(remaining);
389
- const pendingApprovals = remainingRunStatePendingApprovalsFromSuffix(remaining);
403
+ const requiresActionApprovals = [
404
+ ...remainingPendingApprovalsFromSuffix(remaining),
405
+ ...(input.additionalApprovals ?? []),
406
+ ];
407
+ const pendingApprovals = [
408
+ ...remainingRunStatePendingApprovalsFromSuffix(remaining),
409
+ ...(input.additionalApprovals ?? []),
410
+ ];
390
411
  const settled = await input.settle({
391
412
  events: [
392
413
  ...(requiresActionApprovals.length > 0
@@ -0,0 +1,26 @@
1
+ import type { CodemodeOperation } from "@opengeni/contracts";
2
+
3
+ /** Programmatic receipts are not open SDK calls. Exact arguments stay in protected storage. */
4
+ export function programmaticApproval(operation: CodemodeOperation) {
5
+ return {
6
+ id: operation.operationId,
7
+ name: operation.identity.toolName,
8
+ source: "codemode" as const,
9
+ operationId: operation.operationId,
10
+ requestId: operation.approvalRequestId,
11
+ };
12
+ }
13
+
14
+ export function programmaticContinuationNote(
15
+ operations: readonly CodemodeOperation[],
16
+ ): string | undefined {
17
+ if (operations.length === 0) return undefined;
18
+ return [
19
+ "Stored programmatic operations (durable server receipts):",
20
+ ...operations.map(
21
+ (operation) =>
22
+ `${operation.operationId}: ${operation.state}${operation.errorCode ? ` (${operation.errorCode})` : ""}`,
23
+ ),
24
+ "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.",
25
+ ].join("\n");
26
+ }
@@ -81,6 +81,8 @@ export type TurnInputOptions = {
81
81
  unavailableSandboxFilesNote?: string;
82
82
  runCredentialsNote?: string;
83
83
  mcpAvailabilityNote?: string;
84
+ codemodeContinuationNote?: string;
85
+ programmaticApprovalAcknowledged?: boolean;
84
86
  knowledgeSourcePreparationNote?: string;
85
87
  providerApi: HistoryProviderApi;
86
88
  projectCanonicalHistory?: ModelHistoryAttachmentProjector;
@@ -513,6 +515,7 @@ export async function turnInput(
513
515
  options.unavailableSandboxFilesNote,
514
516
  options.runCredentialsNote,
515
517
  options.mcpAvailabilityNote,
518
+ options.codemodeContinuationNote,
516
519
  options.knowledgeSourcePreparationNote,
517
520
  );
518
521
  if (trigger.type === "user.message") {
@@ -606,7 +609,7 @@ async function openSuffixMessageInput(
606
609
  trigger.sessionId,
607
610
  options.turnId,
608
611
  );
609
- if (suffixRows.length === 0) {
612
+ if (suffixRows.length === 0 && !options.programmaticApprovalAcknowledged) {
610
613
  throw new Error("Open suffix resume has no interruption rows");
611
614
  }
612
615
  if (suffixRows.some((row) => row.resultItem == null)) {