@opengeni/core 2.10.0-canary.0 → 2.10.0-canary.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/dist/application/external-workspace-members.d.ts +16 -0
- package/dist/application/host-mcp-resolvers.d.ts +13 -0
- package/dist/application/new-session-drafts.d.ts +4 -2
- package/dist/chunk-5WZYFL45.js +266 -0
- package/dist/chunk-5WZYFL45.js.map +1 -0
- package/dist/domain/file-owner.d.ts +8 -0
- package/dist/domain/knowledge-files.d.ts +20 -0
- package/dist/domain/knowledge-messages.d.ts +39 -0
- package/dist/domain/knowledge-messages.test.d.ts +1 -0
- package/dist/domain/knowledge-search.d.ts +80 -0
- package/dist/domain/knowledge-search.test.d.ts +1 -0
- package/dist/domain/knowledge.d.ts +9 -0
- package/dist/domain/pr-review.d.ts +2 -2
- package/dist/domain/resources.d.ts +2 -2
- package/dist/domain/scheduled-tasks.d.ts +12 -2
- package/dist/domain/sessions.d.ts +6 -2
- package/dist/domain/skills.d.ts +16 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +3948 -3939
- package/dist/index.js.map +1 -1
- package/dist/remote-mcp-credentials.d.ts +16 -1
- package/dist/remote-mcp-credentials.js +7 -215
- package/dist/remote-mcp-credentials.js.map +1 -1
- package/package.json +12 -12
- package/src/application/external-workspace-members.ts +89 -0
- package/src/application/host-mcp-resolvers.ts +85 -0
- package/src/application/new-session-drafts.ts +37 -3
- package/src/domain/file-owner.ts +52 -0
- package/src/domain/host-mcp-task-admission.ts +27 -17
- package/src/domain/knowledge-files.ts +39 -0
- package/src/domain/knowledge-messages.test.ts +91 -0
- package/src/domain/knowledge-messages.ts +105 -0
- package/src/domain/knowledge-search.test.ts +45 -0
- package/src/domain/knowledge-search.ts +55 -0
- package/src/domain/knowledge.ts +133 -0
- package/src/domain/product-integration-skill.gen.ts +7 -7
- package/src/domain/resources.ts +36 -25
- package/src/domain/scheduled-tasks.ts +362 -139
- package/src/domain/sessions.ts +117 -20
- package/src/domain/skills.ts +8 -0
- package/src/index.ts +9 -4
- package/src/remote-mcp-credentials.ts +76 -8
- package/dist/domain/company-brain-governed-writes.d.ts +0 -79
- package/dist/domain/governed-learning-activation.d.ts +0 -16
- package/dist/domain/governed-learning-evaluator.d.ts +0 -6
- package/dist/domain/remember.d.ts +0 -72
- package/src/domain/company-brain-governed-writes.ts +0 -346
- package/src/domain/governed-learning-activation.ts +0 -44
- package/src/domain/governed-learning-evaluator.ts +0 -49
- package/src/domain/remember.ts +0 -577
package/src/domain/sessions.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import { knowledgeContextForAccess } from "./knowledge";
|
|
2
|
+
import { saveAgentLearningSettings } from "@opengeni/db";
|
|
3
|
+
import { withSessionRlsActorContext } from "@opengeni/db";
|
|
4
|
+
import { fileOwnerContextForAccess, fileOwnerContextForAgent } from "./file-owner";
|
|
1
5
|
import { CODEX_MODEL_ID_PREFIX, isCodexBilledModel } from "@opengeni/codex";
|
|
2
6
|
import { sessionCreationMetadata } from "../site-session-origin";
|
|
3
7
|
import {
|
|
4
|
-
|
|
8
|
+
hostMcpBindingMatchesSelection,
|
|
5
9
|
HostMcpCreateSelections,
|
|
6
10
|
type HostMcpCreateSelection,
|
|
7
11
|
} from "@opengeni/contracts/host-mcp-bindings";
|
|
@@ -30,6 +34,7 @@ import {
|
|
|
30
34
|
CreateSessionRequest,
|
|
31
35
|
DEFAULT_FIRST_PARTY_MCP_PERMISSIONS,
|
|
32
36
|
DEFAULT_FIRST_PARTY_MCP_TOOLS,
|
|
37
|
+
currentAgentLearningToolSelection,
|
|
33
38
|
DraftTimelineAnnotations,
|
|
34
39
|
FIRST_PARTY_MCP_TOOL_NAMES,
|
|
35
40
|
OPENGENI_SLACK_BOT_SESSION_METADATA_KEY,
|
|
@@ -272,8 +277,10 @@ export function effectiveFirstPartyMcpToolCeiling(
|
|
|
272
277
|
allowed: readonly FirstPartyMcpToolName[];
|
|
273
278
|
},
|
|
274
279
|
): Set<FirstPartyMcpToolName> {
|
|
275
|
-
const allowed = new Set(policy.allowed);
|
|
276
|
-
const ceiling = new Set(
|
|
280
|
+
const allowed = new Set(currentAgentLearningToolSelection(policy.allowed));
|
|
281
|
+
const ceiling = new Set(
|
|
282
|
+
currentAgentLearningToolSelection(stored ?? policy.default).filter((tool) => allowed.has(tool)),
|
|
283
|
+
);
|
|
277
284
|
if (ceiling.has("goal_pause") && allowed.has("goal_resume")) ceiling.add("goal_resume");
|
|
278
285
|
return ceiling;
|
|
279
286
|
}
|
|
@@ -300,6 +307,7 @@ export function resolveFirstPartyMcpToolsForCreate(
|
|
|
300
307
|
},
|
|
301
308
|
): FirstPartyMcpToolName[] {
|
|
302
309
|
if (requested !== undefined) {
|
|
310
|
+
requested = currentAgentLearningToolSelection(requested);
|
|
303
311
|
if (parentStored !== undefined) {
|
|
304
312
|
const parentCeiling = effectiveFirstPartyMcpToolCeiling(parentStored, policy);
|
|
305
313
|
const widened = requested.find((tool) => !parentCeiling.has(tool));
|
|
@@ -311,9 +319,9 @@ export function resolveFirstPartyMcpToolsForCreate(
|
|
|
311
319
|
}
|
|
312
320
|
return [...requested];
|
|
313
321
|
}
|
|
314
|
-
const allowed = new Set(policy.allowed);
|
|
322
|
+
const allowed = new Set(currentAgentLearningToolSelection(policy.allowed));
|
|
315
323
|
const inherited = parentStored === undefined ? policy.default : (parentStored ?? policy.default);
|
|
316
|
-
return
|
|
324
|
+
return currentAgentLearningToolSelection(inherited).filter((tool) => allowed.has(tool));
|
|
317
325
|
}
|
|
318
326
|
|
|
319
327
|
function sessionSpawnDeniedMessage(denial: SessionSpawnDenial): string {
|
|
@@ -738,6 +746,7 @@ function automaticTitleForAgentChildCreate(
|
|
|
738
746
|
}
|
|
739
747
|
|
|
740
748
|
export async function createAndStartSessionWithOutcome(input: {
|
|
749
|
+
initialAgentLearning?: import("@opengeni/contracts").AgentLearningOverrides | undefined;
|
|
741
750
|
requestedSessionId?: string;
|
|
742
751
|
db: Database;
|
|
743
752
|
bus: EventBus;
|
|
@@ -1024,6 +1033,7 @@ export async function createAndStartSessionWithOutcome(input: {
|
|
|
1024
1033
|
tools: input.tools,
|
|
1025
1034
|
toolPolicy: input.toolPolicy,
|
|
1026
1035
|
metadata: sessionMetadata,
|
|
1036
|
+
initialAgentLearning: input.initialAgentLearning,
|
|
1027
1037
|
selectedHostMcpDelegations: input.selectedHostMcpDelegations ?? [],
|
|
1028
1038
|
...(input.createdBy ? { createdBy: input.createdBy } : {}),
|
|
1029
1039
|
...(frozenCreatedByContext ? { createdByContext: frozenCreatedByContext } : {}),
|
|
@@ -1119,6 +1129,7 @@ export async function createAndStartSessionWithOutcome(input: {
|
|
|
1119
1129
|
tools: input.tools,
|
|
1120
1130
|
toolPolicy: input.toolPolicy,
|
|
1121
1131
|
metadata: sessionMetadata,
|
|
1132
|
+
initialAgentLearning: input.initialAgentLearning,
|
|
1122
1133
|
...(input.createdBy ? { createdBy: input.createdBy } : {}),
|
|
1123
1134
|
selectedHostMcpDelegations: input.selectedHostMcpDelegations ?? [],
|
|
1124
1135
|
...(frozenCreatedByContext ? { createdByContext: frozenCreatedByContext } : {}),
|
|
@@ -2004,7 +2015,7 @@ async function withSessionCreateUsageRecording(input: {
|
|
|
2004
2015
|
return { ...input.createOutcome, usageRecording };
|
|
2005
2016
|
}
|
|
2006
2017
|
|
|
2007
|
-
|
|
2018
|
+
async function createSessionForRequestInFileScope(
|
|
2008
2019
|
unresolvedDeps: ApiRouteDeps,
|
|
2009
2020
|
grant: AccessGrant,
|
|
2010
2021
|
workspaceId: string,
|
|
@@ -2180,6 +2191,8 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2180
2191
|
: {}),
|
|
2181
2192
|
createIdempotencyKey: payload.idempotencyKey,
|
|
2182
2193
|
selectedInstalledSkillIds: payload.installedSkillIds ?? [],
|
|
2194
|
+
initialAgentLearning: payload.agentLearning,
|
|
2195
|
+
...sessionScope,
|
|
2183
2196
|
selectedHostMcpDelegations: hostSelections,
|
|
2184
2197
|
...(payload.requestedSessionId ? { requestedSessionId: payload.requestedSessionId } : {}),
|
|
2185
2198
|
visibility: effectiveVisibility,
|
|
@@ -2455,7 +2468,21 @@ export async function createSessionForRequestWithOutcome(
|
|
|
2455
2468
|
message: "object storage is not configured",
|
|
2456
2469
|
});
|
|
2457
2470
|
}
|
|
2458
|
-
await validateFileResources(
|
|
2471
|
+
await validateFileResources(
|
|
2472
|
+
db,
|
|
2473
|
+
grant.accountId,
|
|
2474
|
+
workspaceId,
|
|
2475
|
+
personalResourceSubjectId ?? grant.subjectId,
|
|
2476
|
+
resources,
|
|
2477
|
+
(authorization || grant.principalKind === "agent_attempt") &&
|
|
2478
|
+
(effectiveVisibility === "user_private" ||
|
|
2479
|
+
sessionScope.memoryScope === "user" ||
|
|
2480
|
+
workspace.kind === "personal")
|
|
2481
|
+
? authorization
|
|
2482
|
+
? await fileOwnerContextForAccess({ db }, authorization, "sessions:create")
|
|
2483
|
+
: await fileOwnerContextForAgent({ db }, grant, "sessions:create")
|
|
2484
|
+
: undefined,
|
|
2485
|
+
);
|
|
2459
2486
|
// Every selected Variable Set is independently authorized. Scope does not
|
|
2460
2487
|
// affect precedence: explicit order is low-to-high and later sets win name
|
|
2461
2488
|
// collisions.
|
|
@@ -3016,6 +3043,46 @@ export async function createSessionForRequestWithOutcome(
|
|
|
3016
3043
|
model,
|
|
3017
3044
|
});
|
|
3018
3045
|
}
|
|
3046
|
+
const initialLearning =
|
|
3047
|
+
payload.agentLearning && Object.keys(payload.agentLearning).length
|
|
3048
|
+
? payload.agentLearning
|
|
3049
|
+
: null;
|
|
3050
|
+
const initialLearningContext =
|
|
3051
|
+
initialLearning && authorization
|
|
3052
|
+
? await knowledgeContextForAccess(deps, authorization, "sessions:control")
|
|
3053
|
+
: null;
|
|
3054
|
+
if (initialLearning && initialLearningContext?.actor.kind !== "human") {
|
|
3055
|
+
throw new HTTPException(403, {
|
|
3056
|
+
message: "Chat learning settings require authenticated human session control",
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
const initialLearningScope =
|
|
3060
|
+
effectiveVisibility === "user_private" ||
|
|
3061
|
+
sessionScope.memoryScope === "user" ||
|
|
3062
|
+
workspace.kind === "personal"
|
|
3063
|
+
? ("personal" as const)
|
|
3064
|
+
: ("workspace" as const);
|
|
3065
|
+
const initialLearningActor = initialLearningContext?.actor;
|
|
3066
|
+
const beforeCreateCommit =
|
|
3067
|
+
initialLearning && initialLearningContext && initialLearningActor?.kind === "human"
|
|
3068
|
+
? async (tx: Database, sessionId: string) => {
|
|
3069
|
+
await externalBeforeCreateCommit?.(tx);
|
|
3070
|
+
await saveAgentLearningSettings(
|
|
3071
|
+
tx,
|
|
3072
|
+
{
|
|
3073
|
+
...initialLearningContext,
|
|
3074
|
+
actor: { ...initialLearningActor, settingsScopes: [initialLearningScope] },
|
|
3075
|
+
},
|
|
3076
|
+
{
|
|
3077
|
+
scope: initialLearningScope,
|
|
3078
|
+
source: { kind: "chat", id: sessionId },
|
|
3079
|
+
operationId: sessionId,
|
|
3080
|
+
expectedVersion: 0,
|
|
3081
|
+
settings: initialLearning,
|
|
3082
|
+
},
|
|
3083
|
+
);
|
|
3084
|
+
}
|
|
3085
|
+
: externalBeforeCreateCommit;
|
|
3019
3086
|
let createOutcome: CreateSessionOutcome;
|
|
3020
3087
|
try {
|
|
3021
3088
|
createOutcome = await createAndStartSessionWithOutcome({
|
|
@@ -3050,7 +3117,7 @@ export async function createSessionForRequestWithOutcome(
|
|
|
3050
3117
|
...(effectiveSandboxOs ? { sandboxOs: effectiveSandboxOs } : {}),
|
|
3051
3118
|
sandboxGroupId,
|
|
3052
3119
|
metadata: creationMetadata ?? {},
|
|
3053
|
-
...(
|
|
3120
|
+
...(beforeCreateCommit ? { beforeCreateCommit } : {}),
|
|
3054
3121
|
selectedHostMcpDelegations: hostSelections,
|
|
3055
3122
|
...(captureSelectedHostAuthority || captureLinkedAuthority
|
|
3056
3123
|
? {
|
|
@@ -3098,6 +3165,7 @@ export async function createSessionForRequestWithOutcome(
|
|
|
3098
3165
|
parentSessionId,
|
|
3099
3166
|
createIdempotencyKey: payload.idempotencyKey ?? null,
|
|
3100
3167
|
selectedInstalledSkillIds,
|
|
3168
|
+
initialAgentLearning: payload.agentLearning,
|
|
3101
3169
|
maxNestedAgentDepthOverride: payload.maxNestedAgentDepth ?? null,
|
|
3102
3170
|
allowNestedAgentDepthIncrease: hasPermission(grant.permissions, "workspace:admin"),
|
|
3103
3171
|
subjectId: grant.subjectId,
|
|
@@ -3263,22 +3331,17 @@ function prepareSelectedHostTurnAuthority(
|
|
|
3263
3331
|
const delegation = await getHostMcpDelegation(tx, owner, selection.delegationId);
|
|
3264
3332
|
const binding = delegation ? await getHostMcpBinding(tx, owner, delegation.bindingId) : null;
|
|
3265
3333
|
const configured = configs.get(selection.serverId)!;
|
|
3266
|
-
const { hostBinding, ...connectionRef } = configured.connectionRef!;
|
|
3267
|
-
const definition = HostMcpBindingDefinition.safeParse({
|
|
3268
|
-
serverId: selection.serverId,
|
|
3269
|
-
destinationUrl: configured.url,
|
|
3270
|
-
connectionRef,
|
|
3271
|
-
});
|
|
3272
3334
|
if (
|
|
3273
3335
|
!delegation ||
|
|
3274
3336
|
!binding ||
|
|
3275
3337
|
delegation.status !== "active" ||
|
|
3276
3338
|
binding.status !== "active" ||
|
|
3277
|
-
!definition.success ||
|
|
3278
3339
|
delegation.generation !== selection.generation ||
|
|
3279
|
-
binding
|
|
3280
|
-
|
|
3281
|
-
|
|
3340
|
+
!hostMcpBindingMatchesSelection(binding, {
|
|
3341
|
+
serverId: selection.serverId,
|
|
3342
|
+
destinationUrl: configured.url!,
|
|
3343
|
+
connectionRef: configured.connectionRef!,
|
|
3344
|
+
})
|
|
3282
3345
|
)
|
|
3283
3346
|
throw new HTTPException(403, { message: "Host delegation selection changed" });
|
|
3284
3347
|
try {
|
|
@@ -3357,7 +3420,7 @@ function sessionPromptBoundaryRequestHash(input: {
|
|
|
3357
3420
|
* enqueue, and usage recording. `toolsProvided: false` durably preserves an
|
|
3358
3421
|
* Tool selection is durable session state and never rides a follow-up prompt.
|
|
3359
3422
|
*/
|
|
3360
|
-
|
|
3423
|
+
async function acceptSessionUserMessageInFileScope(
|
|
3361
3424
|
deps: AcceptSessionUserMessageDependencies,
|
|
3362
3425
|
grant: AccessGrant,
|
|
3363
3426
|
workspaceId: string,
|
|
@@ -3582,6 +3645,15 @@ export async function acceptSessionUserMessageWithOutcome(
|
|
|
3582
3645
|
workspaceId,
|
|
3583
3646
|
grant.subjectId,
|
|
3584
3647
|
requestedResources,
|
|
3648
|
+
(input.authorization || grant.principalKind === "agent_attempt") &&
|
|
3649
|
+
((await getSessionAuthorityProjection(db, workspaceId, sessionId))?.visibility ===
|
|
3650
|
+
"user_private" ||
|
|
3651
|
+
existingSession.memoryScope === "user" ||
|
|
3652
|
+
(await requireWorkspace(db, workspaceId)).kind === "personal")
|
|
3653
|
+
? input.authorization
|
|
3654
|
+
? await fileOwnerContextForAccess({ db }, input.authorization, "sessions:control")
|
|
3655
|
+
: await fileOwnerContextForAgent({ db }, grant, "sessions:control")
|
|
3656
|
+
: undefined,
|
|
3585
3657
|
);
|
|
3586
3658
|
await validateGitHubRepositorySelection(db, workspaceId, [
|
|
3587
3659
|
...existingSession.resources,
|
|
@@ -3634,7 +3706,7 @@ export async function acceptSessionUserMessageWithOutcome(
|
|
|
3634
3706
|
...(input.connectionAuthorities ? { authoritySelections: input.connectionAuthorities } : {}),
|
|
3635
3707
|
});
|
|
3636
3708
|
const captureSelectedHostAuthority = prepareSelectedHostTurnAuthority(
|
|
3637
|
-
runtimeSettings,
|
|
3709
|
+
settingsWithSessionMcpServerMetadata(runtimeSettings, existingSession.mcpServers),
|
|
3638
3710
|
existingSession.tools,
|
|
3639
3711
|
grant,
|
|
3640
3712
|
workspaceId,
|
|
@@ -4215,3 +4287,28 @@ function hasOwnProperty(value: unknown, key: string): boolean {
|
|
|
4215
4287
|
value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key),
|
|
4216
4288
|
);
|
|
4217
4289
|
}
|
|
4290
|
+
|
|
4291
|
+
/** Keep original-file ownership scoped across admission, history hydration and setup. */
|
|
4292
|
+
export async function createSessionForRequestWithOutcome(
|
|
4293
|
+
...args: Parameters<typeof createSessionForRequestInFileScope>
|
|
4294
|
+
): Promise<CreateSessionRequestOutcome> {
|
|
4295
|
+
const [deps, grant, , , authorization] = args;
|
|
4296
|
+
const actor = authorization
|
|
4297
|
+
? await fileOwnerContextForAccess(deps, authorization, "sessions:create")
|
|
4298
|
+
: grant.principalKind === "agent_attempt"
|
|
4299
|
+
? await fileOwnerContextForAgent(deps, grant, "sessions:create")
|
|
4300
|
+
: { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
4301
|
+
return withSessionRlsActorContext(actor, () => createSessionForRequestInFileScope(...args));
|
|
4302
|
+
}
|
|
4303
|
+
|
|
4304
|
+
export async function acceptSessionUserMessageWithOutcome(
|
|
4305
|
+
...args: Parameters<typeof acceptSessionUserMessageInFileScope>
|
|
4306
|
+
): ReturnType<typeof acceptSessionUserMessageInFileScope> {
|
|
4307
|
+
const [deps, grant, , , input] = args;
|
|
4308
|
+
const actor = input.authorization
|
|
4309
|
+
? await fileOwnerContextForAccess(deps, input.authorization, "sessions:control")
|
|
4310
|
+
: grant.principalKind === "agent_attempt"
|
|
4311
|
+
? await fileOwnerContextForAgent(deps, grant, "sessions:control")
|
|
4312
|
+
: { subjectId: grant.subjectId, privateFileOwnerSubjectId: null };
|
|
4313
|
+
return withSessionRlsActorContext(actor, () => acceptSessionUserMessageInFileScope(...args));
|
|
4314
|
+
}
|
package/src/domain/skills.ts
CHANGED
|
@@ -77,6 +77,14 @@ export async function approveSkill(db: Database, input: SkillRevisionInput) {
|
|
|
77
77
|
{ ...request, operation: "approve" },
|
|
78
78
|
);
|
|
79
79
|
}
|
|
80
|
+
export async function rejectSkill(db: Database, input: SkillRevisionInput) {
|
|
81
|
+
const { accountId, workspaceId, actor, ...request } = input;
|
|
82
|
+
return applySkillLifecycle(
|
|
83
|
+
db,
|
|
84
|
+
{ accountId, workspaceId, actor },
|
|
85
|
+
{ ...request, operation: "reject" },
|
|
86
|
+
);
|
|
87
|
+
}
|
|
80
88
|
export async function restoreSkill(db: Database, input: SkillRevisionInput) {
|
|
81
89
|
const { accountId, workspaceId, actor, ...request } = input;
|
|
82
90
|
return applySkillLifecycle(
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export * from "./domain/skills";
|
|
2
|
+
export * from "./domain/knowledge";
|
|
3
|
+
export * from "./domain/knowledge-search";
|
|
2
4
|
// @opengeni/core — the framework-agnostic OpenGeni core.
|
|
3
5
|
//
|
|
4
6
|
// WHAT THIS PACKAGE IS: the OpenGeni domain, access, and billing layers carved
|
|
@@ -63,6 +65,7 @@ export * from "./sandbox/runtime-settings";
|
|
|
63
65
|
export * from "./access";
|
|
64
66
|
export * from "./application/external-workspace-members";
|
|
65
67
|
export * from "./application/external-identity-lifecycle";
|
|
68
|
+
export * from "./application/host-mcp-resolvers";
|
|
66
69
|
export * from "./application/external-continuation";
|
|
67
70
|
export * from "./application/session-mcp-credential-rotation";
|
|
68
71
|
export * from "./application/external-link-work-admission";
|
|
@@ -102,10 +105,6 @@ export * from "./domain/governed-learning-slack-publication";
|
|
|
102
105
|
export * from "./domain/slack-publication-secret-safety";
|
|
103
106
|
export * from "./domain/company-profile-durable-learning-adapter";
|
|
104
107
|
export * from "./domain/company-profile-agent-admin";
|
|
105
|
-
export * from "./domain/company-brain-governed-writes";
|
|
106
|
-
export * from "./domain/governed-learning-evaluator";
|
|
107
|
-
export * from "./domain/governed-learning-activation";
|
|
108
|
-
export * from "./domain/remember";
|
|
109
108
|
export * from "./domain/slack-bot";
|
|
110
109
|
export * from "./domain/conversation-integrations";
|
|
111
110
|
export * from "./domain/fiken";
|
|
@@ -126,3 +125,9 @@ export * from "./editable-artifact-live";
|
|
|
126
125
|
// Transport-neutral editable-artifact domain service, ports, and contracts.
|
|
127
126
|
export * from "./editable-artifacts";
|
|
128
127
|
export { withSiteSessionOrigin } from "./site-session-origin";
|
|
128
|
+
|
|
129
|
+
export { fileOwnerContextForAccess, fileOwnerContextForAgent } from "./domain/file-owner";
|
|
130
|
+
|
|
131
|
+
export { prepareKnowledgeFile } from "./domain/knowledge-files";
|
|
132
|
+
|
|
133
|
+
export { retainKnowledgeMessage } from "./domain/knowledge-messages";
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import type { Settings } from "@opengeni/config";
|
|
2
|
+
import { environmentsEncryptionKeyBytes } from "@opengeni/config";
|
|
3
|
+
import {
|
|
4
|
+
resolveHostMcpResolverRoute,
|
|
5
|
+
hostMcpResolverRouteIsCurrent,
|
|
6
|
+
type Database,
|
|
7
|
+
type HostMcpResolverRoute,
|
|
8
|
+
} from "@opengeni/db";
|
|
2
9
|
import {
|
|
3
10
|
McpConnectionResourceScope,
|
|
11
|
+
hostMcpCredentialUseGuard,
|
|
4
12
|
type ConnectionCredentialsPort,
|
|
5
13
|
type McpCredentialsRequest,
|
|
6
14
|
type McpCredentialResolution,
|
|
@@ -144,11 +152,18 @@ export function createRemoteMcpCredentialsPort(
|
|
|
144
152
|
"hostMcpCredentialResolversJson" | "environment" | "integrationsAllowPrivateNetworkTargets"
|
|
145
153
|
>,
|
|
146
154
|
transport: typeof pinnedFetch = pinnedFetch,
|
|
155
|
+
routes?: {
|
|
156
|
+
resolve: (input: { accountId: string; workspaceId: string }) => Promise<HostMcpResolverRoute>;
|
|
157
|
+
isCurrent: (
|
|
158
|
+
input: { accountId: string; workspaceId: string },
|
|
159
|
+
route: HostMcpResolverRoute,
|
|
160
|
+
) => Promise<boolean>;
|
|
161
|
+
},
|
|
147
162
|
): ConnectionCredentialsPort {
|
|
148
|
-
if (!settings.hostMcpCredentialResolversJson) return {};
|
|
163
|
+
if (!settings.hostMcpCredentialResolversJson && !routes) return {};
|
|
149
164
|
let entries: z.infer<typeof configuration>;
|
|
150
165
|
try {
|
|
151
|
-
entries = configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson));
|
|
166
|
+
entries = configuration.parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]"));
|
|
152
167
|
for (const entry of entries) validateHttpUrl(entry.url);
|
|
153
168
|
if (new Set(entries.map((entry) => entry.accountId)).size !== entries.length) throw new Error();
|
|
154
169
|
} catch {
|
|
@@ -188,15 +203,39 @@ export function createRemoteMcpCredentialsPort(
|
|
|
188
203
|
: {}),
|
|
189
204
|
reason,
|
|
190
205
|
});
|
|
191
|
-
|
|
206
|
+
let route: HostMcpResolverRoute = { mode: "legacy" };
|
|
207
|
+
try {
|
|
208
|
+
if (routes) route = await routes.resolve(request);
|
|
209
|
+
} catch {
|
|
210
|
+
return unavailable("refresh_failed");
|
|
211
|
+
}
|
|
212
|
+
if (route.mode === "denied") return unavailable("unsupported_auth");
|
|
213
|
+
const config = route.mode === "namespace" ? route : byAccount.get(request.accountId);
|
|
192
214
|
if (!config || request.connectionRef.authoritySource !== "host")
|
|
193
215
|
return unavailable("unsupported_auth");
|
|
216
|
+
const current = async () => {
|
|
217
|
+
try {
|
|
218
|
+
return routes ? await routes.isCurrent(request, route) : true;
|
|
219
|
+
} catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
const finish = async (value: RemoteResolution): Promise<RemoteResolution> => {
|
|
224
|
+
if (!(await current())) return unavailable("refresh_failed");
|
|
225
|
+
const result = structuredClone(value);
|
|
226
|
+
if (result.status === "ok" && routes) result[hostMcpCredentialUseGuard] = current;
|
|
227
|
+
return result;
|
|
228
|
+
};
|
|
194
229
|
// Snapshot before any asynchronous operation; never retain mutable caller
|
|
195
230
|
// objects as the authority for a delayed response.
|
|
196
231
|
if (new TextEncoder().encode(serialized).byteLength > 65_536)
|
|
197
232
|
return unavailable("refresh_failed");
|
|
198
|
-
const
|
|
199
|
-
|
|
233
|
+
const activeKey = JSON.stringify([
|
|
234
|
+
route.mode === "namespace" ? [route.id, route.generation] : "legacy",
|
|
235
|
+
serialized,
|
|
236
|
+
]);
|
|
237
|
+
const pending = active.get(activeKey);
|
|
238
|
+
if (pending) return finish(await pending);
|
|
200
239
|
if (physicalRequests >= 128) return unavailable("refresh_failed");
|
|
201
240
|
const run = async (): Promise<RemoteResolution> => {
|
|
202
241
|
const requestId = crypto.randomUUID();
|
|
@@ -213,6 +252,7 @@ export function createRemoteMcpCredentialsPort(
|
|
|
213
252
|
return await Promise.race([
|
|
214
253
|
deadline,
|
|
215
254
|
(async () => {
|
|
255
|
+
if (!(await current())) return unavailable("refresh_failed");
|
|
216
256
|
const response = await transport(
|
|
217
257
|
config.url,
|
|
218
258
|
{
|
|
@@ -270,11 +310,11 @@ export function createRemoteMcpCredentialsPort(
|
|
|
270
310
|
}
|
|
271
311
|
};
|
|
272
312
|
const task = run();
|
|
273
|
-
active.set(
|
|
313
|
+
active.set(activeKey, task);
|
|
274
314
|
try {
|
|
275
|
-
return
|
|
315
|
+
return finish(await task);
|
|
276
316
|
} finally {
|
|
277
|
-
if (active.get(
|
|
317
|
+
if (active.get(activeKey) === task) active.delete(activeKey);
|
|
278
318
|
}
|
|
279
319
|
};
|
|
280
320
|
return {
|
|
@@ -291,3 +331,31 @@ export function createRemoteMcpCredentialsPort(
|
|
|
291
331
|
},
|
|
292
332
|
};
|
|
293
333
|
}
|
|
334
|
+
|
|
335
|
+
/** Native standalone transport; the database remains authoritative on every
|
|
336
|
+
* resolution/use. Embedded in-process ports retain their existing precedence. */
|
|
337
|
+
export function createNativeRemoteMcpCredentialsPort(
|
|
338
|
+
settings: Settings,
|
|
339
|
+
db: Database,
|
|
340
|
+
transport: typeof pinnedFetch = pinnedFetch,
|
|
341
|
+
): ConnectionCredentialsPort {
|
|
342
|
+
return createRemoteMcpCredentialsPort(settings, transport, {
|
|
343
|
+
resolve: (request) =>
|
|
344
|
+
resolveHostMcpResolverRoute(db, request, environmentsEncryptionKeyBytes(settings)),
|
|
345
|
+
isCurrent: (request, route) => hostMcpResolverRouteIsCurrent(db, request, route),
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** Parses only server configuration; never return parser errors containing secrets. */
|
|
350
|
+
export function hasLegacyHostMcpResolver(
|
|
351
|
+
settings: Pick<Settings, "hostMcpCredentialResolversJson">,
|
|
352
|
+
accountId: string,
|
|
353
|
+
): boolean {
|
|
354
|
+
try {
|
|
355
|
+
return configuration
|
|
356
|
+
.parse(JSON.parse(settings.hostMcpCredentialResolversJson || "[]"))
|
|
357
|
+
.some((entry) => entry.accountId === accountId);
|
|
358
|
+
} catch {
|
|
359
|
+
throw new Error("Invalid host MCP credential resolver configuration");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { type CompanyBrainGovernedWriteReceipt as CompanyBrainGovernedWriteReceiptType, type CompanyBrainLearningPolicyRouteReceipt as CompanyBrainLearningPolicyRouteReceiptType, type GovernedLearningActivationDestination, type GovernedLearningActivationReceipt } from "@opengeni/contracts";
|
|
2
|
-
import { type Database, activateGovernedLearningDecision, evaluateGovernedLearningProposal, getOrCreateWorkspaceLearningPolicySnapshot, writeCompanyBrainGovernedProposal } from "@opengeni/db";
|
|
3
|
-
import { type GovernedLearningSlackPublicationResult } from "./governed-learning-slack-publication.js";
|
|
4
|
-
export type CompanyBrainGovernedWriteInput = {
|
|
5
|
-
attempt: unknown;
|
|
6
|
-
request: unknown;
|
|
7
|
-
};
|
|
8
|
-
export type CompanyBrainGovernedWriteRouterOptions = {
|
|
9
|
-
db: Database;
|
|
10
|
-
authority?: typeof writeCompanyBrainGovernedProposal;
|
|
11
|
-
learningPolicySnapshot?: typeof getOrCreateWorkspaceLearningPolicySnapshot;
|
|
12
|
-
/** Governed-learning evaluator (migration 0268). Defaults to the DB capability. */
|
|
13
|
-
evaluate?: typeof evaluateGovernedLearningProposal;
|
|
14
|
-
/** Governed-learning activation controller (migration 0269). Defaults to the DB capability. */
|
|
15
|
-
activate?: typeof activateGovernedLearningDecision;
|
|
16
|
-
/**
|
|
17
|
-
* Destinations the router may activate automatically from a final eligible
|
|
18
|
-
* decision. Defaults to Skills and instruction policy. Both still pass
|
|
19
|
-
* through the evaluator and destination-owned activation lifecycle.
|
|
20
|
-
*/
|
|
21
|
-
automaticDestinations?: ReadonlyArray<GovernedLearningActivationDestination>;
|
|
22
|
-
/**
|
|
23
|
-
* Optional post-activation notification sink (Slack publication outbox).
|
|
24
|
-
* Notification is never authority: failures are swallowed after the
|
|
25
|
-
* activation receipt is durable and never change the route receipt.
|
|
26
|
-
*/
|
|
27
|
-
notifyActivation?: (input: {
|
|
28
|
-
db: Database;
|
|
29
|
-
receipt: GovernedLearningActivationReceipt;
|
|
30
|
-
sessionId: string;
|
|
31
|
-
attemptId: string;
|
|
32
|
-
}) => Promise<GovernedLearningSlackPublicationResult>;
|
|
33
|
-
};
|
|
34
|
-
export declare const DEFAULT_AUTOMATIC_LEARNING_DESTINATIONS: ReadonlyArray<GovernedLearningActivationDestination>;
|
|
35
|
-
/**
|
|
36
|
-
* Start a non-authoritative post-activation notification without making the
|
|
37
|
-
* durable activation receipt wait for its settlement. The callback is invoked
|
|
38
|
-
* synchronously so immediate enqueue work begins before the router returns;
|
|
39
|
-
* both synchronous throws and later promise rejections are contained.
|
|
40
|
-
*
|
|
41
|
-
* Exact retries intentionally dispatch again: the publication sink owns an
|
|
42
|
-
* activation-receipt idempotency key, while the activation receipt remains the
|
|
43
|
-
* caller-facing source of truth even if notification delivery stalls forever.
|
|
44
|
-
*/
|
|
45
|
-
export declare function dispatchBestEffortGovernedLearningNotification(notify: () => Promise<unknown>): void;
|
|
46
|
-
/**
|
|
47
|
-
* Transport-neutral facade for explicit governed Company Brain proposals.
|
|
48
|
-
* It intentionally exposes no generic remember call, selector, activation,
|
|
49
|
-
* rollback token, or personal/organization destination.
|
|
50
|
-
*/
|
|
51
|
-
export declare function createCompanyBrainGovernedWriteRouter(options: CompanyBrainGovernedWriteRouterOptions): {
|
|
52
|
-
write: (input: CompanyBrainGovernedWriteInput) => Promise<CompanyBrainGovernedWriteReceiptType>;
|
|
53
|
-
};
|
|
54
|
-
/**
|
|
55
|
-
* Deterministic UUIDv5-shaped operation id derived from the caller's proposal
|
|
56
|
-
* operation id, so an exact retry of the same write converges on the same
|
|
57
|
-
* evaluator/activation receipts instead of conflicting.
|
|
58
|
-
*/
|
|
59
|
-
export declare function derivedGovernedLearningOperationId(operationId: string, stage: "evaluation" | "activation"): string;
|
|
60
|
-
/**
|
|
61
|
-
* Resolve one derived Company Brain write from the immutable policy snapshot
|
|
62
|
-
* frozen for the exact accepted attempt. The evidence identity is the policy
|
|
63
|
-
* source identity; callers cannot select another override key to widen the
|
|
64
|
-
* decision.
|
|
65
|
-
*
|
|
66
|
-
* After the proposal commits, a Ways-of-working proposal (instruction policy or
|
|
67
|
-
* preference, i.e. one that materialized a `knowledge_change_proposals` row) is
|
|
68
|
-
* evaluated by the governed-learning evaluator against the same accepted
|
|
69
|
-
* snapshot. `suggest` records the content-free decision receipt only. Under
|
|
70
|
-
* `automatic`, a final `automaticEligible` receipt is handed to the activation
|
|
71
|
-
* controller, which revalidates current authority and applies the change only
|
|
72
|
-
* through the destination-owned lifecycle. Eligible Skills and instruction
|
|
73
|
-
* policies may activate automatically. Evaluation or activation failure
|
|
74
|
-
* never rolls back the durable proposal; it is reported as a bounded
|
|
75
|
-
* `learningFailure` and the proposal remains for human review.
|
|
76
|
-
*/
|
|
77
|
-
export declare function createCompanyBrainLearningPolicyRouter(options: CompanyBrainGovernedWriteRouterOptions): {
|
|
78
|
-
write: (input: CompanyBrainGovernedWriteInput) => Promise<CompanyBrainLearningPolicyRouteReceiptType>;
|
|
79
|
-
};
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { type GovernedLearningActivationReceipt, type GovernedLearningActivationUndoReceipt } from "@opengeni/contracts";
|
|
2
|
-
import { activateGovernedLearningDecision, undoGovernedLearningActivation, type Database } from "@opengeni/db";
|
|
3
|
-
export declare function createGovernedLearningActivationController(options: {
|
|
4
|
-
db: Database;
|
|
5
|
-
activate?: typeof activateGovernedLearningDecision;
|
|
6
|
-
undo?: typeof undoGovernedLearningActivation;
|
|
7
|
-
}): {
|
|
8
|
-
activate(input: {
|
|
9
|
-
caller: unknown;
|
|
10
|
-
request: unknown;
|
|
11
|
-
}): Promise<GovernedLearningActivationReceipt>;
|
|
12
|
-
undo(input: {
|
|
13
|
-
caller: unknown;
|
|
14
|
-
request: unknown;
|
|
15
|
-
}): Promise<GovernedLearningActivationUndoReceipt>;
|
|
16
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { type GovernedLearningDecision as GovernedLearningDecisionType, type GovernedLearningDecisionFacts as GovernedLearningDecisionFactsType } from "@opengeni/contracts";
|
|
2
|
-
/**
|
|
3
|
-
* Pure, closed evaluator mirrored by the 0268 database authority. It never
|
|
4
|
-
* receives source content and cannot activate a destination authority.
|
|
5
|
-
*/
|
|
6
|
-
export declare function deriveGovernedLearningDecision(input: GovernedLearningDecisionFactsType): GovernedLearningDecisionType;
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { type RememberLane, type GovernedLearningActivationReceipt, type RememberConfirmReceipt as RememberConfirmReceiptType, type RememberReceipt as RememberReceiptType } from "@opengeni/contracts";
|
|
2
|
-
import { type Database, activateHumanConfirmedLearningDecision, archiveTaskNote, confirmRememberKnowledgeClaim, createTaskNote, getWorkspaceInstructionPolicyBaseline, getWorkspaceKnowledgeChangeProposalSummary, getWorkspaceKnowledgeClaimInitiatingHuman, materializeConfirmedRememberKnowledgeMemory, rebaselineWorkspaceInstructionPolicyKnowledgeProposal } from "@opengeni/db";
|
|
3
|
-
import { createCompanyBrainLearningPolicyRouter } from "./company-brain-governed-writes.js";
|
|
4
|
-
export declare class RememberError extends Error {
|
|
5
|
-
readonly code: "proposal_unavailable" | "proposal_not_confirmable" | "human_confirmation_unavailable" | "preference_retired" | "baseline_stale";
|
|
6
|
-
readonly name = "RememberError";
|
|
7
|
-
constructor(code: "proposal_unavailable" | "proposal_not_confirmable" | "human_confirmation_unavailable" | "preference_retired" | "baseline_stale", message: string);
|
|
8
|
-
}
|
|
9
|
-
export type RememberRouterOptions = {
|
|
10
|
-
db: Database;
|
|
11
|
-
learningRouter?: Pick<ReturnType<typeof createCompanyBrainLearningPolicyRouter>, "write">;
|
|
12
|
-
createNote?: typeof createTaskNote;
|
|
13
|
-
archiveNote?: typeof archiveTaskNote;
|
|
14
|
-
rebaselineProposal?: typeof rebaselineWorkspaceInstructionPolicyKnowledgeProposal;
|
|
15
|
-
activateHumanConfirmed?: typeof activateHumanConfirmedLearningDecision;
|
|
16
|
-
confirmKnowledgeClaim?: typeof confirmRememberKnowledgeClaim;
|
|
17
|
-
materializeKnowledgeMemory?: typeof materializeConfirmedRememberKnowledgeMemory;
|
|
18
|
-
proposalSummary?: typeof getWorkspaceKnowledgeChangeProposalSummary;
|
|
19
|
-
claimInitiatingHuman?: typeof getWorkspaceKnowledgeClaimInitiatingHuman;
|
|
20
|
-
instructionPolicyBaseline?: typeof getWorkspaceInstructionPolicyBaseline;
|
|
21
|
-
notifyActivation?: (input: {
|
|
22
|
-
db: Database;
|
|
23
|
-
receipt: GovernedLearningActivationReceipt;
|
|
24
|
-
sessionId: string;
|
|
25
|
-
attemptId: string;
|
|
26
|
-
}) => Promise<unknown>;
|
|
27
|
-
};
|
|
28
|
-
/** Deterministic UUID-shaped id derived from the caller's remember operation id. */
|
|
29
|
-
export declare function derivedRememberOperationId(operationId: string, stage: "note" | "note-archive" | "promotion" | "evaluation" | "activation" | "rebaseline"): string;
|
|
30
|
-
/**
|
|
31
|
-
* What saving this costs, shown on the confirmation card so a human can judge
|
|
32
|
-
* the length before agreeing. A mandatory rule is composed into the prompt of
|
|
33
|
-
* every session it applies to; a preference contributes only its short
|
|
34
|
-
* descriptor to that prompt and keeps its content behind on-demand retrieval;
|
|
35
|
-
* knowledge is retrieval evidence and never joins the always-composed prefix.
|
|
36
|
-
*
|
|
37
|
-
* `HumanInputForm` renders a single question's `label` as the card heading and
|
|
38
|
-
* its `prompt` as the sub-text, so this stays a title with a parenthetical
|
|
39
|
-
* rather than a sentence: the question the human answers has to keep reading as
|
|
40
|
-
* the heading of the card.
|
|
41
|
-
*
|
|
42
|
-
* This deliberately lives on `label` rather than `helpText`: migrations 0272 /
|
|
43
|
-
* 0274 / 0284 / 0293 / 0316 byte-verify the reconstructed `prompt`, `helpText`,
|
|
44
|
-
* and `options` against the exact Task-note text before authorizing an
|
|
45
|
-
* activation, and `label` is the one field of the canonical question those
|
|
46
|
-
* capabilities do not constrain.
|
|
47
|
-
*/
|
|
48
|
-
export declare function rememberConfirmationLabel(input: {
|
|
49
|
-
lane: RememberLane;
|
|
50
|
-
contentChars: number;
|
|
51
|
-
/** Role-scoped rules compose only for sessions bound to that role. */
|
|
52
|
-
policyScope?: "global" | "role" | undefined;
|
|
53
|
-
}): string;
|
|
54
|
-
/**
|
|
55
|
-
* Explicit user-directed remember. Content becomes an exact task note (the
|
|
56
|
-
* evidence), the note is promoted through the frozen learning policy router,
|
|
57
|
-
* and the result is either an immediate activation (automatic policy), a
|
|
58
|
-
* proposal for the human Knowledge review lifecycle, or a durable proposal that
|
|
59
|
-
* still needs one bound human confirmation through `request_human_input`.
|
|
60
|
-
* A confirmed Knowledge claim is then materialized as a keyword-searchable
|
|
61
|
-
* Memory record from its exact approved Task-note text.
|
|
62
|
-
*/
|
|
63
|
-
export declare function createRememberRouter(options: RememberRouterOptions): {
|
|
64
|
-
remember: (input: {
|
|
65
|
-
attempt: unknown;
|
|
66
|
-
request: unknown;
|
|
67
|
-
}) => Promise<RememberReceiptType>;
|
|
68
|
-
confirm: (input: {
|
|
69
|
-
attempt: unknown;
|
|
70
|
-
request: unknown;
|
|
71
|
-
}) => Promise<RememberConfirmReceiptType>;
|
|
72
|
-
};
|