@opengeni/worker-bundle 2.2.0 → 2.2.1-canary.36927100590001
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 +1 -0
- package/dist/activities/agent-turn/claude-usage-observer.d.ts +13 -1
- package/dist/activities/agent-turn/compaction-prep.d.ts +20 -0
- package/dist/activities/agent-turn/credential-restriction.d.ts +3 -0
- package/dist/activities/agent-turn/final-reply.d.ts +18 -0
- package/dist/activities/agent-turn/governance-model.d.ts +6 -0
- package/dist/activities/agent-turn/model-call-admission.d.ts +15 -0
- package/dist/activities/agent-turn/run-credentials.d.ts +4 -0
- package/dist/activities/agent-turn/sandbox-establish.d.ts +1 -0
- package/dist/activities/agent-turn/session-title.d.ts +3 -1
- package/dist/activities/agent-turn/stream-attempt.d.ts +1 -0
- package/dist/activities/agent-turn/turn-context.d.ts +1 -0
- package/dist/activities/automations.d.ts +3 -1
- package/dist/activities/browser-deadline-checkpoint.d.ts +29 -0
- package/dist/activities/goals.d.ts +8 -0
- package/dist/activities/run-credentials.d.ts +4 -2
- package/dist/activities/scheduled-tasks.d.ts +4 -35
- package/dist/activities/types.d.ts +4 -1
- package/dist/activities/workspace-capture.d.ts +2 -0
- package/dist/{activities-control-MHNA3CYV.js → activities-control-4F2A734B.js} +502 -133
- package/dist/activities-control-4F2A734B.js.map +1 -0
- package/dist/activities-control.d.ts +30 -0
- package/dist/{activities-turn-FQ5OO2WW.js → activities-turn-TESOIOEX.js} +696 -251
- package/dist/activities-turn-TESOIOEX.js.map +1 -0
- package/dist/activities.d.ts +30 -0
- package/dist/browser-deadline-checkpoint-contract.d.ts +2 -0
- package/dist/{chunk-RZAAGRFQ.js → chunk-4PJTUBWQ.js} +220 -88
- package/dist/chunk-4PJTUBWQ.js.map +1 -0
- package/dist/{chunk-IJZU752L.js → chunk-YG27NEMX.js} +34 -1
- package/dist/chunk-YG27NEMX.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +46 -24
- package/dist/index.js.map +1 -1
- package/dist/observability-metrics.d.ts +16 -1
- package/dist/sandbox-resume.d.ts +4 -1
- package/dist/workflow-bundle.js +89 -21
- package/dist/workflows/browser-deadline-checkpoint.d.ts +9 -0
- package/dist/workflows/scheduled-tasks.d.ts +4 -0
- package/dist/workflows.d.ts +1 -0
- package/package.json +21 -20
- package/src/activities/agent-run-admission.ts +17 -1
- package/src/activities/agent-turn/admission.ts +64 -1
- package/src/activities/agent-turn/agent-build.ts +24 -3
- package/src/activities/agent-turn/claim.ts +69 -15
- package/src/activities/agent-turn/claude-usage-observer.ts +33 -1
- package/src/activities/agent-turn/compaction-prep.ts +67 -16
- package/src/activities/agent-turn/credential-restriction.ts +14 -0
- package/src/activities/agent-turn/errors.ts +55 -0
- package/src/activities/agent-turn/failure-settlement.ts +26 -6
- package/src/activities/agent-turn/final-reply.ts +46 -0
- package/src/activities/agent-turn/governance-model.ts +12 -0
- package/src/activities/agent-turn/model-call-admission.ts +94 -0
- package/src/activities/agent-turn/run-credentials.ts +20 -3
- package/src/activities/agent-turn/run.ts +44 -5
- package/src/activities/agent-turn/sandbox-establish.ts +9 -5
- package/src/activities/agent-turn/session-title.ts +8 -2
- package/src/activities/agent-turn/stream-attempt.ts +144 -38
- package/src/activities/agent-turn/tool-environment.ts +55 -39
- package/src/activities/agent-turn/turn-context.ts +1 -0
- package/src/activities/automations.ts +78 -4
- package/src/activities/browser-deadline-checkpoint.ts +279 -0
- package/src/activities/capabilities.ts +52 -14
- package/src/activities/goals.ts +95 -98
- package/src/activities/knowledge-indexing.ts +29 -0
- package/src/activities/open-suffix-resume.ts +2 -1
- package/src/activities/run-credentials.ts +22 -16
- package/src/activities/sandbox-lease.ts +22 -0
- package/src/activities/scheduled-tasks.ts +172 -38
- package/src/activities/site-auth-maintenance.ts +1 -0
- package/src/activities/types.ts +4 -0
- package/src/activities/workspace-capture.ts +13 -2
- package/src/activities/workspace-credential-provider.ts +12 -0
- package/src/activities-control.ts +2 -0
- package/src/activities.ts +3 -0
- package/src/browser-deadline-checkpoint-contract.ts +5 -0
- package/src/index.ts +53 -25
- package/src/observability-metrics.ts +55 -1
- package/src/sandbox-resume.ts +23 -8
- package/src/sandbox-routing.ts +4 -2
- package/src/workflows/browser-deadline-checkpoint.ts +50 -0
- package/src/workflows/scheduled-tasks.ts +26 -13
- package/src/workflows.ts +4 -0
- package/dist/activities-control-MHNA3CYV.js.map +0 -1
- package/dist/activities-turn-FQ5OO2WW.js.map +0 -1
- package/dist/chunk-IJZU752L.js.map +0 -1
- package/dist/chunk-RZAAGRFQ.js.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { BrowserDeadlineCheckpointTarget } from "@opengeni/db";
|
|
2
|
+
export declare function browserDeadlineCheckpointWorkflow(target: BrowserDeadlineCheckpointTarget): Promise<{
|
|
3
|
+
status: "skipped";
|
|
4
|
+
} | {
|
|
5
|
+
status: "suspended";
|
|
6
|
+
}>;
|
|
7
|
+
/** Runs from the existing lease-sweep dispatch. Inventory never performs provider
|
|
8
|
+
* I/O; each exact browser has an independent durable capture/cleanup child. */
|
|
9
|
+
export declare function browserDeadlineCheckpointSweepWorkflow(): Promise<void>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TurnInitiator } from "@opengeni/contracts";
|
|
2
|
+
import type { DispatchScheduledTaskRunInput } from "../activities/types.js";
|
|
2
3
|
type ScheduledTaskFireWorkflowBase = {
|
|
3
4
|
accountId: string;
|
|
4
5
|
workspaceId: string;
|
|
@@ -8,10 +9,13 @@ export type ScheduledTaskFireWorkflowInput = ScheduledTaskFireWorkflowBase & ({
|
|
|
8
9
|
triggerType: "scheduled";
|
|
9
10
|
agentRunUsageIdempotencyKey?: never;
|
|
10
11
|
initiator?: never;
|
|
12
|
+
credentialRestriction?: never;
|
|
11
13
|
} | {
|
|
12
14
|
triggerType: "manual" | "initial" | "provider_event" | "retry" | "repair";
|
|
13
15
|
agentRunUsageIdempotencyKey: string;
|
|
14
16
|
initiator: TurnInitiator;
|
|
17
|
+
credentialRestriction?: "developer_setup";
|
|
15
18
|
});
|
|
19
|
+
export declare function scheduledTaskDispatchInput(input: ScheduledTaskFireWorkflowInput, producerKey: string): DispatchScheduledTaskRunInput;
|
|
16
20
|
export declare function scheduledTaskFireWorkflow(input: ScheduledTaskFireWorkflowInput): Promise<void>;
|
|
17
21
|
export {};
|
package/dist/workflows.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { automationRunWorkflow, type AutomationRunWorkflowInput } from "./workfl
|
|
|
6
6
|
export { knowledgeSourceSyncWake, knowledgeSourceSyncWorkflow, knowledgeSourceSyncWorkflowId, type KnowledgeSourceSyncWorkflowInput, } from "./workflows/knowledge-source-sync.js";
|
|
7
7
|
export { sandboxDrainWorkflow, sandboxReaperMaintenanceWorkflow, sandboxReaperWorkflow, sandboxReaperWorkflowV2, } from "./workflows/sandbox-reaper.js";
|
|
8
8
|
export { fileUploadReaperWorkflow } from "./workflows/file-upload-reaper.js";
|
|
9
|
+
export { browserDeadlineCheckpointWorkflow, browserDeadlineCheckpointSweepWorkflow, } from "./workflows/browser-deadline-checkpoint.js";
|
|
9
10
|
export { siteAuthMaintenanceWorkflow } from "./workflows/site-auth-maintenance.js";
|
|
10
11
|
export { videoGenerationWorkflow, videoGenerationWorkflowId, type VideoGenerationWorkflowInput, } from "./workflows/video-generation.js";
|
|
11
12
|
export { sessionWorkflowWakeDispatcherWorkflow } from "./workflows/workflow-wake.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/worker-bundle",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1-canary.36927100590001",
|
|
4
4
|
"description": "OpenGeni worker entry and reusable embedded lifecycle, shipped with a release-coherent pre-bundled Temporal workflow artifact.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -54,25 +54,26 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@llamaindex/liteparse": "2.14.2",
|
|
57
|
-
"@opengeni/agent-proto": "^0.6.
|
|
58
|
-
"@opengeni/capabilities": "^0.3.
|
|
59
|
-
"@opengeni/codemode": "^0.6.
|
|
60
|
-
"@opengeni/codex": "^0.2.
|
|
61
|
-
"@opengeni/config": "^3.
|
|
62
|
-
"@opengeni/contracts": "^5.
|
|
63
|
-
"@opengeni/core": "^5.0.
|
|
64
|
-
"@opengeni/db": "^6.
|
|
65
|
-
"@opengeni/documents": "^0.8.
|
|
66
|
-
"@opengeni/events": "^0.4.
|
|
67
|
-
"@opengeni/github": "^0.8.
|
|
68
|
-
"@opengeni/
|
|
69
|
-
"@opengeni/
|
|
70
|
-
"@opengeni/
|
|
71
|
-
"@opengeni/
|
|
72
|
-
"@opengeni/
|
|
73
|
-
"@opengeni/
|
|
74
|
-
"@opengeni/
|
|
75
|
-
"@opengeni/
|
|
57
|
+
"@opengeni/agent-proto": "^0.6.1-canary.36927100590001",
|
|
58
|
+
"@opengeni/capabilities": "^0.3.5-canary.36927100590001",
|
|
59
|
+
"@opengeni/codemode": "^0.6.6-canary.36927100590001",
|
|
60
|
+
"@opengeni/codex": "^0.2.30-canary.36927100590001",
|
|
61
|
+
"@opengeni/config": "^3.2.0-canary.36927100590001",
|
|
62
|
+
"@opengeni/contracts": "^5.5.0-canary.36927100590001",
|
|
63
|
+
"@opengeni/core": "^5.0.1-canary.36927100590001",
|
|
64
|
+
"@opengeni/db": "^6.3.0-canary.36927100590001",
|
|
65
|
+
"@opengeni/documents": "^0.8.38-canary.36927100590001",
|
|
66
|
+
"@opengeni/events": "^0.4.36-canary.36927100590001",
|
|
67
|
+
"@opengeni/github": "^0.8.1-canary.36927100590001",
|
|
68
|
+
"@opengeni/interaction": "^0.4.44-canary.36927100590001",
|
|
69
|
+
"@opengeni/jev": "^0.2.1-canary.36927100590001",
|
|
70
|
+
"@opengeni/network": "^0.3.1-canary.36927100590001",
|
|
71
|
+
"@opengeni/observability": "^0.8.36-canary.36927100590001",
|
|
72
|
+
"@opengeni/runtime": "^4.4.0-canary.36927100590001",
|
|
73
|
+
"@opengeni/sdk": "^7.5.0-canary.36927100590001",
|
|
74
|
+
"@opengeni/storage": "^0.2.137-canary.36927100590001",
|
|
75
|
+
"@opengeni/tool-gateway": "^0.1.17-canary.36927100590001",
|
|
76
|
+
"@opengeni/xai-subscription": "^0.1.5-canary.36927100590001",
|
|
76
77
|
"@temporalio/activity": "^1.17.0",
|
|
77
78
|
"@temporalio/client": "^1.17.0",
|
|
78
79
|
"@temporalio/worker": "^1.17.0",
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { configuredStaticUsageLimits, type Settings } from "@opengeni/config";
|
|
2
2
|
import { modelFundingForAdmission } from "@opengeni/core";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
checkWorkspaceAllowance,
|
|
5
|
+
getBillingBalance,
|
|
6
|
+
isCodexBilledTurn,
|
|
7
|
+
sumUsageQuantity,
|
|
8
|
+
} from "@opengeni/db";
|
|
4
9
|
import type { ControlActivityServices } from "./types";
|
|
5
10
|
|
|
6
11
|
export type AgentRunAdmissionDenial =
|
|
7
12
|
| "insufficient_credits"
|
|
13
|
+
| "allowance_exhausted"
|
|
8
14
|
| "monthly_model_cost_limit"
|
|
9
15
|
| "monthly_agent_run_limit";
|
|
10
16
|
|
|
@@ -16,6 +22,8 @@ export async function agentRunAdmissionDenial(
|
|
|
16
22
|
workspaceId: string;
|
|
17
23
|
model: string;
|
|
18
24
|
requestedAgentRuns: number;
|
|
25
|
+
/** The accepted work's causal human, not the scheduler/service caller. */
|
|
26
|
+
initiatingHumanSubjectId?: string | null;
|
|
19
27
|
},
|
|
20
28
|
): Promise<AgentRunAdmissionDenial | null> {
|
|
21
29
|
const codexBilled = await isCodexBilledTurn({
|
|
@@ -46,6 +54,14 @@ export async function agentRunAdmissionDenial(
|
|
|
46
54
|
if (balance.balanceMicros <= 0) return "insufficient_credits";
|
|
47
55
|
}
|
|
48
56
|
}
|
|
57
|
+
if (!externallyBilled) {
|
|
58
|
+
const refusal = await checkWorkspaceAllowance(services.db, {
|
|
59
|
+
accountId: input.accountId,
|
|
60
|
+
workspaceId: input.workspaceId,
|
|
61
|
+
subjectId: input.initiatingHumanSubjectId ?? null,
|
|
62
|
+
});
|
|
63
|
+
if (refusal) return refusal.code;
|
|
64
|
+
}
|
|
49
65
|
if (
|
|
50
66
|
services.settings.usageLimitsMode !== "static" &&
|
|
51
67
|
services.settings.usageLimitsMode !== "managed"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getBillingBalance, sumUsageQuantity } from "@opengeni/db";
|
|
1
|
+
import { checkWorkspaceAllowance, getBillingBalance, sumUsageQuantity } from "@opengeni/db";
|
|
2
2
|
import {
|
|
3
3
|
configuredStaticUsageLimits,
|
|
4
4
|
resolveTurnExecutionPolicyV1,
|
|
@@ -8,6 +8,7 @@ import { selectCodexCredentialId } from "@opengeni/codex";
|
|
|
8
8
|
import { directPersonalConnectionSubjectId } from "@opengeni/core";
|
|
9
9
|
import type { TurnActivityServices as ActivityServices } from "../types";
|
|
10
10
|
import {
|
|
11
|
+
type AllowanceExhaustedRefusal,
|
|
11
12
|
type SessionEvent,
|
|
12
13
|
type SessionTurn,
|
|
13
14
|
type ToolAuthNeededPayload,
|
|
@@ -243,12 +244,65 @@ export class BudgetExhaustedError extends Error {
|
|
|
243
244
|
constructor(
|
|
244
245
|
message: string,
|
|
245
246
|
readonly serializedRunState: string | null,
|
|
247
|
+
readonly allowance: AllowanceRefusal | null = null,
|
|
246
248
|
) {
|
|
247
249
|
super(message);
|
|
248
250
|
this.name = "BudgetExhaustedError";
|
|
249
251
|
}
|
|
250
252
|
}
|
|
251
253
|
|
|
254
|
+
export type AllowanceRefusal = AllowanceExhaustedRefusal;
|
|
255
|
+
|
|
256
|
+
/** Account allowance exhaustion is recoverable state, never a provider failure. */
|
|
257
|
+
export class AllowanceExhaustedError extends Error {
|
|
258
|
+
readonly code = "allowance_exhausted";
|
|
259
|
+
|
|
260
|
+
constructor(readonly refusal: AllowanceRefusal) {
|
|
261
|
+
super(refusal.message);
|
|
262
|
+
this.name = "AllowanceExhaustedError";
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/** Revalidate between paid calls without replaying provider work or reserving credits. */
|
|
267
|
+
export async function ensureRunAllowedBetweenModelCalls(input: {
|
|
268
|
+
settings: Settings;
|
|
269
|
+
db: ActivityServices["db"];
|
|
270
|
+
accountId: string;
|
|
271
|
+
workspaceId: string;
|
|
272
|
+
isExternallyBilledTurn: boolean;
|
|
273
|
+
entitlements?: ActivityServices["entitlements"];
|
|
274
|
+
chargesOpenGeniCredits: boolean;
|
|
275
|
+
countsTowardTokenCap: boolean;
|
|
276
|
+
initiatingHumanSubjectId: string | null;
|
|
277
|
+
serializedRunState?: () => string | null;
|
|
278
|
+
}): Promise<void> {
|
|
279
|
+
try {
|
|
280
|
+
await ensureRunAllowed(
|
|
281
|
+
input.settings,
|
|
282
|
+
input.db,
|
|
283
|
+
input.accountId,
|
|
284
|
+
input.workspaceId,
|
|
285
|
+
input.isExternallyBilledTurn,
|
|
286
|
+
input.entitlements,
|
|
287
|
+
input.chargesOpenGeniCredits,
|
|
288
|
+
input.countsTowardTokenCap,
|
|
289
|
+
input.initiatingHumanSubjectId,
|
|
290
|
+
);
|
|
291
|
+
} catch (limitError) {
|
|
292
|
+
let serializedRunState: string | null = null;
|
|
293
|
+
try {
|
|
294
|
+
serializedRunState = input.serializedRunState?.() ?? null;
|
|
295
|
+
} catch {
|
|
296
|
+
// Durable history remains authoritative when the SDK state cannot serialize.
|
|
297
|
+
}
|
|
298
|
+
throw new BudgetExhaustedError(
|
|
299
|
+
limitError instanceof Error ? limitError.message : String(limitError),
|
|
300
|
+
serializedRunState,
|
|
301
|
+
limitError instanceof AllowanceExhaustedError ? limitError.refusal : null,
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
252
306
|
// Exported for unit testing the external-billing bypass (codex-billing.test.ts); not
|
|
253
307
|
// part of the activity surface. Takes the accepted policy's billing attribution and
|
|
254
308
|
// the optional §7.5 P3 host `entitlements` port (when bound, its `admitRun` REPLACES
|
|
@@ -262,6 +316,7 @@ export async function ensureRunAllowed(
|
|
|
262
316
|
entitlements?: ActivityServices["entitlements"],
|
|
263
317
|
chargesOpenGeniCredits = !isExternallyBilledTurn,
|
|
264
318
|
countsTowardTokenCap = !isExternallyBilledTurn,
|
|
319
|
+
initiatingHumanSubjectId: string | null = null,
|
|
265
320
|
): Promise<void> {
|
|
266
321
|
// Upstream settlement and workspace-facing cost are independent. External
|
|
267
322
|
// metering skips the token cap; free/subscription/workspace cost skips the
|
|
@@ -302,6 +357,14 @@ export async function ensureRunAllowed(
|
|
|
302
357
|
throw new Error("insufficient OpenGeni credits");
|
|
303
358
|
}
|
|
304
359
|
}
|
|
360
|
+
if (chargesOpenGeniCredits) {
|
|
361
|
+
const refusal = await checkWorkspaceAllowance(db, {
|
|
362
|
+
accountId,
|
|
363
|
+
workspaceId,
|
|
364
|
+
subjectId: initiatingHumanSubjectId,
|
|
365
|
+
});
|
|
366
|
+
if (refusal) throw new AllowanceExhaustedError(refusal);
|
|
367
|
+
}
|
|
305
368
|
if (settings.usageLimitsMode === "static" || settings.usageLimitsMode === "managed") {
|
|
306
369
|
const limits = configuredStaticUsageLimits(settings);
|
|
307
370
|
if (limits.maxMonthlyAgentRunsPerWorkspace) {
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getSessionTurnForAttempt,
|
|
11
11
|
ensureSessionReasoningConfiguration,
|
|
12
12
|
ensureSessionSkillCatalog,
|
|
13
|
+
sessionHasToolRouterHistory,
|
|
13
14
|
} from "@opengeni/db";
|
|
14
15
|
import { recoveryAwareSessionInstructions } from "./recovery-warning";
|
|
15
16
|
import {
|
|
@@ -52,7 +53,7 @@ import {
|
|
|
52
53
|
} from "../image-generation-references";
|
|
53
54
|
import { SandboxChannelAService } from "@opengeni/runtime/sandbox";
|
|
54
55
|
import { sandboxRunAs } from "@opengeni/runtime";
|
|
55
|
-
import { VideoGenerationRejectedResult } from "@opengeni/contracts";
|
|
56
|
+
import { VideoGenerationRejectedResult, resolveAgentToolFamilies } from "@opengeni/contracts";
|
|
56
57
|
|
|
57
58
|
import {
|
|
58
59
|
structuredToolTransportForTurn,
|
|
@@ -111,6 +112,7 @@ export type BuildTurnAgentDeps = {
|
|
|
111
112
|
supportsImageInput: GovernanceModelOk["supportsImageInput"];
|
|
112
113
|
agentHumanInputEnabled: GovernanceModelOk["agentHumanInputEnabled"];
|
|
113
114
|
workspaceAgentInstructions: GovernanceModelOk["workspaceAgentInstructions"];
|
|
115
|
+
workspaceAgentIdentity: GovernanceModelOk["workspaceAgentIdentity"];
|
|
114
116
|
workspaceGovernance: GovernanceModelOk["workspaceGovernance"];
|
|
115
117
|
structuredWorkspacePolicyActive: GovernanceModelOk["structuredWorkspacePolicyActive"];
|
|
116
118
|
workspaceMemory: GovernanceModelOk["workspaceMemory"];
|
|
@@ -173,6 +175,7 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
173
175
|
supportsImageInput,
|
|
174
176
|
agentHumanInputEnabled,
|
|
175
177
|
workspaceAgentInstructions,
|
|
178
|
+
workspaceAgentIdentity,
|
|
176
179
|
workspaceGovernance,
|
|
177
180
|
structuredWorkspacePolicyActive,
|
|
178
181
|
workspaceMemory,
|
|
@@ -284,7 +287,7 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
284
287
|
// Never expose a paid image operation unless its permanent artifact can
|
|
285
288
|
// be committed. Failing after provider execution would leave an
|
|
286
289
|
// unrecoverable outcome-unknown operation with no user-visible image.
|
|
287
|
-
if (!objectStorage) return {};
|
|
290
|
+
if (!objectStorage || !resolveAgentToolFamilies(session.agent).media) return {};
|
|
288
291
|
if (nativeImageProviderBinding) {
|
|
289
292
|
media.nativeImageGenerationRetention = {
|
|
290
293
|
...nativeImageProviderBinding,
|
|
@@ -405,7 +408,7 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
405
408
|
videoGenerationPolicy.defaultModelId !== null &&
|
|
406
409
|
videoGenerationPolicy.enabledModelIds.length > 0;
|
|
407
410
|
let videoGenerationCredential: VideoGenerationCredentialLease | null = null;
|
|
408
|
-
if (objectStorage && videoGenerationEnabled) {
|
|
411
|
+
if (objectStorage && videoGenerationEnabled && resolveAgentToolFamilies(session.agent).media) {
|
|
409
412
|
if (videoGenerationPolicy.fundingSource === "opengeni_credits") {
|
|
410
413
|
videoGenerationCredential = managedVideoGenerationCredentialLease(eventing.modelRunSettings);
|
|
411
414
|
} else if (videoGenerationPolicy.fundingSource === "workspace_gateway") {
|
|
@@ -626,6 +629,13 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
626
629
|
effort: turn.reasoningEffort,
|
|
627
630
|
})
|
|
628
631
|
: turn.reasoningEffort;
|
|
632
|
+
const toolRouterInHistory = session.agent
|
|
633
|
+
? await sessionHasToolRouterHistory(db, {
|
|
634
|
+
accountId: input.accountId,
|
|
635
|
+
workspaceId: input.workspaceId,
|
|
636
|
+
sessionId: input.sessionId,
|
|
637
|
+
})
|
|
638
|
+
: false;
|
|
629
639
|
const agent = (() => {
|
|
630
640
|
const agentConstructionStartedAt = performance.now();
|
|
631
641
|
let agentConstructionOutcome: "completed" | "failed" = "completed";
|
|
@@ -652,6 +662,7 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
652
662
|
}
|
|
653
663
|
: {}),
|
|
654
664
|
...(preparedTools.inputWaitYield ? { inputWaitYield: preparedTools.inputWaitYield } : {}),
|
|
665
|
+
...(session.agent ? { agentConfig: session.agent, toolRouterInHistory } : {}),
|
|
655
666
|
reasoningEffort: requestReasoningEffort,
|
|
656
667
|
latencyMode: turnExecutionPolicy.latencyMode,
|
|
657
668
|
...(serviceTier ? { serviceTier } : {}),
|
|
@@ -757,6 +768,16 @@ export async function buildTurnAgent(deps: BuildTurnAgentDeps) {
|
|
|
757
768
|
onRetainableSessionImageOutput: media.retainSessionImageAtToolBoundary,
|
|
758
769
|
skillCatalog: deps.skillCatalog,
|
|
759
770
|
skillCatalogInHistory: true,
|
|
771
|
+
// A session with an agent configuration composes the modular prompt
|
|
772
|
+
// (identity, base behavior, runtime mechanics, capability modules);
|
|
773
|
+
// its workspace identity survives instruction policies. Null keeps
|
|
774
|
+
// the legacy composition below byte-for-byte.
|
|
775
|
+
...(session.agent
|
|
776
|
+
? {
|
|
777
|
+
agentConfig: session.agent,
|
|
778
|
+
...(workspaceAgentIdentity ? { workspaceAgentIdentity } : {}),
|
|
779
|
+
}
|
|
780
|
+
: {}),
|
|
760
781
|
...(!structuredWorkspacePolicyActive && workspaceAgentInstructions
|
|
761
782
|
? { instructionsTemplate: workspaceAgentInstructions }
|
|
762
783
|
: {}),
|
|
@@ -56,12 +56,15 @@ import {
|
|
|
56
56
|
import { createTurnCredentialLeases } from "./credential-leases";
|
|
57
57
|
import { createTurnMediaArtifacts } from "./media-artifacts";
|
|
58
58
|
import { readTurnExecutionPolicyV1 } from "@opengeni/contracts";
|
|
59
|
+
import { turnCredentialRestriction } from "./credential-restriction";
|
|
59
60
|
|
|
60
61
|
import {
|
|
61
62
|
credentialSubjectIdForTurnInitiator,
|
|
62
63
|
turnExecutionPolicyBillingIdentity,
|
|
63
64
|
legacyTurnExecutionPolicyInput,
|
|
64
65
|
ensureRunAllowed,
|
|
66
|
+
AllowanceExhaustedError,
|
|
67
|
+
type AllowanceRefusal,
|
|
65
68
|
} from "./admission";
|
|
66
69
|
import { providerRecoveryCountFromMetadata, isWorkerShutdownCancellation } from "./errors";
|
|
67
70
|
import { throwIfTurnOperationCancelled, waitForTurnOperation } from "./sandbox-provision";
|
|
@@ -288,10 +291,21 @@ export async function claimTurnAttempt(deps: ClaimTurnDeps): Promise<ClaimTurnOu
|
|
|
288
291
|
const codexAppsCredentialId = capabilitySettings.codexConnectedAppsEnabled
|
|
289
292
|
? await resolveCodexAppsCredentialIdForRun(db, input.workspaceId)
|
|
290
293
|
: null;
|
|
291
|
-
const
|
|
294
|
+
const candidatePolicy =
|
|
292
295
|
claimedPolicy.kind === "valid"
|
|
293
296
|
? claimedPolicy.policy
|
|
294
297
|
: resolveTurnExecutionPolicyV1(capabilitySettings, legacyTurnExecutionPolicyInput(turn));
|
|
298
|
+
// This context is frozen by the accepted-turn writer from the exact source
|
|
299
|
+
// turn. Its reserved restriction field cannot come from public service JSON.
|
|
300
|
+
const credentialRestriction =
|
|
301
|
+
claimedPolicy.kind === "absent"
|
|
302
|
+
? turn.initiatorContext?.credentialRestriction === "developer_setup"
|
|
303
|
+
? "developer_setup"
|
|
304
|
+
: turnCredentialRestriction(candidatePolicy, session.metadata)
|
|
305
|
+
: undefined;
|
|
306
|
+
const policyForAbsent = credentialRestriction
|
|
307
|
+
? { ...candidatePolicy, credentialRestriction }
|
|
308
|
+
: candidatePolicy;
|
|
295
309
|
const installedPolicy = await installOrReadTurnExecutionPolicyForAttempt(db, {
|
|
296
310
|
accountId: input.accountId,
|
|
297
311
|
workspaceId: input.workspaceId,
|
|
@@ -368,20 +382,27 @@ export async function claimTurnAttempt(deps: ClaimTurnDeps): Promise<ClaimTurnOu
|
|
|
368
382
|
// bypass OpenGeni credit/token gates)
|
|
369
383
|
// AND the optional host `entitlements` port (when bound, its admitRun replaces
|
|
370
384
|
// the local credit read). Unset port → today's local-ledger path.
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
+
let allowanceRefusal: AllowanceRefusal | null = null;
|
|
386
|
+
try {
|
|
387
|
+
await waitForTurnOperation(
|
|
388
|
+
ensureRunAllowed(
|
|
389
|
+
capabilitySettings,
|
|
390
|
+
db,
|
|
391
|
+
input.accountId,
|
|
392
|
+
input.workspaceId,
|
|
393
|
+
billingState.isExternallyBilledTurn,
|
|
394
|
+
entitlements,
|
|
395
|
+
billingState.chargesOpenGeniCredits,
|
|
396
|
+
billingState.countsTowardTokenCap,
|
|
397
|
+
turn.initiatingHumanSubjectId,
|
|
398
|
+
),
|
|
399
|
+
cancellationSignal,
|
|
400
|
+
undefined,
|
|
401
|
+
);
|
|
402
|
+
} catch (error) {
|
|
403
|
+
if (!(error instanceof AllowanceExhaustedError)) throw error;
|
|
404
|
+
allowanceRefusal = error.refusal;
|
|
405
|
+
}
|
|
385
406
|
// Setup (variableSet load, MCP connects, sandbox restore) does not
|
|
386
407
|
// stream and so never observes cancellation on its own; these explicit
|
|
387
408
|
// checks let a graceful shutdown checkpoint the turn before the worker is
|
|
@@ -514,6 +535,9 @@ export async function claimTurnAttempt(deps: ClaimTurnDeps): Promise<ClaimTurnOu
|
|
|
514
535
|
...(inputSettlement.suppressGoalContinuation !== undefined
|
|
515
536
|
? { suppressGoalContinuation: inputSettlement.suppressGoalContinuation }
|
|
516
537
|
: {}),
|
|
538
|
+
...(inputSettlement.allowanceGoalPause
|
|
539
|
+
? { allowanceGoalPause: inputSettlement.allowanceGoalPause }
|
|
540
|
+
: {}),
|
|
517
541
|
events: inputs,
|
|
518
542
|
...(runState ? { runState } : {}),
|
|
519
543
|
...(compactionRequestFailure ? { compactionRequestFailure } : {}),
|
|
@@ -575,6 +599,36 @@ export async function claimTurnAttempt(deps: ClaimTurnDeps): Promise<ClaimTurnOu
|
|
|
575
599
|
durationSeconds: (performance.now() - activityStarted) / 1_000,
|
|
576
600
|
});
|
|
577
601
|
const turnStartSettlementStartedAt = performance.now();
|
|
602
|
+
if (allowanceRefusal) {
|
|
603
|
+
// Claim has frozen the exact human, but no provider or sandbox has started.
|
|
604
|
+
// Use the same terminal valve as a post-response stop, retaining a usable
|
|
605
|
+
// session and a visible typed refusal instead of manufacturing a failure.
|
|
606
|
+
if (
|
|
607
|
+
!(await eventing.settle({
|
|
608
|
+
events: [
|
|
609
|
+
{ type: "usage.exhausted", payload: allowanceRefusal },
|
|
610
|
+
{
|
|
611
|
+
type: "turn.completed",
|
|
612
|
+
payload: {
|
|
613
|
+
output: "",
|
|
614
|
+
segmentLimit: "budget_exhausted",
|
|
615
|
+
...allowanceRefusal,
|
|
616
|
+
},
|
|
617
|
+
},
|
|
618
|
+
{ type: "session.status.changed", payload: { status: "idle" } },
|
|
619
|
+
],
|
|
620
|
+
turnStatus: "completed",
|
|
621
|
+
sessionStatus: "idle",
|
|
622
|
+
activeTurnId: null,
|
|
623
|
+
allowanceGoalPause: { rationale: allowanceRefusal.message },
|
|
624
|
+
}))
|
|
625
|
+
) {
|
|
626
|
+
return { exit: claimedResult({ status: "cancelled" }) };
|
|
627
|
+
}
|
|
628
|
+
control.turnMetricOutcome = "completed";
|
|
629
|
+
control.activityStatus = "idle";
|
|
630
|
+
return { exit: claimedResult({ status: "idle" }) };
|
|
631
|
+
}
|
|
578
632
|
if (
|
|
579
633
|
!(await eventing.settle({
|
|
580
634
|
events: [
|
|
@@ -35,6 +35,17 @@ export async function createClaudeUsageObserver(
|
|
|
35
35
|
.map(async (provider) => {
|
|
36
36
|
const scope: Scope =
|
|
37
37
|
provider.kind === "claude-subscription-workspace" ? "workspace" : "organization";
|
|
38
|
+
const binding = provider.anthropic?.credentialBinding;
|
|
39
|
+
if (binding && provider.apiKey)
|
|
40
|
+
return [
|
|
41
|
+
provider.id,
|
|
42
|
+
{
|
|
43
|
+
scope,
|
|
44
|
+
token: provider.apiKey,
|
|
45
|
+
expectedConnectionId: binding.connectionId,
|
|
46
|
+
expectedCredentialVersion: binding.credentialVersion,
|
|
47
|
+
},
|
|
48
|
+
] as const;
|
|
38
49
|
const credential = await readCredential(scope).catch(() => null);
|
|
39
50
|
if (!credential || credential.token !== provider.apiKey) return null;
|
|
40
51
|
return [
|
|
@@ -49,7 +60,7 @@ export async function createClaudeUsageObserver(
|
|
|
49
60
|
}),
|
|
50
61
|
);
|
|
51
62
|
const captured = new Map(bindings.filter((binding) => binding !== null));
|
|
52
|
-
|
|
63
|
+
const observe = (providerId: string, response: Response) => {
|
|
53
64
|
const binding = captured.get(providerId);
|
|
54
65
|
if (!binding) return;
|
|
55
66
|
const { scope, ...identity } = binding;
|
|
@@ -76,4 +87,25 @@ export async function createClaudeUsageObserver(
|
|
|
76
87
|
: {}),
|
|
77
88
|
});
|
|
78
89
|
};
|
|
90
|
+
return Object.assign(observe, {
|
|
91
|
+
binding(providerId: string) {
|
|
92
|
+
return captured.get(providerId);
|
|
93
|
+
},
|
|
94
|
+
renew(
|
|
95
|
+
providerId: string,
|
|
96
|
+
credential: {
|
|
97
|
+
token: string;
|
|
98
|
+
connectionId: string;
|
|
99
|
+
credentialVersion: number;
|
|
100
|
+
},
|
|
101
|
+
) {
|
|
102
|
+
const binding = captured.get(providerId);
|
|
103
|
+
if (
|
|
104
|
+
binding &&
|
|
105
|
+
binding.expectedConnectionId === credential.connectionId &&
|
|
106
|
+
binding.expectedCredentialVersion === credential.credentialVersion
|
|
107
|
+
)
|
|
108
|
+
captured.set(providerId, { ...binding, token: credential.token });
|
|
109
|
+
},
|
|
110
|
+
});
|
|
79
111
|
}
|
|
@@ -4,7 +4,9 @@ import {
|
|
|
4
4
|
appendSessionInstructions,
|
|
5
5
|
appendWorkspaceGovernance,
|
|
6
6
|
appendWorkspaceMemory,
|
|
7
|
+
agentPromptResourcesFor,
|
|
7
8
|
composeAgentInstructions,
|
|
9
|
+
inspectPersistentAgentInstructions,
|
|
8
10
|
requestRemoteCompactionV2,
|
|
9
11
|
preparedCompactionRequest,
|
|
10
12
|
queuePreparedCompaction,
|
|
@@ -86,6 +88,7 @@ export type CompactionPrepDeps = {
|
|
|
86
88
|
turnExecutionPolicy: ClaimTurnOk["turnExecutionPolicy"];
|
|
87
89
|
resolvedModel: GovernanceModelOk["resolvedModel"];
|
|
88
90
|
workspaceAgentInstructions: GovernanceModelOk["workspaceAgentInstructions"];
|
|
91
|
+
workspaceAgentIdentity: GovernanceModelOk["workspaceAgentIdentity"];
|
|
89
92
|
workspaceGovernance: GovernanceModelOk["workspaceGovernance"];
|
|
90
93
|
structuredWorkspacePolicyActive: GovernanceModelOk["structuredWorkspacePolicyActive"];
|
|
91
94
|
workspaceMemory: GovernanceModelOk["workspaceMemory"];
|
|
@@ -131,6 +134,59 @@ export type PostAgentCompactionOutcome =
|
|
|
131
134
|
| { exit: RunAgentTurnResult }
|
|
132
135
|
| { ok: PostAgentCompactionOk };
|
|
133
136
|
|
|
137
|
+
/**
|
|
138
|
+
* System instructions for the standalone (chat-provider) compaction request.
|
|
139
|
+
* A session with an agent configuration uses the same modular composer and
|
|
140
|
+
* module selection as its turns; a legacy session keeps the historical
|
|
141
|
+
* persona + CORE + governance + session + memory string byte-for-byte.
|
|
142
|
+
*/
|
|
143
|
+
export function standaloneCompactionInstructions(input: {
|
|
144
|
+
settings: Settings;
|
|
145
|
+
session: Pick<ClaimTurnOk["session"], "agent" | "instructions" | "resources">;
|
|
146
|
+
workspaceAgentInstructions: string | null | undefined;
|
|
147
|
+
workspaceAgentIdentity: string | null;
|
|
148
|
+
workspaceGovernance: string | null | undefined;
|
|
149
|
+
structuredWorkspacePolicyActive: boolean;
|
|
150
|
+
workspaceMemory: string | null | undefined;
|
|
151
|
+
rig: { name: string; version: number } | undefined;
|
|
152
|
+
}): string {
|
|
153
|
+
if (input.session.agent) {
|
|
154
|
+
return inspectPersistentAgentInstructions(input.settings, {
|
|
155
|
+
agentConfig: input.session.agent,
|
|
156
|
+
...(input.workspaceAgentIdentity
|
|
157
|
+
? { workspaceAgentIdentity: input.workspaceAgentIdentity }
|
|
158
|
+
: {}),
|
|
159
|
+
...(input.workspaceGovernance ? { workspaceGovernance: input.workspaceGovernance } : {}),
|
|
160
|
+
...(input.workspaceMemory ? { workspaceMemory: input.workspaceMemory } : {}),
|
|
161
|
+
...(input.session.instructions ? { sessionInstructions: input.session.instructions } : {}),
|
|
162
|
+
...(input.rig ? { rig: input.rig } : {}),
|
|
163
|
+
// Session-level facts only: per-turn attachments do not apply to a
|
|
164
|
+
// standalone compaction request.
|
|
165
|
+
agentPromptResources: agentPromptResourcesFor(
|
|
166
|
+
input.settings,
|
|
167
|
+
input.session.resources.filter((resource) => resource.kind !== "file"),
|
|
168
|
+
input.rig ? { rig: input.rig } : {},
|
|
169
|
+
),
|
|
170
|
+
}).composed;
|
|
171
|
+
}
|
|
172
|
+
return appendWorkspaceMemory(
|
|
173
|
+
appendSessionInstructions(
|
|
174
|
+
appendWorkspaceGovernance(
|
|
175
|
+
composeAgentInstructions(
|
|
176
|
+
input.structuredWorkspacePolicyActive
|
|
177
|
+
? input.settings.agentInstructionsTemplate
|
|
178
|
+
: (input.workspaceAgentInstructions ?? input.settings.agentInstructionsTemplate),
|
|
179
|
+
undefined,
|
|
180
|
+
input.rig,
|
|
181
|
+
),
|
|
182
|
+
input.workspaceGovernance ?? undefined,
|
|
183
|
+
),
|
|
184
|
+
input.session.instructions ?? undefined,
|
|
185
|
+
),
|
|
186
|
+
input.workspaceMemory ?? undefined,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
|
|
134
190
|
export async function prepareCompaction(deps: CompactionPrepDeps): Promise<CompactionPrepOutcome> {
|
|
135
191
|
const {
|
|
136
192
|
input,
|
|
@@ -155,6 +211,7 @@ export async function prepareCompaction(deps: CompactionPrepDeps): Promise<Compa
|
|
|
155
211
|
turnExecutionPolicy,
|
|
156
212
|
resolvedModel,
|
|
157
213
|
workspaceAgentInstructions,
|
|
214
|
+
workspaceAgentIdentity,
|
|
158
215
|
workspaceGovernance,
|
|
159
216
|
structuredWorkspacePolicyActive,
|
|
160
217
|
workspaceMemory,
|
|
@@ -334,22 +391,16 @@ export async function prepareCompaction(deps: CompactionPrepDeps): Promise<Compa
|
|
|
334
391
|
!remoteV2CompactionNeedsAgentPrefix &&
|
|
335
392
|
!portableResponsesNeedsAgentPrefix
|
|
336
393
|
) {
|
|
337
|
-
const compactionInstructions =
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
workspaceGovernance ?? undefined,
|
|
348
|
-
),
|
|
349
|
-
session.instructions ?? undefined,
|
|
350
|
-
),
|
|
351
|
-
workspaceMemory ?? undefined,
|
|
352
|
-
);
|
|
394
|
+
const compactionInstructions = standaloneCompactionInstructions({
|
|
395
|
+
settings: eventing.modelRunSettings,
|
|
396
|
+
session,
|
|
397
|
+
workspaceAgentInstructions,
|
|
398
|
+
workspaceAgentIdentity,
|
|
399
|
+
workspaceGovernance,
|
|
400
|
+
structuredWorkspacePolicyActive,
|
|
401
|
+
workspaceMemory,
|
|
402
|
+
rig: rigVersion && rigName ? { name: rigName, version: rigVersion.version } : undefined,
|
|
403
|
+
});
|
|
353
404
|
const requested = await isSessionCompactionRequested(db, input.workspaceId, input.sessionId);
|
|
354
405
|
let outcome: Awaited<ReturnType<typeof maybeCompactContext>> | null = null;
|
|
355
406
|
if (requested) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { readTurnExecutionPolicyV1, type TurnExecutionPolicyV1 } from "@opengeni/contracts";
|
|
2
|
+
|
|
3
|
+
/** Only accepted policies establish the ceiling; ordinary metadata is not authority. */
|
|
4
|
+
export function turnCredentialRestriction(
|
|
5
|
+
acceptedPolicy: TurnExecutionPolicyV1,
|
|
6
|
+
initialSessionMetadata: unknown,
|
|
7
|
+
): "developer_setup" | undefined {
|
|
8
|
+
const initialPolicy = readTurnExecutionPolicyV1(initialSessionMetadata);
|
|
9
|
+
return acceptedPolicy.credentialRestriction === "developer_setup" ||
|
|
10
|
+
(initialPolicy.kind === "valid" &&
|
|
11
|
+
initialPolicy.policy.credentialRestriction === "developer_setup")
|
|
12
|
+
? "developer_setup"
|
|
13
|
+
: undefined;
|
|
14
|
+
}
|