@opengeni/worker-bundle 1.0.0-canary.1 → 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
|
@@ -1,47 +1,46 @@
|
|
|
1
1
|
import type { Settings } from "@opengeni/config";
|
|
2
|
-
import
|
|
3
|
-
import type { HostMcpAcceptedAuthority } from "@opengeni/contracts/host-mcp-bindings";
|
|
2
|
+
import { stableJson } from "@opengeni/contracts";
|
|
4
3
|
import {
|
|
5
4
|
buildConnectionTokenResolver,
|
|
6
|
-
buildHostConnectionTokenResolver,
|
|
7
|
-
getSessionTurnForAttempt,
|
|
8
|
-
authorizeDirectHostMcpUse,
|
|
9
|
-
resolveAcceptedHostMcpBinding,
|
|
10
5
|
resolveAcceptedConnectionUse,
|
|
11
|
-
sessionTenancyProductActivated,
|
|
12
6
|
type Database,
|
|
13
7
|
type ResolveConnectionCredentialInput,
|
|
14
8
|
type ResolveConnectionCredentialResult,
|
|
15
9
|
type SessionTurnForExecution,
|
|
16
10
|
} from "@opengeni/db";
|
|
17
|
-
import { recordTenancyCompatibilityLaneUse, type Observability } from "@opengeni/observability";
|
|
18
11
|
import { mcpOperationAuthorityDigest } from "./mcp-operation-authority";
|
|
19
12
|
|
|
20
|
-
|
|
21
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
22
|
-
|
|
23
|
-
export function connectionTokenResolverForTurn(input: {
|
|
13
|
+
type TurnConnectionInput = {
|
|
24
14
|
db: Database;
|
|
25
15
|
settings: Settings;
|
|
26
|
-
connectionCredentials?: ConnectionCredentialsPort | null;
|
|
27
16
|
accountId: string;
|
|
28
17
|
workspaceId: string;
|
|
29
18
|
sessionId: string;
|
|
30
|
-
rootSessionId: string;
|
|
31
19
|
attemptId: string;
|
|
32
20
|
turn: SessionTurnForExecution;
|
|
21
|
+
/** Policy identities before account expansion; never used to select credentials. */
|
|
22
|
+
canonicalMcpServerIds?: readonly string[];
|
|
33
23
|
authorizeAcceptedUse?: typeof resolveAcceptedConnectionUse;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type CredentialResolver = (
|
|
27
|
+
request: ResolveConnectionCredentialInput,
|
|
28
|
+
) => Promise<ResolveConnectionCredentialResult>;
|
|
29
|
+
|
|
30
|
+
export function connectionTokenResolverForTurn(input: TurnConnectionInput): CredentialResolver {
|
|
31
|
+
return bindNativeConnectionCredentialsToTurn(
|
|
32
|
+
input,
|
|
33
|
+
buildConnectionTokenResolver(input.db, input.settings),
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Bind the ordinary credential resolver to one immutable accepted turn.
|
|
38
|
+
* Credential acquisition and refresh stay inside the native connection engine;
|
|
39
|
+
* this layer adds the exact execution context and physical-request checks. */
|
|
40
|
+
export function bindNativeConnectionCredentialsToTurn(
|
|
41
|
+
input: TurnConnectionInput,
|
|
42
|
+
nativeResolver: CredentialResolver,
|
|
43
|
+
): CredentialResolver {
|
|
45
44
|
const recoveryEnabled = (serverId: string) =>
|
|
46
45
|
input.settings.mcpServers.some(
|
|
47
46
|
(server) =>
|
|
@@ -50,84 +49,14 @@ export function connectionTokenResolverForTurn(input: {
|
|
|
50
49
|
server.operationRecovery !== undefined &&
|
|
51
50
|
Object.keys(server.operationRecovery ?? {}).length > 0,
|
|
52
51
|
);
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
let authorizedSnapshot: HostMcpAcceptedAuthority | undefined;
|
|
58
|
-
const wantsDigest = recoveryEnabled(credentialRequest.serverId);
|
|
59
|
-
const resolver = buildHostConnectionTokenResolver(hostResolver, {
|
|
60
|
-
accountId: input.accountId,
|
|
61
|
-
workspaceId: input.workspaceId,
|
|
62
|
-
sessionId: input.sessionId,
|
|
63
|
-
rootSessionId: input.rootSessionId,
|
|
64
|
-
turnId: input.turn.id,
|
|
65
|
-
attemptId: input.attemptId,
|
|
66
|
-
executionGeneration: input.turn.executionGeneration,
|
|
67
|
-
initiator: input.turn.initiator,
|
|
68
|
-
initiatorContext: input.turn.initiatorContext,
|
|
69
|
-
surface: "model",
|
|
70
|
-
resolveAcceptedBinding: (request) => resolveAcceptedHostMcpBinding(hostDb, request),
|
|
71
|
-
// Only immutable captured direct-turn authority is currently supported.
|
|
72
|
-
// Direct, scheduled and exact causal/child snapshots are validated;
|
|
73
|
-
// no authority follows merely from a binding or creator identity.
|
|
74
|
-
authorizeDurableBinding: (request) =>
|
|
75
|
-
authorizeDirectHostMcpUse(
|
|
76
|
-
hostDb,
|
|
77
|
-
request,
|
|
78
|
-
wantsDigest
|
|
79
|
-
? (snapshot) => {
|
|
80
|
-
authorizedSnapshot = snapshot;
|
|
81
|
-
}
|
|
82
|
-
: undefined,
|
|
83
|
-
),
|
|
84
|
-
authorizeExecution: async (request) => {
|
|
85
|
-
// Native UUID references already pass the accepted-use boundary below.
|
|
86
|
-
// Legacy opaque host IDs retain their compatibility path, but not a
|
|
87
|
-
// right to execute after their accepted attempt has stopped.
|
|
88
|
-
if (
|
|
89
|
-
request.connectionRef.authoritySource !== "host" &&
|
|
90
|
-
(!request.connectionRef.connectionId ||
|
|
91
|
-
OPENGENI_CONNECTION_ID_PATTERN.test(request.connectionRef.connectionId))
|
|
92
|
-
)
|
|
93
|
-
return true;
|
|
94
|
-
if (!request.attemptId) return false;
|
|
95
|
-
const current = await readHostTurn(
|
|
96
|
-
hostDb,
|
|
97
|
-
request.workspaceId,
|
|
98
|
-
request.sessionId,
|
|
99
|
-
request.attemptId,
|
|
100
|
-
);
|
|
101
|
-
return (
|
|
102
|
-
current !== null &&
|
|
103
|
-
current.id === request.turnId &&
|
|
104
|
-
current.executionGeneration === request.executionGeneration
|
|
105
|
-
);
|
|
106
|
-
},
|
|
107
|
-
});
|
|
108
|
-
const result = await resolver(credentialRequest);
|
|
109
|
-
return result.status === "ok" && authorizedSnapshot
|
|
110
|
-
? {
|
|
111
|
-
...result,
|
|
112
|
-
operationAuthorityDigest: mcpOperationAuthorityDigest(credentialRequest, {
|
|
113
|
-
host: authorizedSnapshot,
|
|
114
|
-
}),
|
|
115
|
-
}
|
|
116
|
-
: result;
|
|
117
|
-
}
|
|
118
|
-
: nativeResolver;
|
|
119
|
-
const baseResolver = (request: ResolveConnectionCredentialInput) =>
|
|
120
|
-
input.connectionCredentials?.mcpAuthoritySource === "host" &&
|
|
121
|
-
request.connectionRef.authoritySource !== "host"
|
|
122
|
-
? nativeResolver(request)
|
|
123
|
-
: configuredResolver(request);
|
|
52
|
+
const canonicalMcpServerIds = new Set(
|
|
53
|
+
input.canonicalMcpServerIds ??
|
|
54
|
+
input.settings.mcpServers.filter((server) => server.connectionRef).map((server) => server.id),
|
|
55
|
+
);
|
|
124
56
|
return async (request) => {
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
// authority or PostgreSQL UUID lookup; the bound host authorizes the exact
|
|
128
|
-
// immutable turn context on every credential request.
|
|
57
|
+
// Superseded host references must never fall through to native lookup,
|
|
58
|
+
// even when their opaque identifier happens to be a valid native UUID.
|
|
129
59
|
if (request.connectionRef.authoritySource === "host") {
|
|
130
|
-
if (hostResolver) return await baseResolver(request);
|
|
131
60
|
return {
|
|
132
61
|
status: "auth_needed",
|
|
133
62
|
reason: "unsupported_auth",
|
|
@@ -144,34 +73,31 @@ export function connectionTokenResolverForTurn(input: {
|
|
|
144
73
|
: {}),
|
|
145
74
|
};
|
|
146
75
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
// so UUID-shaped host ids are unambiguous.
|
|
76
|
+
const accountBindings = input.turn.mcpAccountBindings ?? [];
|
|
77
|
+
const accountBinding = accountBindings.find((binding) => binding.serverId === request.serverId);
|
|
78
|
+
// Canonical policy identity cannot be invoked as a credential fallback once
|
|
79
|
+
// this turn selected explicit account routes for that connector.
|
|
152
80
|
if (
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
!
|
|
81
|
+
(input.turn.mcpAccountBindings != null &&
|
|
82
|
+
!accountBinding &&
|
|
83
|
+
canonicalMcpServerIds.has(request.serverId)) ||
|
|
84
|
+
(!accountBinding &&
|
|
85
|
+
accountBindings.some((binding) => binding.canonicalServerId === request.serverId)) ||
|
|
86
|
+
(accountBinding &&
|
|
87
|
+
(request.connectionRef.connectionId !== accountBinding.connectionId ||
|
|
88
|
+
request.connectionRef.providerDomain !== accountBinding.providerDomain ||
|
|
89
|
+
request.connectionRef.kind !== accountBinding.kind ||
|
|
90
|
+
request.connectionRef.subjectScope !== accountBinding.subjectScope ||
|
|
91
|
+
stableJson(request.connectionRef) !== stableJson(accountBinding.connectionRef) ||
|
|
92
|
+
(accountBinding.subjectScope === "subject" &&
|
|
93
|
+
request.subjectId !== accountBinding.ownerSubjectId)))
|
|
157
94
|
) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
providerDomain: request.connectionRef.providerDomain,
|
|
165
|
-
authoritySource: "host",
|
|
166
|
-
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
167
|
-
connectionId: request.connectionRef.connectionId,
|
|
168
|
-
...(request.connectionRef.scopes ? { scopes: request.connectionRef.scopes } : {}),
|
|
169
|
-
...(request.connectionRef.resource ? { resource: request.connectionRef.resource } : {}),
|
|
170
|
-
...(request.connectionRef.selectedResources
|
|
171
|
-
? { selectedResources: request.connectionRef.selectedResources }
|
|
172
|
-
: {}),
|
|
173
|
-
};
|
|
174
|
-
}
|
|
95
|
+
return {
|
|
96
|
+
status: "auth_needed",
|
|
97
|
+
reason: "personal_authority_unavailable",
|
|
98
|
+
providerDomain: request.connectionRef.providerDomain,
|
|
99
|
+
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
100
|
+
};
|
|
175
101
|
}
|
|
176
102
|
const acceptedDelegation = input.turn.personalConnectionDelegations.find(
|
|
177
103
|
(delegation) =>
|
|
@@ -191,9 +117,7 @@ export function connectionTokenResolverForTurn(input: {
|
|
|
191
117
|
const subjectScope: "subject" | "workspace" =
|
|
192
118
|
request.connectionRef.subjectScope === "subject" ? "subject" : "workspace";
|
|
193
119
|
// Every subject-scoped request must match an exact connection frozen on the
|
|
194
|
-
// accepted turn.
|
|
195
|
-
// lack a userDelegation: the DB resolver denies those rows because only a
|
|
196
|
-
// true legacy_user connection is eligible for bounded compatibility.
|
|
120
|
+
// accepted turn. The database then checks its immutable sender snapshot.
|
|
197
121
|
if (
|
|
198
122
|
subjectScope === "subject" &&
|
|
199
123
|
(!acceptedDelegation || !request.connectionRef.connectionId)
|
|
@@ -205,31 +129,15 @@ export function connectionTokenResolverForTurn(input: {
|
|
|
205
129
|
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
206
130
|
};
|
|
207
131
|
}
|
|
208
|
-
// Workspace
|
|
209
|
-
//
|
|
210
|
-
// inside the canonical lifecycle fences and every use leaves an idempotent
|
|
211
|
-
// audit fact. A ref with no connection id is the bounded pre-snapshot
|
|
212
|
-
// legacy path - it cannot be authorized by exact identity, so it keeps the
|
|
213
|
-
// unprivileged resolution the old short-circuit used.
|
|
132
|
+
// Workspace connections also need an exact identity for accepted-use
|
|
133
|
+
// validation and attribution. Never rediscover a credential by domain here.
|
|
214
134
|
if (subjectScope === "workspace" && !request.connectionRef.connectionId) {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
)
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
status: "auth_needed",
|
|
223
|
-
reason: "missing_connection",
|
|
224
|
-
providerDomain: request.connectionRef.providerDomain,
|
|
225
|
-
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
// This lane writes no `connection_use_audit_facts` row, so this counter is
|
|
229
|
-
// the only evidence it was taken. Lane name only - never the server,
|
|
230
|
-
// provider domain, connection, or subject.
|
|
231
|
-
recordTenancyCompatibilityLaneUse(input.observability, "connection_pre_snapshot_ref");
|
|
232
|
-
return await baseResolver(request);
|
|
135
|
+
return {
|
|
136
|
+
status: "auth_needed",
|
|
137
|
+
reason: "missing_connection",
|
|
138
|
+
providerDomain: request.connectionRef.providerDomain,
|
|
139
|
+
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
140
|
+
};
|
|
233
141
|
}
|
|
234
142
|
const credentialUseContext = {
|
|
235
143
|
accountId: input.accountId,
|
|
@@ -299,50 +207,31 @@ export function connectionTokenResolverForTurn(input: {
|
|
|
299
207
|
},
|
|
300
208
|
};
|
|
301
209
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
210
|
+
const { subjectId: requestSubjectId, ...requestWithoutSubject } = request;
|
|
211
|
+
const result = await nativeResolver({
|
|
212
|
+
...requestWithoutSubject,
|
|
213
|
+
...(accountBinding?.connectionAuthorityGeneration !== undefined
|
|
214
|
+
? { expectedAuthorityGeneration: accountBinding.connectionAuthorityGeneration }
|
|
215
|
+
: {}),
|
|
216
|
+
// Workspace authority has no personal owner, even when the turn has a
|
|
217
|
+
// causal human. Do not pass that human as credential ownership context.
|
|
218
|
+
...(accountBinding?.subjectScope !== "workspace" && requestSubjectId !== undefined
|
|
219
|
+
? { subjectId: requestSubjectId }
|
|
220
|
+
: {}),
|
|
221
|
+
connectionUseContext: credentialUseContext,
|
|
222
|
+
});
|
|
223
|
+
if (
|
|
224
|
+
accountBinding &&
|
|
225
|
+
result.status === "ok" &&
|
|
226
|
+
result.connectionId !== accountBinding.connectionId
|
|
227
|
+
) {
|
|
320
228
|
return {
|
|
321
229
|
status: "auth_needed",
|
|
322
|
-
reason:
|
|
323
|
-
|
|
324
|
-
? "personal_authority_unavailable"
|
|
325
|
-
: "missing_connection",
|
|
326
|
-
providerDomain: request.connectionRef.providerDomain,
|
|
327
|
-
...(request.connectionRef.provider ? { provider: request.connectionRef.provider } : {}),
|
|
230
|
+
reason: "personal_authority_unavailable",
|
|
231
|
+
providerDomain: accountBinding.providerDomain,
|
|
328
232
|
};
|
|
329
233
|
}
|
|
330
|
-
|
|
331
|
-
const result = await baseResolver({
|
|
332
|
-
...request,
|
|
333
|
-
connectionUseContext: credentialUseContext,
|
|
334
|
-
connectionUseAuthority: authorization.attribution,
|
|
335
|
-
connectionRef: {
|
|
336
|
-
...request.connectionRef,
|
|
337
|
-
connectionId: authorization.attribution.connectionId,
|
|
338
|
-
kind: authorization.connectionKind,
|
|
339
|
-
subjectScope: authorization.attribution.scope === "workspace" ? "workspace" : "subject",
|
|
340
|
-
},
|
|
341
|
-
...(authorization.attribution.ownerSubjectId
|
|
342
|
-
? { subjectId: authorization.attribution.ownerSubjectId }
|
|
343
|
-
: {}),
|
|
344
|
-
});
|
|
345
|
-
return withProviderRequestAuthorization(result, authorization.attribution);
|
|
234
|
+
return withProviderRequestAuthorization(result);
|
|
346
235
|
};
|
|
347
236
|
}
|
|
348
237
|
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { stableJson } from "@opengeni/contracts";
|
|
3
3
|
import type { ConnectionUseAttribution } from "@opengeni/contracts/connection-authority";
|
|
4
|
-
import type { HostMcpAcceptedAuthority } from "@opengeni/contracts/host-mcp-bindings";
|
|
5
4
|
import type { ResolveConnectionCredentialInput } from "@opengeni/db";
|
|
6
5
|
|
|
7
6
|
/** Metadata only. Callers must obtain authority from a current live fence.
|
|
8
7
|
* This equality key is never authorization and never replaces physical-use checks. */
|
|
9
8
|
export function mcpOperationAuthorityDigest(
|
|
10
9
|
request: ResolveConnectionCredentialInput,
|
|
11
|
-
authority:
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
principal?: { kind: string; subjectId?: string };
|
|
16
|
-
}
|
|
17
|
-
| { host: HostMcpAcceptedAuthority; native?: never },
|
|
10
|
+
authority: {
|
|
11
|
+
native: ConnectionUseAttribution;
|
|
12
|
+
principal?: { kind: string; subjectId?: string };
|
|
13
|
+
},
|
|
18
14
|
): string {
|
|
19
15
|
const n = authority.native;
|
|
20
|
-
const h = authority.host;
|
|
21
16
|
const ref = request.connectionRef;
|
|
22
17
|
const metadata = {
|
|
23
18
|
version: 1,
|
|
@@ -31,7 +26,6 @@ export function mcpOperationAuthorityDigest(
|
|
|
31
26
|
providerDomain: ref.providerDomain,
|
|
32
27
|
kind: ref.kind,
|
|
33
28
|
subjectScope: ref.subjectScope,
|
|
34
|
-
hostBinding: ref.hostBinding,
|
|
35
29
|
scopes: ref.scopes ? [...ref.scopes].sort() : undefined,
|
|
36
30
|
resource: ref.resource,
|
|
37
31
|
selectedResources: ref.selectedResources
|
|
@@ -40,37 +34,18 @@ export function mcpOperationAuthorityDigest(
|
|
|
40
34
|
)
|
|
41
35
|
: undefined,
|
|
42
36
|
},
|
|
43
|
-
native:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
: undefined,
|
|
57
|
-
host: h
|
|
58
|
-
? {
|
|
59
|
-
accountId: h.accountId,
|
|
60
|
-
workspaceId: h.workspaceId,
|
|
61
|
-
targetSessionId: h.targetSessionId,
|
|
62
|
-
targetSessionVisibility: h.targetSessionVisibility,
|
|
63
|
-
targetSessionAuthorityEpoch: h.targetSessionAuthorityEpoch,
|
|
64
|
-
ownerSubjectId: h.ownerSubjectId,
|
|
65
|
-
ownerOrganizationMembershipId: h.ownerOrganizationMembershipId,
|
|
66
|
-
ownerMembershipAuthorizationRevision: h.ownerMembershipAuthorizationRevision,
|
|
67
|
-
bindingId: h.bindingId,
|
|
68
|
-
bindingGeneration: h.bindingGeneration,
|
|
69
|
-
definition: h.definition,
|
|
70
|
-
delegationId: h.delegationId,
|
|
71
|
-
delegationGeneration: h.delegationGeneration,
|
|
72
|
-
}
|
|
73
|
-
: undefined,
|
|
37
|
+
native: {
|
|
38
|
+
organizationId: n.organizationId,
|
|
39
|
+
workspaceId: n.workspaceId,
|
|
40
|
+
sessionId: n.sessionId,
|
|
41
|
+
connectionId: n.connectionId,
|
|
42
|
+
connectionGeneration: n.connectionGeneration,
|
|
43
|
+
scope: n.scope,
|
|
44
|
+
ownerSubjectId: n.ownerSubjectId,
|
|
45
|
+
authorityId: n.authorityId,
|
|
46
|
+
grantId: n.grantId,
|
|
47
|
+
principal: authority.principal,
|
|
48
|
+
},
|
|
74
49
|
};
|
|
75
50
|
return createHash("sha256").update(stableJson(metadata)).digest("hex");
|
|
76
51
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { listWorkspaceIdsAfter, reconcileModelCallFacts } from "@opengeni/db";
|
|
3
|
+
import type { ControlActivityServices } from "./types";
|
|
4
|
+
|
|
5
|
+
/** Recent charged calls are rechecked on every run; older gaps use the backfill script. */
|
|
6
|
+
export const MODEL_CALL_FACT_RECONCILE_LOOKBACK_MS = 2 * 60 * 60 * 1_000;
|
|
7
|
+
/** Skip the newest calls so a live fact write is not raced by its own repair. */
|
|
8
|
+
export const MODEL_CALL_FACT_RECONCILE_SETTLE_MS = 10 * 60 * 1_000;
|
|
9
|
+
export const MODEL_CALL_FACT_RECONCILE_WORKSPACE_LIMIT = 500;
|
|
10
|
+
export const MODEL_CALL_FACT_RECONCILE_RUN_BUDGET_MS = 3 * 60 * 1_000;
|
|
11
|
+
const WORKSPACE_PAGE_SIZE = 200;
|
|
12
|
+
|
|
13
|
+
export type ReconcileRecentModelCallFactsResult = {
|
|
14
|
+
workspaces: number;
|
|
15
|
+
missing: number;
|
|
16
|
+
repaired: number;
|
|
17
|
+
unrepaired: number;
|
|
18
|
+
/** Workspaces with more missing facts than one bounded pass examines. */
|
|
19
|
+
truncatedWorkspaces: number;
|
|
20
|
+
failedWorkspaces: number;
|
|
21
|
+
budgetExhausted: boolean;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ModelCallFactReconcilerOptions = {
|
|
25
|
+
now?: () => number;
|
|
26
|
+
runBudgetMs?: number;
|
|
27
|
+
startAfterWorkspaceId?: () => string;
|
|
28
|
+
reconcile?: typeof reconcileModelCallFacts;
|
|
29
|
+
listWorkspaces?: typeof listWorkspaceIdsAfter;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Rebuild missing Insights call facts for recently charged model calls. Each
|
|
34
|
+
* workspace pass is bounded and idempotent, one failure never stops the rest,
|
|
35
|
+
* and each run starts at a random workspace so a run that exhausts its budget
|
|
36
|
+
* does not starve the same tail of workspaces every time.
|
|
37
|
+
*/
|
|
38
|
+
export function createModelCallFactReconcilerActivities(
|
|
39
|
+
services: () => Promise<ControlActivityServices>,
|
|
40
|
+
options: ModelCallFactReconcilerOptions = {},
|
|
41
|
+
) {
|
|
42
|
+
const now = options.now ?? Date.now;
|
|
43
|
+
const runBudgetMs = options.runBudgetMs ?? MODEL_CALL_FACT_RECONCILE_RUN_BUDGET_MS;
|
|
44
|
+
const startAfterWorkspaceId = options.startAfterWorkspaceId ?? randomUUID;
|
|
45
|
+
const reconcile = options.reconcile ?? reconcileModelCallFacts;
|
|
46
|
+
const listWorkspaces = options.listWorkspaces ?? listWorkspaceIdsAfter;
|
|
47
|
+
|
|
48
|
+
async function reconcileRecentModelCallFacts(): Promise<ReconcileRecentModelCallFactsResult> {
|
|
49
|
+
const { db, observability } = await services();
|
|
50
|
+
const startedAt = now();
|
|
51
|
+
const until = new Date(startedAt - MODEL_CALL_FACT_RECONCILE_SETTLE_MS);
|
|
52
|
+
const since = new Date(until.getTime() - MODEL_CALL_FACT_RECONCILE_LOOKBACK_MS);
|
|
53
|
+
const result: ReconcileRecentModelCallFactsResult = {
|
|
54
|
+
workspaces: 0,
|
|
55
|
+
missing: 0,
|
|
56
|
+
repaired: 0,
|
|
57
|
+
unrepaired: 0,
|
|
58
|
+
truncatedWorkspaces: 0,
|
|
59
|
+
failedWorkspaces: 0,
|
|
60
|
+
budgetExhausted: false,
|
|
61
|
+
};
|
|
62
|
+
const start = startAfterWorkspaceId();
|
|
63
|
+
let cursor: string | null = start;
|
|
64
|
+
let wrapped = false;
|
|
65
|
+
while (true) {
|
|
66
|
+
const page = await listWorkspaces(db, { afterId: cursor, limit: WORKSPACE_PAGE_SIZE });
|
|
67
|
+
const ids = wrapped ? page.filter((id) => id <= start) : page;
|
|
68
|
+
for (const workspaceId of ids) {
|
|
69
|
+
if (now() - startedAt >= runBudgetMs) {
|
|
70
|
+
result.budgetExhausted = true;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
result.workspaces += 1;
|
|
74
|
+
try {
|
|
75
|
+
const outcome = await reconcile(db, {
|
|
76
|
+
workspaceId,
|
|
77
|
+
since,
|
|
78
|
+
until,
|
|
79
|
+
limit: MODEL_CALL_FACT_RECONCILE_WORKSPACE_LIMIT,
|
|
80
|
+
});
|
|
81
|
+
result.missing += outcome.missing;
|
|
82
|
+
result.repaired += outcome.repaired;
|
|
83
|
+
result.unrepaired += outcome.unrepaired;
|
|
84
|
+
if (outcome.truncated) result.truncatedWorkspaces += 1;
|
|
85
|
+
} catch (error) {
|
|
86
|
+
result.failedWorkspaces += 1;
|
|
87
|
+
observability.warn("model call fact reconciliation failed for a workspace", {
|
|
88
|
+
workspaceId,
|
|
89
|
+
errorName: error instanceof Error ? error.name : "unknown",
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (result.budgetExhausted) break;
|
|
94
|
+
if (wrapped && ids.length < page.length) break;
|
|
95
|
+
if (page.length < WORKSPACE_PAGE_SIZE) {
|
|
96
|
+
if (wrapped) break;
|
|
97
|
+
wrapped = true;
|
|
98
|
+
cursor = null;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
cursor = page[page.length - 1]!;
|
|
102
|
+
}
|
|
103
|
+
if (result.failedWorkspaces > 0 || result.truncatedWorkspaces > 0 || result.budgetExhausted) {
|
|
104
|
+
observability.warn("model call fact reconciliation incomplete", { ...result });
|
|
105
|
+
} else if (result.missing > 0) {
|
|
106
|
+
observability.info("model call fact reconciliation", { ...result });
|
|
107
|
+
}
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return { reconcileRecentModelCallFacts };
|
|
112
|
+
}
|
|
@@ -2,6 +2,7 @@ import type { Agent } from "@openai/agents";
|
|
|
2
2
|
import {
|
|
3
3
|
OPEN_SUFFIX_RUN_STATE_BLOB,
|
|
4
4
|
approvalIdentifier,
|
|
5
|
+
withPublicApprovalFields,
|
|
5
6
|
type HumanInputResponse,
|
|
6
7
|
type SessionEvent,
|
|
7
8
|
} from "@opengeni/contracts";
|
|
@@ -164,7 +165,7 @@ function memberResult(input: {
|
|
|
164
165
|
};
|
|
165
166
|
}
|
|
166
167
|
|
|
167
|
-
async function resultItemForOpenSuffixMember(input: {
|
|
168
|
+
export async function resultItemForOpenSuffixMember(input: {
|
|
168
169
|
agent: Agent<any, any>;
|
|
169
170
|
row: OpenSuffixPendingToolCall;
|
|
170
171
|
trigger: Pick<SessionEvent, "type" | "payload">;
|
|
@@ -177,6 +178,18 @@ async function resultItemForOpenSuffixMember(input: {
|
|
|
177
178
|
const name = toolNameFromCallItem(input.row.callItem);
|
|
178
179
|
const rejected = (): { resultItem: Record<string, unknown>; eventOutput: unknown } => {
|
|
179
180
|
const payload = input.trigger.payload as { message?: unknown; decision?: unknown };
|
|
181
|
+
if (
|
|
182
|
+
input.row.interruptionKind === "approval" &&
|
|
183
|
+
payload.decision === "reject" &&
|
|
184
|
+
!(typeof payload.message === "string" && payload.message.trim().length > 0)
|
|
185
|
+
) {
|
|
186
|
+
// This approval was rejected before invocation, not interrupted during execution.
|
|
187
|
+
return memberResult({
|
|
188
|
+
callId: input.row.callId,
|
|
189
|
+
name,
|
|
190
|
+
output: "Tool approval was rejected. This proposed tool call was not executed.",
|
|
191
|
+
});
|
|
192
|
+
}
|
|
180
193
|
const message =
|
|
181
194
|
typeof payload.message === "string" && payload.message.trim().length > 0
|
|
182
195
|
? payload.message
|
|
@@ -380,7 +393,7 @@ export async function settleOpenSuffixResumeIfNeeded(input: {
|
|
|
380
393
|
? [
|
|
381
394
|
{
|
|
382
395
|
type: "session.requiresAction" as const,
|
|
383
|
-
payload: { approvals: requiresActionApprovals },
|
|
396
|
+
payload: { approvals: requiresActionApprovals.map(withPublicApprovalFields) },
|
|
384
397
|
},
|
|
385
398
|
]
|
|
386
399
|
: []),
|