@opengeni/worker-bundle 1.0.0-canary.0 → 1.0.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-run-admission.d.ts +3 -1
- package/dist/activities/agent-turn/admission.d.ts +24 -3
- package/dist/activities/agent-turn/agent-build.d.ts +4 -0
- package/dist/activities/agent-turn/claude-usage-observer.d.ts +58 -0
- package/dist/activities/agent-turn/code-search.d.ts +60 -0
- package/dist/activities/agent-turn/codex-capacity.d.ts +13 -0
- package/dist/activities/agent-turn/codex-plan-entitlement.d.ts +105 -0
- package/dist/activities/agent-turn/codex.d.ts +3 -2
- package/dist/activities/agent-turn/compaction-prep.d.ts +21 -5
- package/dist/activities/agent-turn/credential-leases.d.ts +19 -33
- package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
- package/dist/activities/agent-turn/errors.d.ts +82 -11
- package/dist/activities/agent-turn/failure-settlement.d.ts +6 -3
- package/dist/activities/agent-turn/final-reply.d.ts +18 -0
- package/dist/activities/agent-turn/finalization-monitor.d.ts +17 -0
- package/dist/activities/agent-turn/finalization.d.ts +4 -2
- package/dist/activities/agent-turn/github-repository-bindings.d.ts +2 -0
- package/dist/activities/agent-turn/governance-model.d.ts +9 -2
- package/dist/activities/agent-turn/history-sink.d.ts +2 -0
- package/dist/activities/agent-turn/history.d.ts +2 -0
- package/dist/activities/agent-turn/input-wait-reply.d.ts +41 -0
- package/dist/activities/agent-turn/media-artifacts.d.ts +5 -3
- package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
- package/dist/activities/agent-turn/model-usage.d.ts +6 -0
- package/dist/activities/agent-turn/model-wire-dispatch.d.ts +15 -0
- package/dist/activities/agent-turn/optional-repositories.d.ts +59 -0
- package/dist/activities/agent-turn/provider-dispatch-barrier.d.ts +12 -1
- package/dist/activities/agent-turn/quiescence.d.ts +7 -7
- package/dist/activities/agent-turn/recovery-warning.d.ts +9 -0
- package/dist/activities/agent-turn/refresh-credentials.d.ts +6 -0
- package/dist/activities/agent-turn/run-credentials.d.ts +8 -3
- package/dist/activities/agent-turn/sandbox-establish.d.ts +2 -1
- package/dist/activities/agent-turn/sandbox-provision.d.ts +3 -1
- package/dist/activities/agent-turn/sandbox-route.d.ts +3 -20
- package/dist/activities/agent-turn/sandbox-runtime.d.ts +2 -2
- package/dist/activities/agent-turn/session-title.d.ts +34 -2
- package/dist/activities/agent-turn/skill-checkout.d.ts +25 -6
- package/dist/activities/agent-turn/skill-read.d.ts +70 -2
- package/dist/activities/agent-turn/skill-remove.d.ts +14 -0
- package/dist/activities/agent-turn/skill-search.d.ts +3 -1
- package/dist/activities/agent-turn/skill-tools.d.ts +15 -2
- package/dist/activities/agent-turn/skill-transfer.d.ts +18 -6
- package/dist/activities/agent-turn/stream-attempt.d.ts +7 -3
- package/dist/activities/agent-turn/subscription-lease.d.ts +38 -0
- package/dist/activities/agent-turn/tool-environment.d.ts +56 -6
- package/dist/activities/agent-turn/tool-policy.d.ts +43 -0
- package/dist/activities/agent-turn/turn-context.d.ts +29 -0
- package/dist/activities/agent-turn/turn-sandbox-access.d.ts +3 -0
- package/dist/activities/agent-turn/xai-capacity.d.ts +2 -1
- package/dist/activities/automations.d.ts +3 -1
- package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
- package/dist/activities/codemode-dispatcher.d.ts +9 -2
- package/dist/activities/codex-capacity.d.ts +18 -2
- package/dist/activities/codex-rotation.d.ts +7 -1
- package/dist/activities/context-compaction.d.ts +16 -2
- package/dist/activities/gmail-files.d.ts +32 -0
- package/dist/activities/goals.d.ts +8 -0
- package/dist/activities/knowledge-indexing.d.ts +19 -0
- package/dist/activities/mcp-account-routes.d.ts +3 -0
- package/dist/activities/mcp-credentials.d.ts +12 -13
- package/dist/activities/mcp-operation-authority.d.ts +0 -5
- package/dist/activities/model-call-fact-reconciler.d.ts +34 -0
- package/dist/activities/open-suffix-resume.d.ts +13 -0
- package/dist/activities/parent-wake.d.ts +6 -12
- package/dist/activities/retained-screenshots.d.ts +7 -2
- package/dist/activities/rig-verification.d.ts +2 -3
- package/dist/activities/run-credential-renewal.d.ts +1 -0
- package/dist/activities/run-credentials.d.ts +15 -3
- package/dist/activities/sandbox-images.d.ts +1 -1
- package/dist/activities/sandbox-lease.d.ts +47 -9
- package/dist/activities/scheduled-tasks.d.ts +4 -35
- package/dist/activities/session-state.d.ts +70 -3
- package/dist/activities/types.d.ts +55 -6
- package/dist/activities/workspace-capture.d.ts +2 -0
- package/dist/activities/workspace-credential-provider.d.ts +46 -0
- package/dist/{activities-control-HMFGSKC5.js → activities-control-BNPTRTOE.js} +1896 -418
- package/dist/activities-control-BNPTRTOE.js.map +1 -0
- package/dist/activities-control.d.ts +182 -4
- package/dist/{activities-turn-AP67JADS.js → activities-turn-5LGZOSVU.js} +4476 -1327
- package/dist/activities-turn-5LGZOSVU.js.map +1 -0
- package/dist/activities.d.ts +182 -4
- package/dist/artifact-materializer-entry.js +5 -2
- package/dist/artifact-materializer-entry.js.map +1 -1
- package/dist/artifact-outbox-entry.js +5 -2
- package/dist/artifact-outbox-entry.js.map +1 -1
- package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
- package/dist/{chunk-A4XQWVZK.js → chunk-3ZTRWDMN.js} +307 -4
- package/dist/chunk-3ZTRWDMN.js.map +1 -0
- package/dist/{chunk-RAMNYSAW.js → chunk-4ER3YXOT.js} +22 -4
- package/dist/chunk-4ER3YXOT.js.map +1 -0
- package/dist/{chunk-CYITU5UH.js → chunk-LJX7Z2KP.js} +1445 -343
- package/dist/chunk-LJX7Z2KP.js.map +1 -0
- package/dist/editable-artifact-materializer-service.d.ts +2 -2
- package/dist/editable-artifact-outbox-service.d.ts +2 -2
- package/dist/host-export-pump.d.ts +3 -1
- package/dist/host-export.d.ts +1 -1
- package/dist/host-export.js +1 -1
- package/dist/http.d.ts +1 -1
- package/dist/index.d.ts +95 -3
- package/dist/index.js +137 -43
- package/dist/index.js.map +1 -1
- package/dist/observability-metrics.d.ts +118 -8
- package/dist/retained-process-diagnostics.d.ts +4 -0
- package/dist/retained-process-retry.d.ts +7 -0
- package/dist/sandbox-resume.d.ts +55 -13
- package/dist/sandbox-routing.d.ts +5 -3
- package/dist/sandbox-snapshot-diagnostics.d.ts +20 -0
- package/dist/session-event-fanout.d.ts +6 -0
- package/dist/warm-capture-holder.d.ts +3 -0
- package/dist/worker-service-lifecycle.d.ts +12 -0
- package/dist/workflow-bundle.js +273 -41
- package/dist/workflows/activities.d.ts +1 -1
- package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
- package/dist/workflows/scheduled-tasks.d.ts +4 -0
- package/dist/workflows/session.d.ts +36 -0
- package/dist/workflows.d.ts +1 -0
- package/package.json +21 -19
- package/src/activities/agent-run-admission.ts +17 -1
- package/src/activities/agent-turn/admission.ts +66 -3
- package/src/activities/agent-turn/agent-build.ts +84 -10
- package/src/activities/agent-turn/claim.ts +186 -43
- package/src/activities/agent-turn/claude-usage-observer.ts +221 -0
- package/src/activities/agent-turn/code-search.ts +275 -0
- package/src/activities/agent-turn/codex-capacity.ts +172 -8
- package/src/activities/agent-turn/codex-plan-entitlement.ts +254 -0
- package/src/activities/agent-turn/codex.ts +13 -5
- package/src/activities/agent-turn/compaction-prep.ts +170 -102
- package/src/activities/agent-turn/credential-leases.ts +122 -216
- package/src/activities/agent-turn/credential-restriction.ts +14 -0
- package/src/activities/agent-turn/errors.ts +647 -48
- package/src/activities/agent-turn/failure-settlement.ts +682 -130
- package/src/activities/agent-turn/final-reply.ts +46 -0
- package/src/activities/agent-turn/finalization-monitor.ts +120 -0
- package/src/activities/agent-turn/finalization.ts +146 -43
- package/src/activities/agent-turn/github-repository-bindings.ts +3 -1
- package/src/activities/agent-turn/governance-model.ts +69 -28
- package/src/activities/agent-turn/history-sink.ts +16 -2
- package/src/activities/agent-turn/history.ts +38 -11
- package/src/activities/agent-turn/input-wait-reply.ts +103 -0
- package/src/activities/agent-turn/knowledge-source-tools.ts +2 -0
- package/src/activities/agent-turn/media-artifacts.ts +2 -1
- package/src/activities/agent-turn/model-call-admission.ts +94 -0
- package/src/activities/agent-turn/model-usage.ts +64 -3
- package/src/activities/agent-turn/model-wire-dispatch.ts +27 -0
- package/src/activities/agent-turn/optional-repositories.ts +224 -0
- package/src/activities/agent-turn/provider-dispatch-barrier.ts +22 -0
- package/src/activities/agent-turn/quiescence.ts +10 -7
- package/src/activities/agent-turn/recovery-warning.ts +16 -0
- package/src/activities/agent-turn/refresh-credentials.ts +44 -0
- package/src/activities/agent-turn/run-credentials.ts +116 -55
- package/src/activities/agent-turn/run.ts +320 -93
- package/src/activities/agent-turn/sandbox-establish.ts +84 -8
- package/src/activities/agent-turn/sandbox-provision.ts +3 -1
- package/src/activities/agent-turn/sandbox-route.ts +4 -21
- package/src/activities/agent-turn/sandbox-runtime.ts +343 -18
- package/src/activities/agent-turn/session-title.ts +81 -5
- package/src/activities/agent-turn/skill-checkout.ts +111 -24
- package/src/activities/agent-turn/skill-install.ts +1 -1
- package/src/activities/agent-turn/skill-read.ts +374 -28
- package/src/activities/agent-turn/skill-remove.ts +46 -0
- package/src/activities/agent-turn/skill-save.ts +1 -1
- package/src/activities/agent-turn/skill-search.ts +10 -1
- package/src/activities/agent-turn/skill-selection.ts +4 -0
- package/src/activities/agent-turn/skill-tools.ts +112 -18
- package/src/activities/agent-turn/skill-transfer.ts +68 -23
- package/src/activities/agent-turn/stream-attempt.ts +313 -77
- package/src/activities/agent-turn/subscription-lease.ts +115 -0
- package/src/activities/agent-turn/tool-environment.ts +316 -167
- package/src/activities/agent-turn/tool-policy.ts +80 -1
- package/src/activities/agent-turn/turn-context.ts +35 -0
- package/src/activities/agent-turn/turn-sandbox-access.ts +7 -1
- package/src/activities/agent-turn/xai-capacity.ts +94 -51
- package/src/activities/automations.ts +76 -4
- package/src/activities/browser-deadline-checkpoint.ts +279 -0
- package/src/activities/capabilities.ts +108 -11
- package/src/activities/codemode-dispatcher.ts +36 -8
- package/src/activities/codex-capacity.ts +60 -25
- package/src/activities/codex-rotation.ts +39 -17
- package/src/activities/context-compaction.ts +75 -18
- package/src/activities/gmail-files.ts +88 -0
- package/src/activities/goals.ts +116 -121
- package/src/activities/google-drive-publication.ts +1 -3
- package/src/activities/image-generation-operation.ts +1 -1
- package/src/activities/knowledge-indexing.ts +269 -15
- package/src/activities/knowledge-source-sync.ts +10 -0
- package/src/activities/mcp-account-routes.ts +17 -0
- package/src/activities/mcp-credentials.ts +83 -194
- package/src/activities/mcp-operation-authority.ts +16 -41
- package/src/activities/model-call-fact-reconciler.ts +112 -0
- package/src/activities/open-suffix-resume.ts +15 -2
- package/src/activities/parent-wake.ts +46 -21
- package/src/activities/retained-screenshots.ts +82 -11
- package/src/activities/rig-verification.ts +38 -37
- package/src/activities/run-credential-renewal.ts +13 -1
- package/src/activities/run-credentials.ts +59 -17
- package/src/activities/run-input.ts +25 -16
- package/src/activities/sandbox-images.ts +0 -1
- package/src/activities/sandbox-lease.ts +798 -82
- package/src/activities/scheduled-tasks.ts +550 -178
- package/src/activities/session-state.ts +245 -6
- package/src/activities/site-auth-maintenance.ts +3 -0
- package/src/activities/types.ts +72 -5
- package/src/activities/workflow-wake.ts +2 -17
- package/src/activities/workspace-capture.ts +13 -2
- package/src/activities/workspace-credential-provider.ts +283 -0
- package/src/activities-control.ts +4 -0
- package/src/activities-turn.ts +5 -0
- package/src/activities.ts +13 -0
- package/src/activity-services.ts +16 -4
- package/src/browser-deadline-checkpoint-contract.ts +5 -0
- package/src/editable-artifact-hint-broker.ts +3 -0
- package/src/editable-artifact-materializer-service.ts +7 -3
- package/src/editable-artifact-outbox-service.ts +4 -4
- package/src/github-rest-mcp.ts +1 -2
- package/src/host-export-pump.ts +26 -4
- package/src/host-export.ts +3 -0
- package/src/http.ts +4 -2
- package/src/index.ts +99 -37
- package/src/observability-metrics.ts +510 -5
- package/src/personal-github-git-credentials.ts +2 -1
- package/src/pr-review-credentials.ts +1 -3
- package/src/retained-process-diagnostics.ts +50 -0
- package/src/retained-process-retry.ts +36 -0
- package/src/sandbox-resume.ts +388 -101
- package/src/sandbox-routing.ts +150 -25
- package/src/sandbox-snapshot-diagnostics.ts +112 -0
- package/src/session-event-fanout.ts +23 -0
- package/src/warm-capture-holder.ts +15 -0
- package/src/worker-service-lifecycle.ts +53 -0
- package/src/workflows/activities.ts +16 -1
- package/src/workflows/browser-deadline-checkpoint.ts +50 -0
- package/src/workflows/file-upload-reaper.ts +2 -0
- package/src/workflows/scheduled-tasks.ts +26 -13
- package/src/workflows/session.ts +242 -22
- package/src/workflows.ts +4 -0
- package/dist/activities/agent-turn/knowledge-sources.d.ts +0 -20
- package/dist/activities/packs.d.ts +0 -55
- package/dist/activities-control-HMFGSKC5.js.map +0 -1
- package/dist/activities-turn-AP67JADS.js.map +0 -1
- package/dist/chunk-A4XQWVZK.js.map +0 -1
- package/dist/chunk-CYITU5UH.js.map +0 -1
- package/dist/chunk-RAMNYSAW.js.map +0 -1
- package/src/activities/agent-turn/knowledge-sources.ts +0 -86
- package/src/activities/packs.ts +0 -166
|
@@ -16,7 +16,9 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
calculateGatewayReportedCostBreakdown,
|
|
18
18
|
calculateGatewayReportedProviderCostMicros,
|
|
19
|
+
calculateModelListUsageCostSnapshot,
|
|
19
20
|
calculateModelUsageCostBreakdown,
|
|
21
|
+
configuredModelListPricingSchedules,
|
|
20
22
|
configuredModelPricingSchedules,
|
|
21
23
|
resolveModelProvider,
|
|
22
24
|
responseSatisfiesLatencyMode,
|
|
@@ -39,6 +41,7 @@ import {
|
|
|
39
41
|
type ModelContextContributionSummary,
|
|
40
42
|
type SessionEvent,
|
|
41
43
|
} from "@opengeni/contracts";
|
|
44
|
+
import type { InsightsUsageClassMicros } from "@opengeni/contracts/insights-usage";
|
|
42
45
|
import { safeErrorDiagnostic } from "./errors";
|
|
43
46
|
|
|
44
47
|
export function modelUsageSourceKey(input: {
|
|
@@ -293,6 +296,7 @@ export async function processModelResponseTerminalEvent(input: {
|
|
|
293
296
|
usage: responseUsage,
|
|
294
297
|
normalizedUsage,
|
|
295
298
|
...(billing ? { billingPath: billing.billingPath } : {}),
|
|
299
|
+
...(billing ? { billingSnapshot: billing } : {}),
|
|
296
300
|
...(billing?.upstreamProvider ? { upstreamProvider: billing.upstreamProvider } : {}),
|
|
297
301
|
servingAccountHash: accountContext.servingAccountHash,
|
|
298
302
|
accountChangedFromPrevCall: accountContext.accountChangedFromPrevCall,
|
|
@@ -439,6 +443,7 @@ export async function processCompactionModelUsageEvent(input: {
|
|
|
439
443
|
usage: input.usage,
|
|
440
444
|
normalizedUsage,
|
|
441
445
|
...(billing ? { billingPath: billing.billingPath } : {}),
|
|
446
|
+
...(billing ? { billingSnapshot: billing } : {}),
|
|
442
447
|
...(billing?.upstreamProvider ? { upstreamProvider: billing.upstreamProvider } : {}),
|
|
443
448
|
servingAccountHash: accountContext.servingAccountHash,
|
|
444
449
|
accountChangedFromPrevCall: accountContext.accountChangedFromPrevCall,
|
|
@@ -492,6 +497,16 @@ export async function emitModelCallUsage(input: {
|
|
|
492
497
|
normalizedUsage?: ModelCallUsageNormalization;
|
|
493
498
|
/** Accepted billing authority persisted for Insights repair after a soft fact-write failure. */
|
|
494
499
|
billingPath?: ModelUsageBillingRecord["billingPath"];
|
|
500
|
+
/** Accepted comparisons are frozen with the event, not repriced during fact repair. */
|
|
501
|
+
billingSnapshot?: Pick<
|
|
502
|
+
ModelUsageBillingRecord,
|
|
503
|
+
| "pricedCostMicros"
|
|
504
|
+
| "estimatedProviderCostMicros"
|
|
505
|
+
| "equivalentCreditCostMicros"
|
|
506
|
+
| "pricingSource"
|
|
507
|
+
| "listByClassMicros"
|
|
508
|
+
| "listByClassApprox"
|
|
509
|
+
>;
|
|
495
510
|
/** Validated Gateway endpoint provider persisted for exact Insights repair. */
|
|
496
511
|
upstreamProvider?: string;
|
|
497
512
|
// Prompt-cache research dimensions (log-only; NEVER on a metric label or a
|
|
@@ -527,6 +542,16 @@ export async function emitModelCallUsage(input: {
|
|
|
527
542
|
sourceKey: input.sourceKey,
|
|
528
543
|
...(input.billingPath ? { billingPath: input.billingPath } : {}),
|
|
529
544
|
...(input.upstreamProvider ? { upstreamProvider: input.upstreamProvider } : {}),
|
|
545
|
+
...(input.billingSnapshot
|
|
546
|
+
? {
|
|
547
|
+
pricedCostMicros: input.billingSnapshot.pricedCostMicros,
|
|
548
|
+
estimatedProviderCostMicros: input.billingSnapshot.estimatedProviderCostMicros,
|
|
549
|
+
equivalentCreditCostMicros: input.billingSnapshot.equivalentCreditCostMicros,
|
|
550
|
+
pricingSource: input.billingSnapshot.pricingSource,
|
|
551
|
+
listByClassMicros: input.billingSnapshot.listByClassMicros ?? null,
|
|
552
|
+
listByClassApprox: input.billingSnapshot.listByClassApprox ?? false,
|
|
553
|
+
}
|
|
554
|
+
: {}),
|
|
530
555
|
...telemetry,
|
|
531
556
|
},
|
|
532
557
|
},
|
|
@@ -605,6 +630,9 @@ export type ModelUsageBillingRecord = {
|
|
|
605
630
|
/** Hypothetical OpenGeni credit price at the captured rate; never a debit. */
|
|
606
631
|
equivalentCreditCostMicros: number | null;
|
|
607
632
|
pricingSource: "configured_list_price" | "gateway_reported" | null;
|
|
633
|
+
/** Forward-only provider list class snapshot; older facts/events stay unknown. */
|
|
634
|
+
listByClassMicros?: InsightsUsageClassMicros | null;
|
|
635
|
+
listByClassApprox?: boolean;
|
|
608
636
|
normalizedUsage: ModelCallUsageNormalization;
|
|
609
637
|
upstreamProvider?: string;
|
|
610
638
|
};
|
|
@@ -665,7 +693,7 @@ export async function recordModelUsageAndDebitCredits(
|
|
|
665
693
|
}
|
|
666
694
|
if (unpinnedWorkspaceGatewayModel && chargesOpenGeniCredits) {
|
|
667
695
|
throw new Error(
|
|
668
|
-
`Workspace Gateway custom model ${input.model} cannot charge
|
|
696
|
+
`Workspace Gateway custom model ${input.model} cannot charge Opengeni credits without pinned pricing`,
|
|
669
697
|
);
|
|
670
698
|
}
|
|
671
699
|
}
|
|
@@ -697,10 +725,30 @@ export async function recordModelUsageAndDebitCredits(
|
|
|
697
725
|
const hasCompleteCoreTokenTelemetry =
|
|
698
726
|
normalizedUsage.telemetry.inputTokens !== null &&
|
|
699
727
|
normalizedUsage.telemetry.outputTokens !== null;
|
|
728
|
+
// Comparison rates are deliberately separate from debit authority. The
|
|
729
|
+
// current usage frame does not establish geography/service-tier provenance,
|
|
730
|
+
// so forward class splits stay unknown even when a total estimate is priced.
|
|
731
|
+
const listPricingSchedules = configuredModelListPricingSchedules(settings);
|
|
732
|
+
const configuredListPricingModel = listPricingSchedules[input.model]
|
|
733
|
+
? input.model
|
|
734
|
+
: input.model.startsWith("codex/") && listPricingSchedules[input.model.slice("codex/".length)]
|
|
735
|
+
? input.model.slice("codex/".length)
|
|
736
|
+
: null;
|
|
737
|
+
const listSnapshot =
|
|
738
|
+
!gatewayBilling && hasCompleteCoreTokenTelemetry && configuredListPricingModel
|
|
739
|
+
? calculateModelListUsageCostSnapshot(settings, configuredListPricingModel, sanitizedUsage, {
|
|
740
|
+
latencyMode: input.latencyMode ?? "standard",
|
|
741
|
+
priceContextKnown: false,
|
|
742
|
+
})
|
|
743
|
+
: null;
|
|
744
|
+
const listClasses = {
|
|
745
|
+
listByClassMicros: listSnapshot?.listByClassMicros ?? null,
|
|
746
|
+
listByClassApprox: listSnapshot?.listByClassApprox ?? false,
|
|
747
|
+
};
|
|
700
748
|
const estimatedProviderCostMicros = gatewayBilling
|
|
701
749
|
? (pricingBreakdown?.providerCostMicros ?? null)
|
|
702
750
|
: hasCompleteCoreTokenTelemetry
|
|
703
|
-
? (pricingBreakdown?.providerCostMicros ?? null)
|
|
751
|
+
? (listSnapshot?.providerCostMicros ?? pricingBreakdown?.providerCostMicros ?? null)
|
|
704
752
|
: null;
|
|
705
753
|
const equivalentCreditCostMicros =
|
|
706
754
|
pricingBreakdown && !unpinnedWorkspaceGatewayModel
|
|
@@ -753,6 +801,7 @@ export async function recordModelUsageAndDebitCredits(
|
|
|
753
801
|
estimatedProviderCostMicros,
|
|
754
802
|
equivalentCreditCostMicros,
|
|
755
803
|
pricingSource,
|
|
804
|
+
...listClasses,
|
|
756
805
|
normalizedUsage,
|
|
757
806
|
...(gatewayBilling ? { upstreamProvider: gatewayBilling.finalProvider } : {}),
|
|
758
807
|
};
|
|
@@ -765,6 +814,7 @@ export async function recordModelUsageAndDebitCredits(
|
|
|
765
814
|
estimatedProviderCostMicros,
|
|
766
815
|
equivalentCreditCostMicros,
|
|
767
816
|
pricingSource,
|
|
817
|
+
...listClasses,
|
|
768
818
|
normalizedUsage,
|
|
769
819
|
...(gatewayBilling ? { upstreamProvider: gatewayBilling.finalProvider } : {}),
|
|
770
820
|
};
|
|
@@ -819,6 +869,7 @@ export async function recordModelUsageAndDebitCredits(
|
|
|
819
869
|
estimatedProviderCostMicros,
|
|
820
870
|
equivalentCreditCostMicros,
|
|
821
871
|
pricingSource,
|
|
872
|
+
...listClasses,
|
|
822
873
|
normalizedUsage,
|
|
823
874
|
...(gatewayBilling ? { upstreamProvider: gatewayBilling.finalProvider } : {}),
|
|
824
875
|
};
|
|
@@ -857,6 +908,8 @@ export async function recordAuthoritativeModelCallFact(input: {
|
|
|
857
908
|
estimatedProviderCostMicros: input.billing.estimatedProviderCostMicros,
|
|
858
909
|
equivalentCreditCostMicros: input.billing.equivalentCreditCostMicros,
|
|
859
910
|
pricingSource: input.billing.pricingSource,
|
|
911
|
+
listByClassMicros: input.billing.listByClassMicros ?? null,
|
|
912
|
+
listByClassApprox: input.billing.listByClassApprox ?? false,
|
|
860
913
|
inputTokens: telemetry.inputTokens,
|
|
861
914
|
outputTokens: telemetry.outputTokens,
|
|
862
915
|
cachedTokens: telemetry.cachedTokens,
|
|
@@ -883,7 +936,9 @@ export function sanitizedModelUsageInput(normalized: ModelCallUsageNormalization
|
|
|
883
936
|
? { outputTokens: normalized.telemetry.outputTokens }
|
|
884
937
|
: {}),
|
|
885
938
|
...(normalized.totalTokens !== null ? { totalTokens: normalized.totalTokens } : {}),
|
|
886
|
-
...(normalized.telemetry.cachedTokens !== null ||
|
|
939
|
+
...(normalized.telemetry.cachedTokens !== null ||
|
|
940
|
+
normalized.telemetry.cacheWriteTokens !== null ||
|
|
941
|
+
normalized.cacheWriteTokensByTtl !== undefined
|
|
887
942
|
? {
|
|
888
943
|
inputTokensDetails: {
|
|
889
944
|
...(normalized.telemetry.cachedTokens === null
|
|
@@ -892,6 +947,12 @@ export function sanitizedModelUsageInput(normalized: ModelCallUsageNormalization
|
|
|
892
947
|
...(normalized.telemetry.cacheWriteTokens === null
|
|
893
948
|
? {}
|
|
894
949
|
: { cache_write_tokens: normalized.telemetry.cacheWriteTokens }),
|
|
950
|
+
...(normalized.cacheWriteTokensByTtl?.fiveMinute == null
|
|
951
|
+
? {}
|
|
952
|
+
: { cache_write_tokens_5m: normalized.cacheWriteTokensByTtl.fiveMinute }),
|
|
953
|
+
...(normalized.cacheWriteTokensByTtl?.oneHour == null
|
|
954
|
+
? {}
|
|
955
|
+
: { cache_write_tokens_1h: normalized.cacheWriteTokensByTtl.oneHour }),
|
|
895
956
|
},
|
|
896
957
|
}
|
|
897
958
|
: {}),
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ModelTransportDispatchClock } from "@opengeni/runtime";
|
|
2
|
+
|
|
3
|
+
type DispatchIdentity = { provider: string; dispatchId: string };
|
|
4
|
+
|
|
5
|
+
/** One immutable physical fetch-entry observation per worker attempt. Generic
|
|
6
|
+
* fallback events already carry that attempt's dispatch/execution identity. */
|
|
7
|
+
export class InitialModelWireDispatchClock {
|
|
8
|
+
private initial: (DispatchIdentity & { initialWireDispatchedAt: string }) | null = null;
|
|
9
|
+
|
|
10
|
+
record(identity: DispatchIdentity, clock: ModelTransportDispatchClock): void {
|
|
11
|
+
if (this.initial !== null) return;
|
|
12
|
+
const timestamp = new Date(clock.dispatchedAtUnixMs);
|
|
13
|
+
if (!Number.isFinite(timestamp.getTime())) return;
|
|
14
|
+
this.initial = { ...identity, initialWireDispatchedAt: timestamp.toISOString() };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
payload(identity: DispatchIdentity): { initialWireDispatchedAt?: string } {
|
|
18
|
+
if (
|
|
19
|
+
this.initial === null ||
|
|
20
|
+
this.initial.provider !== identity.provider ||
|
|
21
|
+
this.initial.dispatchId !== identity.dispatchId
|
|
22
|
+
) {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
return { initialWireDispatchedAt: this.initial.initialWireDispatchedAt };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { Settings } from "@opengeni/config";
|
|
2
|
+
import { resourceMountPath, type ResourceRef } from "@opengeni/contracts";
|
|
3
|
+
import { prReviewRegistrationIdFromCredentialBinding } from "@opengeni/core";
|
|
4
|
+
import { areGitHubRepositoriesAllowedForWorkspace, type Database } from "@opengeni/db";
|
|
5
|
+
import {
|
|
6
|
+
findInaccessibleGitHubAppInstallationRepositories,
|
|
7
|
+
githubAppMissingSettings,
|
|
8
|
+
} from "@opengeni/github";
|
|
9
|
+
import { gitHubTokenAuthorizationSelections } from "../environment";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Turn-time access check for automatically attached (`optional: true`) GitHub
|
|
13
|
+
* App repositories.
|
|
14
|
+
*
|
|
15
|
+
* A Slack-started session attaches the caller's recently used repositories as
|
|
16
|
+
* optional resources. The per-turn workspace-allowlist recheck and the
|
|
17
|
+
* installation-token mint both cover every GitHub repository of the session in
|
|
18
|
+
* one request, so one optional repository that loses access after the session
|
|
19
|
+
* started (an admin removes it from the allowlist, or it is deleted or removed
|
|
20
|
+
* from the App on GitHub) would fail every later turn. Before those checks, this
|
|
21
|
+
* drops each optional repository that is no longer allowlisted or no longer
|
|
22
|
+
* reachable through its installation, for this turn only, and reports it the
|
|
23
|
+
* same way a skipped optional clone is reported. It only ever removes
|
|
24
|
+
* repositories: a remaining repository still passes the unchanged strict
|
|
25
|
+
* allowlist recheck and mint, and an explicitly attached repository is never
|
|
26
|
+
* dropped, so it keeps failing the turn when its access is gone.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
export const OPTIONAL_REPOSITORY_ACCESS_OPERATION = "optional-repository-access";
|
|
30
|
+
|
|
31
|
+
type OptionalRepositoryCandidate = {
|
|
32
|
+
resource: Extract<ResourceRef, { kind: "repository" }>;
|
|
33
|
+
installationId: number;
|
|
34
|
+
repositoryId: number;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type OptionalRepositoryDropReason = "not_allowlisted" | "inaccessible" | "unverified";
|
|
38
|
+
|
|
39
|
+
export type DropUnavailableOptionalRepositoriesInput = {
|
|
40
|
+
db: Database;
|
|
41
|
+
settings: Settings;
|
|
42
|
+
workspaceId: string;
|
|
43
|
+
activeSandboxBackend: Settings["sandboxBackend"] | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* True when a host `gitCredentials` port mints the Git tokens: the host may
|
|
46
|
+
* use another GitHub App, so this deployment's App is not asked.
|
|
47
|
+
*/
|
|
48
|
+
hostMintsGitCredentials: boolean;
|
|
49
|
+
turnResources: readonly ResourceRef[];
|
|
50
|
+
runtimeResources: readonly ResourceRef[];
|
|
51
|
+
/** Publishes one attempt-fenced session event batch. */
|
|
52
|
+
publish: (
|
|
53
|
+
events: Array<{
|
|
54
|
+
type: "sandbox.operation.completed";
|
|
55
|
+
payload: {
|
|
56
|
+
name: typeof OPTIONAL_REPOSITORY_ACCESS_OPERATION;
|
|
57
|
+
repositoryCount: number;
|
|
58
|
+
skippedOptionalRepositories: string[];
|
|
59
|
+
};
|
|
60
|
+
}>,
|
|
61
|
+
) => Promise<void>;
|
|
62
|
+
/** Operational log line; counts only, never repository names. */
|
|
63
|
+
warn: (message: string, fields: Record<string, string>) => void;
|
|
64
|
+
/** Test seam; defaults to the workspace allowlist under RLS. */
|
|
65
|
+
isAllowlisted?: (installationId: number, repositoryId: number) => Promise<boolean>;
|
|
66
|
+
/** Test seam; defaults to a live GitHub App token-mint probe. */
|
|
67
|
+
findInaccessible?: (installationId: number, repositoryIds: number[]) => Promise<number[]>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
function optionalGitHubAppRepositoryCandidate(
|
|
71
|
+
resource: ResourceRef,
|
|
72
|
+
): OptionalRepositoryCandidate | null {
|
|
73
|
+
if (resource.kind !== "repository" || resource.optional !== true) return null;
|
|
74
|
+
let selections: ReturnType<typeof gitHubTokenAuthorizationSelections>;
|
|
75
|
+
try {
|
|
76
|
+
// The exact selection the allowlist recheck and the mint derive, so the
|
|
77
|
+
// decision here covers precisely what those strict steps would check.
|
|
78
|
+
selections = gitHubTokenAuthorizationSelections([resource]);
|
|
79
|
+
} catch {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const [selection] = selections;
|
|
83
|
+
if (!selection || selections.length !== 1 || selection.repositoryIds.length !== 1) return null;
|
|
84
|
+
// PR-review bindings are authorized by their own registration, not the
|
|
85
|
+
// workspace allowlist; they are never automatically attached.
|
|
86
|
+
if (prReviewRegistrationIdFromCredentialBinding(selection.credentialBindingId)) return null;
|
|
87
|
+
return {
|
|
88
|
+
resource,
|
|
89
|
+
installationId: selection.installationId,
|
|
90
|
+
repositoryId: selection.repositoryIds[0]!,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function repositoryIdentity(resource: ResourceRef): string | null {
|
|
95
|
+
return resource.kind === "repository"
|
|
96
|
+
? `${resource.uri}\u0000${resourceMountPath(resource)}`
|
|
97
|
+
: null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function dropUnavailableOptionalRepositories(
|
|
101
|
+
input: DropUnavailableOptionalRepositoriesInput,
|
|
102
|
+
): Promise<{
|
|
103
|
+
turnResources: ResourceRef[];
|
|
104
|
+
runtimeResources: ResourceRef[];
|
|
105
|
+
/**
|
|
106
|
+
* The same decision for another view of this turn's resources (the GitHub
|
|
107
|
+
* REST tool surface is built from the unbound session resources).
|
|
108
|
+
*/
|
|
109
|
+
retainsResource: (resource: ResourceRef) => boolean;
|
|
110
|
+
}> {
|
|
111
|
+
const passthrough = {
|
|
112
|
+
turnResources: [...input.turnResources],
|
|
113
|
+
runtimeResources: [...input.runtimeResources],
|
|
114
|
+
retainsResource: () => true,
|
|
115
|
+
};
|
|
116
|
+
// A Connected Machine receives no platform Git credential and runs neither
|
|
117
|
+
// the allowlist recheck nor the mint, so nothing can fail there.
|
|
118
|
+
if (input.activeSandboxBackend === "selfhosted") return passthrough;
|
|
119
|
+
const candidates = input.turnResources.flatMap(
|
|
120
|
+
(resource) => optionalGitHubAppRepositoryCandidate(resource) ?? [],
|
|
121
|
+
);
|
|
122
|
+
if (candidates.length === 0) return passthrough;
|
|
123
|
+
|
|
124
|
+
const isAllowlisted =
|
|
125
|
+
input.isAllowlisted ??
|
|
126
|
+
((installationId: number, repositoryId: number) =>
|
|
127
|
+
areGitHubRepositoriesAllowedForWorkspace(input.db, input.workspaceId, installationId, [
|
|
128
|
+
repositoryId,
|
|
129
|
+
]));
|
|
130
|
+
const dropped = new Map<OptionalRepositoryCandidate, OptionalRepositoryDropReason>();
|
|
131
|
+
const allowlisted: OptionalRepositoryCandidate[] = [];
|
|
132
|
+
const admitted = await Promise.all(
|
|
133
|
+
candidates.map(async (candidate) => {
|
|
134
|
+
try {
|
|
135
|
+
return (await isAllowlisted(candidate.installationId, candidate.repositoryId))
|
|
136
|
+
? ("allowlisted" as const)
|
|
137
|
+
: ("not_allowlisted" as const);
|
|
138
|
+
} catch {
|
|
139
|
+
// The check itself failed: an optional repository must not fail the
|
|
140
|
+
// turn, so it sits this turn out like an unverifiable GitHub answer.
|
|
141
|
+
return "unverified" as const;
|
|
142
|
+
}
|
|
143
|
+
}),
|
|
144
|
+
);
|
|
145
|
+
candidates.forEach((candidate, index) => {
|
|
146
|
+
const outcome = admitted[index]!;
|
|
147
|
+
if (outcome === "allowlisted") allowlisted.push(candidate);
|
|
148
|
+
else dropped.set(candidate, outcome);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const findInaccessible =
|
|
152
|
+
input.findInaccessible ??
|
|
153
|
+
(!input.hostMintsGitCredentials && githubAppMissingSettings(input.settings).length === 0
|
|
154
|
+
? (installationId: number, repositoryIds: number[]) =>
|
|
155
|
+
findInaccessibleGitHubAppInstallationRepositories(input.settings, {
|
|
156
|
+
installationId,
|
|
157
|
+
repositoryIds,
|
|
158
|
+
})
|
|
159
|
+
: null);
|
|
160
|
+
if (findInaccessible && allowlisted.length > 0) {
|
|
161
|
+
const byInstallation = new Map<number, OptionalRepositoryCandidate[]>();
|
|
162
|
+
for (const candidate of allowlisted) {
|
|
163
|
+
const group = byInstallation.get(candidate.installationId) ?? [];
|
|
164
|
+
group.push(candidate);
|
|
165
|
+
byInstallation.set(candidate.installationId, group);
|
|
166
|
+
}
|
|
167
|
+
await Promise.all(
|
|
168
|
+
[...byInstallation].map(async ([installationId, group]) => {
|
|
169
|
+
try {
|
|
170
|
+
const inaccessible = new Set(
|
|
171
|
+
await findInaccessible(
|
|
172
|
+
installationId,
|
|
173
|
+
group.map((candidate) => candidate.repositoryId),
|
|
174
|
+
),
|
|
175
|
+
);
|
|
176
|
+
for (const candidate of group) {
|
|
177
|
+
if (inaccessible.has(candidate.repositoryId)) dropped.set(candidate, "inaccessible");
|
|
178
|
+
}
|
|
179
|
+
} catch {
|
|
180
|
+
// GitHub could not answer. An optional repository must never fail
|
|
181
|
+
// the turn, and keeping it would put it into a mint GitHub may then
|
|
182
|
+
// refuse, so it sits this turn out and is checked again next turn.
|
|
183
|
+
for (const candidate of group) dropped.set(candidate, "unverified");
|
|
184
|
+
}
|
|
185
|
+
}),
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
if (dropped.size === 0) return passthrough;
|
|
189
|
+
|
|
190
|
+
const droppedIdentities = new Set(
|
|
191
|
+
[...dropped.keys()].flatMap((candidate) => repositoryIdentity(candidate.resource) ?? []),
|
|
192
|
+
);
|
|
193
|
+
const keep = (resource: ResourceRef): boolean => {
|
|
194
|
+
if (resource.kind !== "repository" || resource.optional !== true) return true;
|
|
195
|
+
const identity = repositoryIdentity(resource);
|
|
196
|
+
return identity === null || !droppedIdentities.has(identity);
|
|
197
|
+
};
|
|
198
|
+
const reasons = [...dropped.values()];
|
|
199
|
+
input.warn("optional repository resources were dropped for this turn", {
|
|
200
|
+
droppedCount: String(dropped.size),
|
|
201
|
+
notAllowlistedCount: String(reasons.filter((reason) => reason === "not_allowlisted").length),
|
|
202
|
+
inaccessibleCount: String(reasons.filter((reason) => reason === "inaccessible").length),
|
|
203
|
+
unverifiedCount: String(reasons.filter((reason) => reason === "unverified").length),
|
|
204
|
+
origin: "worker",
|
|
205
|
+
});
|
|
206
|
+
await input.publish([
|
|
207
|
+
{
|
|
208
|
+
type: "sandbox.operation.completed",
|
|
209
|
+
payload: {
|
|
210
|
+
name: OPTIONAL_REPOSITORY_ACCESS_OPERATION,
|
|
211
|
+
repositoryCount: input.turnResources.filter((resource) => resource.kind === "repository")
|
|
212
|
+
.length,
|
|
213
|
+
skippedOptionalRepositories: [
|
|
214
|
+
...new Set([...dropped.keys()].map((candidate) => resourceMountPath(candidate.resource))),
|
|
215
|
+
].sort(),
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
]);
|
|
219
|
+
return {
|
|
220
|
+
turnResources: input.turnResources.filter(keep),
|
|
221
|
+
runtimeResources: input.runtimeResources.filter(keep),
|
|
222
|
+
retainsResource: keep,
|
|
223
|
+
};
|
|
224
|
+
}
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
import type { TurnHistorySink } from "./history-sink";
|
|
2
|
+
import type { Settings } from "@opengeni/config";
|
|
3
|
+
|
|
4
|
+
export class SandboxCapabilitiesChangedError extends Error {
|
|
5
|
+
readonly code = "native_capabilities_changed_this_attempt";
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super("The attached sandbox requires rebuilding this attempt's native capabilities.");
|
|
9
|
+
this.name = "SandboxCapabilitiesChangedError";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
2
12
|
|
|
3
13
|
/**
|
|
4
14
|
* Persist the SDK's complete prior model/tool history before another provider
|
|
@@ -8,6 +18,18 @@ import type { TurnHistorySink } from "./history-sink";
|
|
|
8
18
|
*/
|
|
9
19
|
export async function checkpointHistoryBeforeProviderDispatch(
|
|
10
20
|
historySink: Pick<TurnHistorySink, "reconcileConversationTruth">,
|
|
21
|
+
route?: {
|
|
22
|
+
effectiveSandboxBackend: Settings["sandboxBackend"];
|
|
23
|
+
routingEnabled: boolean;
|
|
24
|
+
readActiveSandbox: () => Promise<{ activeSandboxId: string | null } | null>;
|
|
25
|
+
},
|
|
11
26
|
): Promise<void> {
|
|
12
27
|
await historySink.reconcileConversationTruth({ requireDurable: true });
|
|
28
|
+
// A plain Agent cannot acquire SandboxAgent capabilities in place. Preserve
|
|
29
|
+
// its completed tool batch before recovering the same logical turn; the next
|
|
30
|
+
// attempt resolves and authorizes the route normally.
|
|
31
|
+
if (route?.effectiveSandboxBackend === "none" && route.routingEnabled) {
|
|
32
|
+
const active = await route.readActiveSandbox();
|
|
33
|
+
if (active?.activeSandboxId) throw new SandboxCapabilitiesChangedError();
|
|
34
|
+
}
|
|
13
35
|
}
|
|
@@ -91,10 +91,9 @@ export const QUIESCENCE_PROOF_SIGNAL_MAX_RETRY_MS = 5_000;
|
|
|
91
91
|
export const TURN_QUIESCENCE_WATCHDOG_MS = 5 * 60_000;
|
|
92
92
|
export const TURN_FINALIZER_STEP_TIMEOUT_MS = 30_000;
|
|
93
93
|
|
|
94
|
-
/** A fenced activity must never heartbeat forever while
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
* then commits the exact quiescence receipt. */
|
|
94
|
+
/** A fenced activity must never heartbeat forever while physical cleanup is
|
|
95
|
+
* stuck. The callback requests host-owned containment, which drains peer turns
|
|
96
|
+
* before applying its final exit policy. A timeout is never quiescence proof. */
|
|
98
97
|
export function armTurnQuiescenceWatchdog(input: {
|
|
99
98
|
enabled: boolean;
|
|
100
99
|
timeoutMs?: number;
|
|
@@ -198,13 +197,16 @@ export async function drainAttemptOwnedSandboxWriters(input: {
|
|
|
198
197
|
gitCredentialRenewals: readonly Pick<GitCredentialRenewalController, "stop">[];
|
|
199
198
|
codemodeTokenRenewal: Pick<CodemodeTokenRenewalController, "stop"> | null;
|
|
200
199
|
runCredentialRenewal: Pick<RunCredentialRenewalController, "stop"> | null;
|
|
200
|
+
onStage?: (stage: "tool_writers" | "credential_renewals") => void;
|
|
201
201
|
}): Promise<void> {
|
|
202
|
+
input.onStage?.("tool_writers");
|
|
202
203
|
if (input.toolCancellationFence) {
|
|
203
204
|
input.toolCancellationFence.cancel(
|
|
204
205
|
input.cancellationReason ?? new Error("TURN_ATTEMPT_FENCED"),
|
|
205
206
|
);
|
|
206
207
|
await input.toolCancellationFence.waitForQuiescence();
|
|
207
208
|
}
|
|
209
|
+
input.onStage?.("credential_renewals");
|
|
208
210
|
await Promise.all(input.gitCredentialRenewals.map(async (renewal) => await renewal.stop()));
|
|
209
211
|
await input.codemodeTokenRenewal?.stop();
|
|
210
212
|
await input.runCredentialRenewal?.stop();
|
|
@@ -432,13 +434,14 @@ export async function runMandatoryHistoryPersistenceStep<T>(
|
|
|
432
434
|
}
|
|
433
435
|
|
|
434
436
|
export type OpStreamFinalizer = {
|
|
435
|
-
finalizeOpStreamOps(): Promise<void>;
|
|
437
|
+
finalizeOpStreamOps(toolCallIds?: readonly string[]): Promise<void>;
|
|
436
438
|
};
|
|
437
439
|
|
|
438
|
-
/** Release
|
|
440
|
+
/** Release only durably recorded tool results, or the complete durable turn. */
|
|
439
441
|
export async function finalizeDurableTurnOpStreams(
|
|
440
442
|
sessions: readonly unknown[],
|
|
441
443
|
fallback: OpStreamFinalizer | null,
|
|
444
|
+
toolCallIds?: readonly string[],
|
|
442
445
|
): Promise<void> {
|
|
443
446
|
const candidates = new Set<OpStreamFinalizer>();
|
|
444
447
|
for (const session of sessions) {
|
|
@@ -452,7 +455,7 @@ export async function finalizeDurableTurnOpStreams(
|
|
|
452
455
|
}
|
|
453
456
|
for (const candidate of candidates) {
|
|
454
457
|
try {
|
|
455
|
-
await candidate.finalizeOpStreamOps();
|
|
458
|
+
await candidate.finalizeOpStreamOps(toolCallIds);
|
|
456
459
|
} catch {
|
|
457
460
|
// The runner's retention TTL owns the fallback.
|
|
458
461
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getSandboxRecoveryDiscontinuity, type Database } from "@opengeni/db";
|
|
2
|
+
|
|
3
|
+
/** v2 also recognizes system-selected checkpoint fallback receipts, and v3
|
|
4
|
+
* the empty-workspace continuation receipts. A worker below the version a
|
|
5
|
+
* session's receipts require cannot claim it (migrations 0526 and 0548). */
|
|
6
|
+
export const FILESYSTEM_DISCONTINUITY_PROTOCOL = 3 as const;
|
|
7
|
+
|
|
8
|
+
export async function recoveryAwareSessionInstructions(
|
|
9
|
+
db: Database,
|
|
10
|
+
workspaceId: string,
|
|
11
|
+
session: { id: string; instructions?: string | null },
|
|
12
|
+
readDiscontinuity: typeof getSandboxRecoveryDiscontinuity = getSandboxRecoveryDiscontinuity,
|
|
13
|
+
): Promise<string> {
|
|
14
|
+
const filesystemDiscontinuity = await readDiscontinuity(db, workspaceId, session.id);
|
|
15
|
+
return [session.instructions, filesystemDiscontinuity].filter(Boolean).join("\n\n");
|
|
16
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { AttemptToolDefinition } from "@opengeni/codemode";
|
|
2
|
+
|
|
3
|
+
export const REFRESH_CREDENTIALS_TOOL_NAME = "refresh_credentials";
|
|
4
|
+
|
|
5
|
+
export const REFRESH_CREDENTIALS_TOOL_DESCRIPTION =
|
|
6
|
+
"Fetch fresh host-managed credentials for this sandbox now. Use it when a command fails because a token or credential file provided by the workspace has expired or been revoked. The environment variables and credential files that the host manages are replaced for the next command; commands that are already running keep what they started with.";
|
|
7
|
+
|
|
8
|
+
export function createRefreshCredentialsAttemptToolDefinition(input: {
|
|
9
|
+
refresh: () => Promise<"completed" | "auth_needed" | "error" | "not_provisioned">;
|
|
10
|
+
}): AttemptToolDefinition {
|
|
11
|
+
return {
|
|
12
|
+
identity: { serverId: "opengeni", toolName: REFRESH_CREDENTIALS_TOOL_NAME },
|
|
13
|
+
modelName: REFRESH_CREDENTIALS_TOOL_NAME,
|
|
14
|
+
codemodePath: ["opengeni", REFRESH_CREDENTIALS_TOOL_NAME],
|
|
15
|
+
title: "Refresh credentials",
|
|
16
|
+
description: REFRESH_CREDENTIALS_TOOL_DESCRIPTION,
|
|
17
|
+
inputSchema: { type: "object", properties: {}, additionalProperties: false },
|
|
18
|
+
annotations: {
|
|
19
|
+
title: "Refresh credentials",
|
|
20
|
+
readOnlyHint: false,
|
|
21
|
+
destructiveHint: false,
|
|
22
|
+
idempotentHint: true,
|
|
23
|
+
openWorldHint: true,
|
|
24
|
+
},
|
|
25
|
+
source: "opengeni",
|
|
26
|
+
approval: "none",
|
|
27
|
+
execute: async (args) => {
|
|
28
|
+
if (Object.keys(args).length !== 0) {
|
|
29
|
+
throw new Error(`${REFRESH_CREDENTIALS_TOOL_NAME} accepts no arguments`);
|
|
30
|
+
}
|
|
31
|
+
const outcome = await input.refresh();
|
|
32
|
+
const text = {
|
|
33
|
+
completed: "Credentials refreshed. Retry the command that failed.",
|
|
34
|
+
auth_needed:
|
|
35
|
+
"The host returned credentials that need user attention (reconnect or grant access). Continue with what is available and tell the user which service needs reconnecting.",
|
|
36
|
+
error:
|
|
37
|
+
"The credential provider could not be reached. The previous credentials are still in place and a retry is scheduled.",
|
|
38
|
+
not_provisioned:
|
|
39
|
+
"Credentials are provisioned when the sandbox first starts; run a command and they will be fetched then.",
|
|
40
|
+
}[outcome];
|
|
41
|
+
return { isError: outcome === "error", content: [{ type: "text", text }] };
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|