@opengeni/core 3.0.1 → 3.1.2
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/README.md +4 -4
- package/dist/access/index.d.ts +131 -7
- package/dist/access/service-initiator.d.ts +3 -0
- package/dist/application/archived-session-imports.d.ts +6 -0
- package/dist/application/composer-submit.d.ts +1 -1
- package/dist/application/connect-operation.d.ts +6 -0
- package/dist/application/external-workspace-members.d.ts +13 -1
- package/dist/application/modal-native-live-declaration-join.d.ts +37 -0
- package/dist/application/modal-native-original-configuration.d.ts +79 -0
- package/dist/application/modal-native-worker-host-transport.d.ts +297 -0
- package/dist/application/new-session-drafts.d.ts +29 -2
- package/dist/application/organization-privacy.d.ts +57 -0
- package/dist/application/prepared-mcp-connection.d.ts +31 -0
- package/dist/application/sandbox-recovery.d.ts +58 -0
- package/dist/application/session-commands.d.ts +3 -0
- package/dist/application/session-tenancy.d.ts +13 -4
- package/dist/billing/agent-run-admission.d.ts +21 -0
- package/dist/billing/limits.d.ts +27 -1
- package/dist/billing/model-call-admission.d.ts +34 -0
- package/dist/billing/model-usage-settlement.d.ts +112 -0
- package/dist/canonical-human-identities.js +1 -1
- package/dist/{chunk-VCZFFEPB.js → chunk-7T2SZ7BI.js} +16 -2
- package/dist/chunk-7T2SZ7BI.js.map +1 -0
- package/dist/{chunk-ZYCNLYGH.js → chunk-OMJFIIWK.js} +178 -12
- package/dist/chunk-OMJFIIWK.js.map +1 -0
- package/dist/{chunk-H7X52RI2.js → chunk-QI2M2B2K.js} +83 -8
- package/dist/chunk-QI2M2B2K.js.map +1 -0
- package/dist/{chunk-OF65T3PM.js → chunk-TTWTXQB2.js} +94 -6
- package/dist/chunk-TTWTXQB2.js.map +1 -0
- package/dist/codex-model-availability.d.ts +55 -0
- package/dist/default-session-model.d.ts +192 -0
- package/dist/dependencies.d.ts +41 -7
- package/dist/developer-setup-credential-ceiling.d.ts +10 -0
- package/dist/domain/agent-config-resolution.d.ts +49 -0
- package/dist/domain/automations.d.ts +8 -1
- package/dist/domain/capabilities.d.ts +112 -8
- package/dist/domain/connection-account-selection-error.d.ts +8 -0
- package/dist/domain/connector-tool-permissions.d.ts +62 -0
- package/dist/domain/direct-model-provider.d.ts +3 -0
- package/dist/domain/editable-artifacts/agent-application.d.ts +10 -1
- package/dist/domain/editable-artifacts/durable-export.d.ts +22 -1
- package/dist/domain/editable-artifacts/ports.d.ts +10 -0
- package/dist/domain/editable-artifacts/service.d.ts +3 -1
- package/dist/domain/editable-artifacts/types.d.ts +1 -1
- package/dist/domain/encryption-key.d.ts +12 -0
- package/dist/domain/insights-timing.d.ts +16 -0
- package/dist/domain/insights-usage.d.ts +27 -0
- package/dist/domain/insights.d.ts +21 -3
- package/dist/domain/knowledge-files.d.ts +1 -1
- package/dist/domain/knowledge-preparation.d.ts +10 -0
- package/dist/domain/knowledge-preparation.test.d.ts +1 -0
- package/dist/domain/knowledge-search.d.ts +15 -76
- package/dist/domain/mcp-account-bindings.d.ts +17 -0
- package/dist/domain/mcp-account-routes.d.ts +21 -0
- package/dist/domain/native-mcp-connection-admission.d.ts +3 -0
- package/dist/domain/organization-integration-catalog.d.ts +15 -0
- package/dist/domain/personal-connection-delegations.d.ts +73 -12
- package/dist/domain/pr-review.d.ts +121 -6
- package/dist/domain/realtime-voice-billing.d.ts +103 -0
- package/dist/domain/resources.d.ts +17 -1
- package/dist/domain/scheduled-task-access.d.ts +265 -0
- package/dist/domain/scheduled-task-account-audit.d.ts +27 -0
- package/dist/domain/scheduled-task-audience.d.ts +70 -0
- package/dist/domain/scheduled-tasks.d.ts +61 -18
- package/dist/domain/session-connection-accounts.d.ts +53 -0
- package/dist/domain/session-file-access.d.ts +4 -0
- package/dist/domain/session-native-connection-replacement.d.ts +14 -0
- package/dist/domain/session-start-timing.d.ts +7 -0
- package/dist/domain/session-tool-policy.d.ts +102 -4
- package/dist/domain/sessions.d.ts +179 -15
- package/dist/domain/site-audience.d.ts +52 -0
- package/dist/domain/skills.d.ts +29 -1
- package/dist/domain/slack-bot.d.ts +46 -1
- package/dist/domain/slack-publication-secret-safety.d.ts +1 -1
- package/dist/domain/vaults/index.d.ts +7 -0
- package/dist/domain/vaults/mapping.d.ts +25 -0
- package/dist/domain/vaults/provider-registry.d.ts +72 -0
- package/dist/domain/vaults/provider-sync.d.ts +176 -0
- package/dist/domain/vaults/provider-writes.d.ts +57 -0
- package/dist/domain/vaults/secret-resolver.d.ts +34 -0
- package/dist/domain/vaults/types.d.ts +24 -0
- package/dist/domain/vaults/vault-service.d.ts +35 -0
- package/dist/domain/voice-input-billing.d.ts +77 -0
- package/dist/domain/web-search-billing.d.ts +51 -0
- package/dist/domain/workspace-credits.d.ts +7 -0
- package/dist/editable-artifact-live/application.d.ts +2 -1
- package/dist/editable-artifact-live/server.d.ts +5 -1
- package/dist/editable-artifact-live/ticket.d.ts +2 -1
- package/dist/editable-artifact-live/types.d.ts +9 -0
- package/dist/editable-artifact-live.js +2 -2
- package/dist/editable-artifacts.js +10 -2
- package/dist/goal-admission.d.ts +627 -0
- package/dist/host-session-usage-limit.d.ts +15 -0
- package/dist/index.d.ts +43 -8
- package/dist/index.js +22682 -11743
- package/dist/index.js.map +1 -1
- package/dist/managed-session.d.ts +110 -7
- package/dist/model-call.d.ts +58 -0
- package/dist/model-catalog.d.ts +29 -3
- package/dist/model-provider-credentials.d.ts +43 -0
- package/dist/product-usage-metrics.d.ts +30 -0
- package/dist/rigs/index.d.ts +1 -13
- package/dist/sandbox/fleet.d.ts +58 -4
- package/dist/sandbox/routing.d.ts +42 -2
- package/dist/sandbox/runtime-settings.d.ts +27 -17
- package/dist/session-authorization.d.ts +10 -0
- package/dist/session-usage-limit-metrics.d.ts +60 -0
- package/dist/session-usage-limits.d.ts +89 -0
- package/dist/site-agent-clamp.d.ts +71 -0
- package/dist/site-session-origin.d.ts +39 -2
- package/dist/transcription.d.ts +120 -3
- package/dist/turn-surface.d.ts +20 -0
- package/dist/user-presence.d.ts +32 -0
- package/dist/workflow-wake-contract.d.ts +13 -1
- package/package.json +15 -22
- package/src/access/index.ts +961 -38
- package/src/access/service-initiator.ts +50 -0
- package/src/application/api-integration-servers.ts +9 -0
- package/src/application/archived-session-imports.ts +161 -0
- package/src/application/composer-submit.ts +3 -2
- package/src/application/connect-authority.ts +3 -3
- package/src/application/connect-operation.ts +37 -3
- package/src/application/external-continuation.ts +20 -3
- package/src/application/external-link-work-admission.ts +3 -0
- package/src/application/external-workspace-members.ts +51 -3
- package/src/application/modal-native-live-declaration-join.ts +196 -0
- package/src/application/modal-native-original-configuration.ts +261 -0
- package/src/application/modal-native-worker-host-transport.ts +263 -0
- package/src/application/new-session-drafts.ts +172 -55
- package/src/application/organization-privacy.ts +161 -0
- package/src/application/prepared-mcp-connection.ts +133 -0
- package/src/application/sandbox-recovery.ts +78 -0
- package/src/application/session-commands.ts +73 -1
- package/src/application/session-mcp-credential-rotation.ts +61 -18
- package/src/application/session-tenancy.ts +262 -44
- package/src/application/user-resource-grants.ts +1 -29
- package/src/billing/agent-run-admission.ts +117 -0
- package/src/billing/limits.ts +138 -14
- package/src/billing/model-call-admission.ts +118 -0
- package/src/billing/model-usage-settlement.ts +472 -0
- package/src/codex-model-availability.ts +264 -0
- package/src/default-session-model.ts +692 -0
- package/src/dependencies.ts +48 -6
- package/src/developer-setup-credential-ceiling.ts +60 -0
- package/src/domain/agent-config-resolution.ts +148 -0
- package/src/domain/automations.ts +76 -2
- package/src/domain/capabilities.ts +830 -181
- package/src/domain/connection-account-selection-error.ts +19 -0
- package/src/domain/connector-tool-permissions.ts +572 -0
- package/src/domain/direct-model-provider.ts +62 -0
- package/src/domain/editable-artifacts/agent-application.ts +44 -6
- package/src/domain/editable-artifacts/durable-export.ts +100 -5
- package/src/domain/editable-artifacts/in-memory.ts +6 -0
- package/src/domain/editable-artifacts/ports.ts +11 -0
- package/src/domain/editable-artifacts/service.ts +20 -0
- package/src/domain/editable-artifacts/types.ts +1 -1
- package/src/domain/encryption-key.ts +26 -0
- package/src/domain/file-owner.ts +16 -1
- package/src/domain/github-action-policies.ts +1 -1
- package/src/domain/github-skill-source.ts +3 -1
- package/src/domain/insights-timing.ts +95 -0
- package/src/domain/insights-usage.ts +67 -0
- package/src/domain/insights.ts +167 -43
- package/src/domain/knowledge-files.ts +10 -3
- package/src/domain/knowledge-messages.ts +1 -0
- package/src/domain/knowledge-preparation.test.ts +276 -0
- package/src/domain/knowledge-preparation.ts +147 -0
- package/src/domain/knowledge-search.test.ts +617 -5
- package/src/domain/knowledge-search.ts +240 -23
- package/src/domain/mcp-account-bindings.ts +169 -0
- package/src/domain/mcp-account-routes.ts +152 -0
- package/src/domain/native-mcp-connection-admission.ts +14 -0
- package/src/domain/organization-integration-catalog.ts +88 -0
- package/src/domain/personal-connection-delegations.ts +399 -257
- package/src/domain/pr-review.ts +24 -8
- package/src/domain/realtime-voice-billing.ts +425 -0
- package/src/domain/resources.ts +50 -4
- package/src/domain/scheduled-task-access.ts +1089 -0
- package/src/domain/scheduled-task-account-audit.ts +90 -0
- package/src/domain/scheduled-task-audience.ts +249 -0
- package/src/domain/scheduled-tasks.ts +1313 -374
- package/src/domain/session-connection-accounts.ts +239 -0
- package/src/domain/session-file-access.ts +47 -0
- package/src/domain/session-native-connection-replacement.ts +64 -0
- package/src/domain/session-start-timing.ts +60 -0
- package/src/domain/session-tool-policy.ts +489 -14
- package/src/domain/sessions.ts +2254 -717
- package/src/domain/site-audience.ts +130 -0
- package/src/domain/skills.ts +9 -0
- package/src/domain/slack-bot.ts +141 -4
- package/src/domain/slack-publication-secret-safety.ts +1 -1
- package/src/domain/vaults/index.ts +19 -0
- package/src/domain/vaults/mapping.ts +190 -0
- package/src/domain/vaults/provider-registry.ts +201 -0
- package/src/domain/vaults/provider-sync.ts +531 -0
- package/src/domain/vaults/provider-writes.ts +288 -0
- package/src/domain/vaults/secret-resolver.ts +464 -0
- package/src/domain/vaults/types.ts +26 -0
- package/src/domain/vaults/vault-service.ts +1316 -0
- package/src/domain/voice-input-billing.ts +330 -0
- package/src/domain/web-search-billing.ts +169 -0
- package/src/domain/workspace-credits.ts +13 -0
- package/src/editable-artifact-live/application.ts +8 -1
- package/src/editable-artifact-live/server.ts +154 -6
- package/src/editable-artifact-live/ticket.ts +86 -1
- package/src/editable-artifact-live/types.ts +10 -0
- package/src/goal-admission.ts +220 -0
- package/src/host-session-usage-limit.ts +25 -0
- package/src/index.ts +75 -11
- package/src/managed-session.ts +137 -6
- package/src/model-call.ts +79 -0
- package/src/model-catalog.ts +345 -91
- package/src/model-provider-credentials.ts +394 -0
- package/src/product-usage-metrics.ts +101 -0
- package/src/rigs/index.ts +23 -111
- package/src/sandbox/fleet.ts +253 -28
- package/src/sandbox/routing.ts +204 -43
- package/src/sandbox/runtime-settings.ts +159 -85
- package/src/session-authorization.ts +172 -23
- package/src/session-usage-limit-metrics.ts +95 -0
- package/src/session-usage-limits.ts +415 -0
- package/src/site-agent-clamp.ts +226 -0
- package/src/site-session-origin.ts +84 -5
- package/src/transcription.ts +123 -4
- package/src/turn-surface.ts +47 -0
- package/src/user-presence.ts +134 -0
- package/src/workflow-wake-contract.ts +14 -1
- package/dist/application/host-mcp-owner.d.ts +0 -6
- package/dist/application/host-mcp-resolvers.d.ts +0 -13
- package/dist/chunk-5WZYFL45.js +0 -266
- package/dist/chunk-5WZYFL45.js.map +0 -1
- package/dist/chunk-H7X52RI2.js.map +0 -1
- package/dist/chunk-OF65T3PM.js.map +0 -1
- package/dist/chunk-VCZFFEPB.js.map +0 -1
- package/dist/chunk-ZYCNLYGH.js.map +0 -1
- package/dist/domain/connection-authority.d.ts +0 -97
- package/dist/domain/connection-authority.js +0 -169
- package/dist/domain/connection-authority.js.map +0 -1
- package/dist/domain/environments.d.ts +0 -33
- package/dist/domain/host-mcp-authority-source-admission.d.ts +0 -10
- package/dist/domain/host-mcp-task-admission.d.ts +0 -18
- package/dist/domain/packs.d.ts +0 -59
- package/dist/domain/product-integration-pack.d.ts +0 -44
- package/dist/domain/product-integration-skill.gen.d.ts +0 -5
- package/dist/remote-mcp-credentials.d.ts +0 -23
- package/dist/remote-mcp-credentials.js +0 -11
- package/dist/remote-mcp-credentials.js.map +0 -1
- package/src/application/host-mcp-owner.ts +0 -41
- package/src/application/host-mcp-resolvers.ts +0 -84
- package/src/domain/connection-authority.ts +0 -329
- package/src/domain/environments.ts +0 -120
- package/src/domain/host-mcp-authority-source-admission.ts +0 -25
- package/src/domain/host-mcp-task-admission.ts +0 -121
- package/src/domain/packs.ts +0 -699
- package/src/domain/product-integration-pack.ts +0 -42
- package/src/domain/product-integration-skill.gen.ts +0 -52
- package/src/remote-mcp-credentials.ts +0 -361
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
AccessGrant,
|
|
3
|
+
ConnectionAccountIntent,
|
|
4
|
+
McpConnectionAccountBinding,
|
|
5
|
+
McpConnectionAccountSelection,
|
|
6
|
+
McpPersonalConnectionDelegation,
|
|
7
|
+
ResourceRef,
|
|
8
|
+
ToolRef,
|
|
9
|
+
} from "@opengeni/contracts";
|
|
10
|
+
import { GOOGLE_DRIVE_PUBLICATION_SERVER_ID } from "@opengeni/contracts/google-drive";
|
|
11
|
+
import { PERSONAL_GITHUB_CONNECTION_SURFACE_ID } from "@opengeni/contracts/personal-github";
|
|
12
|
+
import { resolveSessionFirstPartyMcpTools, type Settings } from "@opengeni/config";
|
|
13
|
+
import { requireSession, requireWorkspace, type Database } from "@opengeni/db";
|
|
14
|
+
import { settingsWithEnabledCapabilityMcpServers } from "./capabilities";
|
|
15
|
+
import {
|
|
16
|
+
ConnectionAccountSelectionError,
|
|
17
|
+
freezeConnectionAccounts,
|
|
18
|
+
personalConnectionDelegationSourceForGrant,
|
|
19
|
+
} from "./personal-connection-delegations";
|
|
20
|
+
import { personalGitHubRepositoryResources } from "./resources";
|
|
21
|
+
import {
|
|
22
|
+
sessionToolsForConnectionAccounts,
|
|
23
|
+
settingsWithSessionMcpServerMetadata,
|
|
24
|
+
} from "./sessions";
|
|
25
|
+
import { workspaceSessionToolPolicyDefaultServerIdsFor } from "./session-tool-policy";
|
|
26
|
+
|
|
27
|
+
/** Freeze the authenticated request's eligible accounts before starting voice.
|
|
28
|
+
* The resulting lease snapshot, not a later participant or ambient connection,
|
|
29
|
+
* supplies authority to both live delegations and automatic transcript handoff. */
|
|
30
|
+
export async function freezeSessionRealtimeConnectionAccounts(input: {
|
|
31
|
+
db: Database;
|
|
32
|
+
settings: Settings;
|
|
33
|
+
grant: AccessGrant;
|
|
34
|
+
workspaceId: string;
|
|
35
|
+
sessionId: string;
|
|
36
|
+
}) {
|
|
37
|
+
const { db, settings, grant, workspaceId, sessionId } = input;
|
|
38
|
+
const session = await requireSession(db, workspaceId, sessionId);
|
|
39
|
+
const workspace = await requireWorkspace(db, workspaceId);
|
|
40
|
+
const capabilitySettings = await settingsWithEnabledCapabilityMcpServers(
|
|
41
|
+
db,
|
|
42
|
+
workspaceId,
|
|
43
|
+
settings,
|
|
44
|
+
{
|
|
45
|
+
subjectId: grant.subjectId,
|
|
46
|
+
},
|
|
47
|
+
);
|
|
48
|
+
const runtimeSettings = settingsWithSessionMcpServerMetadata(
|
|
49
|
+
capabilitySettings,
|
|
50
|
+
session.mcpServers,
|
|
51
|
+
);
|
|
52
|
+
const tools = sessionToolsForConnectionAccounts({
|
|
53
|
+
session,
|
|
54
|
+
runtimeMcpServers: runtimeSettings.mcpServers,
|
|
55
|
+
defaultMcpServerIds: workspaceSessionToolPolicyDefaultServerIdsFor(
|
|
56
|
+
capabilitySettings.mcpServers,
|
|
57
|
+
workspace.settings,
|
|
58
|
+
),
|
|
59
|
+
});
|
|
60
|
+
const effectiveFirstPartyTools = resolveSessionFirstPartyMcpTools(
|
|
61
|
+
settings,
|
|
62
|
+
session,
|
|
63
|
+
workspace.settings,
|
|
64
|
+
);
|
|
65
|
+
return await freezeConnectionAccounts({
|
|
66
|
+
db,
|
|
67
|
+
settings: runtimeSettings,
|
|
68
|
+
accountId: grant.accountId,
|
|
69
|
+
workspaceId,
|
|
70
|
+
tools,
|
|
71
|
+
resources: session.resources,
|
|
72
|
+
source: personalConnectionDelegationSourceForGrant(grant),
|
|
73
|
+
targetSessionId: sessionId,
|
|
74
|
+
googleDrivePublicationEnabled:
|
|
75
|
+
effectiveFirstPartyTools.includes("editable_artifact_export") &&
|
|
76
|
+
effectiveFirstPartyTools.includes("editable_artifact_export_status") &&
|
|
77
|
+
(!session.firstPartyMcpPermissions?.length ||
|
|
78
|
+
(session.firstPartyMcpPermissions.includes("artifacts:read") &&
|
|
79
|
+
session.firstPartyMcpPermissions.includes("artifacts:publish"))),
|
|
80
|
+
atlassianEnabled:
|
|
81
|
+
effectiveFirstPartyTools.some((tool) => tool.startsWith("atlassian_")) &&
|
|
82
|
+
(!session.firstPartyMcpPermissions?.length ||
|
|
83
|
+
session.firstPartyMcpPermissions.includes("connections:read")),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** One connector a continued turn runs without, and why. */
|
|
88
|
+
export type ContinuedConnectionAccountGap = {
|
|
89
|
+
serverId: string;
|
|
90
|
+
/** The picked account that can no longer be used; null when none was picked. */
|
|
91
|
+
connectionId: string | null;
|
|
92
|
+
reason: string;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Accounts for a turn that continues earlier work in this session: a goal
|
|
97
|
+
* continuation, a wait wake-up, a command or child result, or informational
|
|
98
|
+
* input delivered into the person's last message. It resolves the carried
|
|
99
|
+
* intent exactly as that person's next message with the same picks would be
|
|
100
|
+
* resolved now, against the session's current connectors and the person's
|
|
101
|
+
* current accounts. Nothing from an earlier turn's accounts is copied.
|
|
102
|
+
*
|
|
103
|
+
* A picked account that can no longer be used is never replaced by another
|
|
104
|
+
* account: its connector is left out of this turn. The same applies to a
|
|
105
|
+
* connector whose account can no longer be chosen automatically (for example
|
|
106
|
+
* several accounts now match and none was picked). Every other connector is
|
|
107
|
+
* unaffected.
|
|
108
|
+
*
|
|
109
|
+
* `db` is the claim transaction, so every read runs one at a time.
|
|
110
|
+
*/
|
|
111
|
+
export async function resolveContinuedConnectionAccounts(input: {
|
|
112
|
+
db: Database;
|
|
113
|
+
settings: Settings;
|
|
114
|
+
accountId: string;
|
|
115
|
+
workspaceId: string;
|
|
116
|
+
sessionId: string;
|
|
117
|
+
intent: ConnectionAccountIntent;
|
|
118
|
+
}): Promise<{
|
|
119
|
+
mcpAccountBindings: McpConnectionAccountBinding[] | null;
|
|
120
|
+
personalConnectionDelegations: McpPersonalConnectionDelegation[];
|
|
121
|
+
/** Connectors the turn runs without, because their account cannot be used. */
|
|
122
|
+
gaps: ContinuedConnectionAccountGap[];
|
|
123
|
+
}> {
|
|
124
|
+
const { db, settings, accountId, workspaceId, sessionId, intent } = input;
|
|
125
|
+
const principalSubjectId =
|
|
126
|
+
intent.principal.kind === "subject" ? intent.principal.subjectId : null;
|
|
127
|
+
const session = await requireSession(db, workspaceId, sessionId);
|
|
128
|
+
const workspace = await requireWorkspace(db, workspaceId);
|
|
129
|
+
const capabilitySettings = await settingsWithEnabledCapabilityMcpServers(
|
|
130
|
+
db,
|
|
131
|
+
workspaceId,
|
|
132
|
+
settings,
|
|
133
|
+
principalSubjectId
|
|
134
|
+
? { subjectId: principalSubjectId, oneReadAtATime: true }
|
|
135
|
+
: { oneReadAtATime: true },
|
|
136
|
+
);
|
|
137
|
+
const runtimeSettings = settingsWithSessionMcpServerMetadata(
|
|
138
|
+
capabilitySettings,
|
|
139
|
+
session.mcpServers,
|
|
140
|
+
);
|
|
141
|
+
let tools: ToolRef[] = sessionToolsForConnectionAccounts({
|
|
142
|
+
session,
|
|
143
|
+
runtimeMcpServers: runtimeSettings.mcpServers,
|
|
144
|
+
defaultMcpServerIds: workspaceSessionToolPolicyDefaultServerIdsFor(
|
|
145
|
+
capabilitySettings.mcpServers,
|
|
146
|
+
workspace.settings,
|
|
147
|
+
),
|
|
148
|
+
});
|
|
149
|
+
const effectiveFirstPartyTools = resolveSessionFirstPartyMcpTools(
|
|
150
|
+
settings,
|
|
151
|
+
session,
|
|
152
|
+
workspace.settings,
|
|
153
|
+
);
|
|
154
|
+
let googleDrivePublicationEnabled =
|
|
155
|
+
effectiveFirstPartyTools.includes("editable_artifact_export") &&
|
|
156
|
+
effectiveFirstPartyTools.includes("editable_artifact_export_status") &&
|
|
157
|
+
(!session.firstPartyMcpPermissions?.length ||
|
|
158
|
+
(session.firstPartyMcpPermissions.includes("artifacts:read") &&
|
|
159
|
+
session.firstPartyMcpPermissions.includes("artifacts:publish")));
|
|
160
|
+
const atlassianEnabled =
|
|
161
|
+
effectiveFirstPartyTools.some((tool) => tool.startsWith("atlassian_")) &&
|
|
162
|
+
(!session.firstPartyMcpPermissions?.length ||
|
|
163
|
+
session.firstPartyMcpPermissions.includes("connections:read"));
|
|
164
|
+
const withoutPersonalRepositories = (from: ResourceRef[]) => {
|
|
165
|
+
const personal = new Set<ResourceRef>(personalGitHubRepositoryResources(from));
|
|
166
|
+
return from.filter((resource) => !personal.has(resource));
|
|
167
|
+
};
|
|
168
|
+
// Work without a person behind it never uses a personal repository grant.
|
|
169
|
+
let resources: ResourceRef[] = principalSubjectId
|
|
170
|
+
? session.resources
|
|
171
|
+
: withoutPersonalRepositories(session.resources);
|
|
172
|
+
// A pick for a connector the session no longer uses does not apply.
|
|
173
|
+
const applies = (selection: McpConnectionAccountSelection) =>
|
|
174
|
+
selection.serverId === GOOGLE_DRIVE_PUBLICATION_SERVER_ID
|
|
175
|
+
? googleDrivePublicationEnabled
|
|
176
|
+
: selection.serverId === PERSONAL_GITHUB_CONNECTION_SURFACE_ID
|
|
177
|
+
? personalGitHubRepositoryResources(resources).length > 0
|
|
178
|
+
: tools.some((tool) => tool.kind === "mcp" && tool.id === selection.serverId);
|
|
179
|
+
let selections = intent.selections.filter(applies);
|
|
180
|
+
const gaps: ContinuedConnectionAccountGap[] = [];
|
|
181
|
+
// Each round removes at least one connector or pick, so this always ends.
|
|
182
|
+
for (let round = 0; ; round += 1) {
|
|
183
|
+
try {
|
|
184
|
+
const resolved = await freezeConnectionAccounts({
|
|
185
|
+
db,
|
|
186
|
+
accountId,
|
|
187
|
+
workspaceId,
|
|
188
|
+
settings: runtimeSettings,
|
|
189
|
+
tools,
|
|
190
|
+
resources,
|
|
191
|
+
source: principalSubjectId
|
|
192
|
+
? { kind: "subject", subjectId: principalSubjectId, accountId }
|
|
193
|
+
: { kind: "none" },
|
|
194
|
+
targetSessionId: sessionId,
|
|
195
|
+
googleDrivePublicationEnabled,
|
|
196
|
+
atlassianEnabled,
|
|
197
|
+
authoritySelections: selections,
|
|
198
|
+
});
|
|
199
|
+
return {
|
|
200
|
+
mcpAccountBindings: resolved.mcpAccountBindings,
|
|
201
|
+
personalConnectionDelegations: resolved.personalConnectionDelegations,
|
|
202
|
+
gaps,
|
|
203
|
+
};
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (!(error instanceof ConnectionAccountSelectionError)) throw error;
|
|
206
|
+
const named = error.diagnostic.accounts.filter(
|
|
207
|
+
(account) =>
|
|
208
|
+
account.connectionId === null ||
|
|
209
|
+
selections.some(
|
|
210
|
+
(selection) =>
|
|
211
|
+
selection.serverId === account.serverId &&
|
|
212
|
+
selection.connectionId === account.connectionId,
|
|
213
|
+
),
|
|
214
|
+
);
|
|
215
|
+
// The person lost access to this workspace: none of their picks can be used.
|
|
216
|
+
const unusable =
|
|
217
|
+
named.length > 0
|
|
218
|
+
? named
|
|
219
|
+
: error.diagnostic.reason === "owner_access_unavailable"
|
|
220
|
+
? selections.map((selection) => ({ ...selection, reason: error.diagnostic.reason }))
|
|
221
|
+
: [];
|
|
222
|
+
const dropped = new Set(unusable.map((account) => account.serverId));
|
|
223
|
+
if (dropped.size === 0 || round > intent.selections.length + tools.length + 2) throw error;
|
|
224
|
+
gaps.push(
|
|
225
|
+
...unusable.map((account) => ({
|
|
226
|
+
serverId: account.serverId,
|
|
227
|
+
connectionId: account.connectionId,
|
|
228
|
+
reason: account.reason,
|
|
229
|
+
})),
|
|
230
|
+
);
|
|
231
|
+
selections = selections.filter((selection) => !dropped.has(selection.serverId));
|
|
232
|
+
tools = tools.filter((tool) => !(tool.kind === "mcp" && dropped.has(tool.id)));
|
|
233
|
+
if (dropped.has(GOOGLE_DRIVE_PUBLICATION_SERVER_ID)) googleDrivePublicationEnabled = false;
|
|
234
|
+
if (dropped.has(PERSONAL_GITHUB_CONNECTION_SURFACE_ID)) {
|
|
235
|
+
resources = withoutPersonalRepositories(resources);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AccessGrant, FileAsset } from "@opengeni/contracts";
|
|
2
|
+
import {
|
|
3
|
+
getSessionAuthorityProjection,
|
|
4
|
+
getFilesForSubject,
|
|
5
|
+
readSessionFileAttachments,
|
|
6
|
+
withSessionRlsActorContext,
|
|
7
|
+
} from "@opengeni/db";
|
|
8
|
+
import type { SessionAuthorizationDependencies } from "../session-authorization";
|
|
9
|
+
import {
|
|
10
|
+
requireSessionAuthorization,
|
|
11
|
+
withResolvedSessionAuthorization,
|
|
12
|
+
} from "../session-authorization";
|
|
13
|
+
|
|
14
|
+
/** A session attachment grant is never a generic file/Knowledge grant. */
|
|
15
|
+
export async function readSessionAttachmentFiles(
|
|
16
|
+
deps: SessionAuthorizationDependencies,
|
|
17
|
+
grant: AccessGrant,
|
|
18
|
+
sessionId: string,
|
|
19
|
+
fileIds: readonly string[],
|
|
20
|
+
): Promise<FileAsset[]> {
|
|
21
|
+
const authority = await getSessionAuthorityProjection(deps.db, grant.workspaceId, sessionId);
|
|
22
|
+
if (!authority) return [];
|
|
23
|
+
const authorization = await requireSessionAuthorization(deps, grant, {
|
|
24
|
+
sessionId,
|
|
25
|
+
operation: "session.read",
|
|
26
|
+
surface: "core",
|
|
27
|
+
});
|
|
28
|
+
const ordinary = await getFilesForSubject(deps.db, {
|
|
29
|
+
accountId: grant.accountId,
|
|
30
|
+
workspaceId: grant.workspaceId,
|
|
31
|
+
subjectId: grant.subjectId,
|
|
32
|
+
fileIds,
|
|
33
|
+
});
|
|
34
|
+
const missing = fileIds.filter((id) => !ordinary.some((file) => file.id === id));
|
|
35
|
+
const actor = authorization?.actor ?? { kind: "subject" as const, subjectId: grant.subjectId };
|
|
36
|
+
const read = () =>
|
|
37
|
+
readSessionFileAttachments(deps.db, {
|
|
38
|
+
accountId: grant.accountId,
|
|
39
|
+
workspaceId: grant.workspaceId,
|
|
40
|
+
fileIds: missing,
|
|
41
|
+
access: { sessionId, authorityEpoch: authority.authorityEpoch, actor },
|
|
42
|
+
});
|
|
43
|
+
const shared = authorization
|
|
44
|
+
? await withResolvedSessionAuthorization(authorization, read)
|
|
45
|
+
: await withSessionRlsActorContext({ subjectId: grant.subjectId }, read);
|
|
46
|
+
return [...ordinary, ...shared];
|
|
47
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ConnectionMetadata, McpServerConnectionRef } from "@opengeni/contracts";
|
|
2
|
+
import { connectionMetadataMatchesBinding } from "@opengeni/db/session-mcp-credential-rotation";
|
|
3
|
+
|
|
4
|
+
/** Selection is restricted to the caller's already-authorized inventory. This
|
|
5
|
+
* projection grants no execution authority: subsequent admission and physical
|
|
6
|
+
* credential use still validate the exact native account normally. */
|
|
7
|
+
export function nativeSessionConnectionReplacement(input: {
|
|
8
|
+
accountId: string;
|
|
9
|
+
workspaceId: string;
|
|
10
|
+
subjectId: string | null;
|
|
11
|
+
serverUrl: string;
|
|
12
|
+
replacementServerUrl?: string;
|
|
13
|
+
currentRef: McpServerConnectionRef | null;
|
|
14
|
+
nativeConnectionId: string;
|
|
15
|
+
connections: ConnectionMetadata[];
|
|
16
|
+
}): McpServerConnectionRef {
|
|
17
|
+
const connection = input.connections.find(
|
|
18
|
+
(candidate) => candidate.id === input.nativeConnectionId,
|
|
19
|
+
);
|
|
20
|
+
if (
|
|
21
|
+
!connection ||
|
|
22
|
+
connection.accountId !== input.accountId ||
|
|
23
|
+
connection.status !== "active" ||
|
|
24
|
+
(connection.subjectId === null
|
|
25
|
+
? connection.workspaceId !== input.workspaceId
|
|
26
|
+
: !input.subjectId || connection.subjectId !== input.subjectId || !connection.authorityId)
|
|
27
|
+
) {
|
|
28
|
+
throw new Error("native connection unavailable");
|
|
29
|
+
}
|
|
30
|
+
const {
|
|
31
|
+
authoritySource: _authoritySource,
|
|
32
|
+
hostBinding: _hostBinding,
|
|
33
|
+
accountSelection: _accountSelection,
|
|
34
|
+
...retained
|
|
35
|
+
} = input.currentRef ?? {};
|
|
36
|
+
// Preserve provider, resource, scope and selected-resource restrictions.
|
|
37
|
+
// Retired host identity is never interpreted as a native connection ID.
|
|
38
|
+
if (
|
|
39
|
+
input.currentRef &&
|
|
40
|
+
input.currentRef.providerDomain.toLowerCase() !== connection.providerDomain.toLowerCase()
|
|
41
|
+
)
|
|
42
|
+
throw new Error("native connection provider mismatch");
|
|
43
|
+
const ref: McpServerConnectionRef = {
|
|
44
|
+
...retained,
|
|
45
|
+
...(!input.currentRef?.resource && typeof connection.metadata.resource === "string"
|
|
46
|
+
? { resource: connection.metadata.resource }
|
|
47
|
+
: {}),
|
|
48
|
+
connectionId: connection.id,
|
|
49
|
+
providerDomain: connection.providerDomain,
|
|
50
|
+
kind: connection.kind,
|
|
51
|
+
subjectScope: connection.subjectId === null ? "workspace" : "subject",
|
|
52
|
+
};
|
|
53
|
+
const destination = input.replacementServerUrl ?? input.serverUrl;
|
|
54
|
+
// A redirect must be explicitly requested and bound in the account metadata;
|
|
55
|
+
// the broker's legacy provider-host fallback is insufficient for rebinding.
|
|
56
|
+
if (
|
|
57
|
+
input.replacementServerUrl &&
|
|
58
|
+
(typeof connection.metadata.mcpUrl !== "string" || !connection.metadata.mcpUrl.trim())
|
|
59
|
+
)
|
|
60
|
+
throw new Error("native connection destination unavailable");
|
|
61
|
+
if (!connectionMetadataMatchesBinding(connection, ref, destination))
|
|
62
|
+
throw new Error("native connection binding mismatch");
|
|
63
|
+
return ref;
|
|
64
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { withTraceContext, type Observability, type Span } from "@opengeni/observability";
|
|
2
|
+
|
|
3
|
+
type SessionStartPhase =
|
|
4
|
+
| "workspace_read"
|
|
5
|
+
| "idempotent_replay"
|
|
6
|
+
| "model_catalog_initial"
|
|
7
|
+
| "default_model"
|
|
8
|
+
| "model_catalog_effective"
|
|
9
|
+
| "capability_settings"
|
|
10
|
+
| "resource_validation"
|
|
11
|
+
| "rig_binding"
|
|
12
|
+
| "model_admission"
|
|
13
|
+
| "connection_freeze"
|
|
14
|
+
| "initiator_freeze"
|
|
15
|
+
| "allowance"
|
|
16
|
+
| "shell_insert"
|
|
17
|
+
| "initialize"
|
|
18
|
+
| "event_fanout"
|
|
19
|
+
| "workflow_wake"
|
|
20
|
+
| "session_reload";
|
|
21
|
+
export type SessionStartObservability = Pick<Observability, "startSpan">;
|
|
22
|
+
|
|
23
|
+
/** Content-free child spans around existing work; export is never joined and
|
|
24
|
+
* diagnostic failures cannot alter the lifecycle or its exact error. */
|
|
25
|
+
export async function measureSessionStartPhase<T>(
|
|
26
|
+
observability: SessionStartObservability | null | undefined,
|
|
27
|
+
phase: SessionStartPhase,
|
|
28
|
+
work: () => Promise<T>,
|
|
29
|
+
): Promise<T> {
|
|
30
|
+
let span: Span | undefined;
|
|
31
|
+
try {
|
|
32
|
+
span = observability?.startSpan(`core.session_start.${phase}`);
|
|
33
|
+
} catch {
|
|
34
|
+
// An unhealthy observer is not session authority.
|
|
35
|
+
}
|
|
36
|
+
const end = (outcome: "completed" | "failed") => {
|
|
37
|
+
try {
|
|
38
|
+
void Promise.resolve(span?.end({ attributes: { outcome } })).catch(() => undefined);
|
|
39
|
+
} catch {
|
|
40
|
+
// Never leak diagnostic errors or user content through an error field.
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
const result = span ? withTraceContext(span, work) : work();
|
|
45
|
+
if (!span) return result;
|
|
46
|
+
return result.then(
|
|
47
|
+
(value) => {
|
|
48
|
+
end("completed");
|
|
49
|
+
return value;
|
|
50
|
+
},
|
|
51
|
+
(error) => {
|
|
52
|
+
end("failed");
|
|
53
|
+
throw error;
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
} catch (error) {
|
|
57
|
+
end("failed");
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|