@opengeni/core 0.18.1 → 0.20.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/session-commands.d.ts +6 -0
- package/dist/dependencies.d.ts +4 -1
- package/dist/domain/sessions.d.ts +3 -0
- package/dist/index.js +52 -32
- package/dist/index.js.map +1 -1
- package/dist/sandbox/fleet.d.ts +2 -0
- package/package.json +10 -10
- package/src/application/session-commands.ts +5 -3
- package/src/dependencies.ts +4 -0
- package/src/domain/resources.ts +2 -1
- package/src/domain/sessions.ts +44 -27
- package/src/sandbox/fleet.ts +12 -2
package/dist/sandbox/fleet.d.ts
CHANGED
|
@@ -132,6 +132,8 @@ export type RunOnResult = {
|
|
|
132
132
|
target: string;
|
|
133
133
|
kind: string;
|
|
134
134
|
ok: boolean;
|
|
135
|
+
/** Display name of the target sandbox when known (from the sandboxes row). */
|
|
136
|
+
targetName?: string;
|
|
135
137
|
stdout?: string;
|
|
136
138
|
stderr?: string;
|
|
137
139
|
exitCode?: number | null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "OpenGeni framework-agnostic core: the domain, access, and billing layers (neutral access, off-HTTP V2 surface). Behavior-preserving extraction from apps/api — keeps Hono's HTTPException for error throwing (typed-errors cleanup deferred).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -34,15 +34,15 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
37
|
-
"@opengeni/codex": "^0.2.
|
|
38
|
-
"@opengeni/config": "^0.10.
|
|
39
|
-
"@opengeni/contracts": "^0.
|
|
40
|
-
"@opengeni/db": "^0.
|
|
41
|
-
"@opengeni/documents": "^0.2
|
|
42
|
-
"@opengeni/events": "^0.3.
|
|
43
|
-
"@opengeni/observability": "^0.4.
|
|
44
|
-
"@opengeni/runtime": "^0.
|
|
45
|
-
"@opengeni/storage": "^0.2.
|
|
37
|
+
"@opengeni/codex": "^0.2.10",
|
|
38
|
+
"@opengeni/config": "^0.10.6",
|
|
39
|
+
"@opengeni/contracts": "^0.35.0",
|
|
40
|
+
"@opengeni/db": "^0.26.0",
|
|
41
|
+
"@opengeni/documents": "^0.3.2",
|
|
42
|
+
"@opengeni/events": "^0.3.65",
|
|
43
|
+
"@opengeni/observability": "^0.4.9",
|
|
44
|
+
"@opengeni/runtime": "^0.18.3",
|
|
45
|
+
"@opengeni/storage": "^0.2.59",
|
|
46
46
|
"hono": "^4.12.18"
|
|
47
47
|
},
|
|
48
48
|
"engines": {
|
|
@@ -595,10 +595,12 @@ export async function controlHumanSessionWorkstream(
|
|
|
595
595
|
),
|
|
596
596
|
interruptionCount: result.interruptionCount,
|
|
597
597
|
wakeCount: result.wakeCount,
|
|
598
|
+
cancelledSessionCount: result.cancelledSessionCount,
|
|
599
|
+
cancelledTurnCount: result.cancelledTurnCount,
|
|
598
600
|
};
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
601
|
+
for (const affected of result.affectedSessionEvents) {
|
|
602
|
+
await publishSessionEventIds(deps, context.workspaceId, affected.sessionId, affected.eventIds);
|
|
603
|
+
}
|
|
602
604
|
await publishWorkspaceControlEvent(deps, context.workspaceId, result.workspaceControlEventId);
|
|
603
605
|
await requestControlWakeDispatch(deps, result.wakeCount);
|
|
604
606
|
return response;
|
package/src/dependencies.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { Settings } from "@opengeni/config";
|
|
|
2
2
|
import type {
|
|
3
3
|
ConnectionCredentialsPort,
|
|
4
4
|
Document,
|
|
5
|
+
DocumentAuthorityKind,
|
|
5
6
|
GitHubAppApiPort,
|
|
6
7
|
ScheduledTask,
|
|
7
8
|
SessionAuthorizationPort,
|
|
@@ -73,6 +74,9 @@ export type DocumentIndexClient = {
|
|
|
73
74
|
accountId: string;
|
|
74
75
|
workspaceId: string;
|
|
75
76
|
documentId: string;
|
|
77
|
+
authorityKind: DocumentAuthorityKind;
|
|
78
|
+
authorityWorkspaceId: string | null;
|
|
79
|
+
authoritySubjectId: string | null;
|
|
76
80
|
}) => Promise<Document | void>;
|
|
77
81
|
};
|
|
78
82
|
|
package/src/domain/resources.ts
CHANGED
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
normalizeRepositorySubpath,
|
|
9
9
|
normalizeResourceMountPath,
|
|
10
10
|
resourceIdentityKey,
|
|
11
|
+
resourceMountPath,
|
|
11
12
|
resourceMountPathCollisionKey,
|
|
12
13
|
ResourceRefConflictError,
|
|
13
14
|
ResourceMountPathError,
|
|
@@ -115,7 +116,7 @@ export function normalizeResources(resources: ResourceRef[]): ResourceRef[] {
|
|
|
115
116
|
for (const resource of resources) {
|
|
116
117
|
let normalized: ResourceRef;
|
|
117
118
|
if (resource.kind === "file") {
|
|
118
|
-
const mountPath = normalizeMountPath(resource
|
|
119
|
+
const mountPath = normalizeMountPath(resourceMountPath(resource));
|
|
119
120
|
normalized = {
|
|
120
121
|
kind: "file",
|
|
121
122
|
fileId: resource.fileId,
|
package/src/domain/sessions.ts
CHANGED
|
@@ -514,6 +514,8 @@ export async function createAndStartSession(input: {
|
|
|
514
514
|
accountId: string;
|
|
515
515
|
workspaceId: string;
|
|
516
516
|
initialMessage: string;
|
|
517
|
+
/** Create the session shell without an initial user event/agent turn. */
|
|
518
|
+
deferInitialTurn?: boolean;
|
|
517
519
|
turnInstructions?: string | null;
|
|
518
520
|
resources: ResourceRef[];
|
|
519
521
|
skills?: SessionSkill[];
|
|
@@ -546,6 +548,9 @@ export async function createAndStartSession(input: {
|
|
|
546
548
|
// workspace agentInstructions at turn time; never emitted as a timeline event.
|
|
547
549
|
// Null/omitted ⇒ the session carries none.
|
|
548
550
|
instructions?: string | null;
|
|
551
|
+
// Immutable normalized prompt-policy role. This never derives from a
|
|
552
|
+
// workspace membership role; null retains the bounded metadata.role fallback.
|
|
553
|
+
policyRole?: string | null;
|
|
549
554
|
// Validated against the creating grant before this is called.
|
|
550
555
|
firstPartyMcpPermissions?: Permission[] | null;
|
|
551
556
|
// Model-visible first-party tool names. Authorization remains controlled by
|
|
@@ -626,6 +631,7 @@ export async function createAndStartSession(input: {
|
|
|
626
631
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
627
632
|
firstPartyMcpTools: input.firstPartyMcpTools,
|
|
628
633
|
instructions: input.instructions ?? null,
|
|
634
|
+
policyRole: input.policyRole ?? null,
|
|
629
635
|
parentSessionId: input.parentSessionId ?? null,
|
|
630
636
|
createIdempotencyKey: input.createIdempotencyKey,
|
|
631
637
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
@@ -672,6 +678,7 @@ export async function createAndStartSession(input: {
|
|
|
672
678
|
firstPartyMcpPermissions: input.firstPartyMcpPermissions ?? null,
|
|
673
679
|
firstPartyMcpTools: input.firstPartyMcpTools,
|
|
674
680
|
instructions: input.instructions ?? null,
|
|
681
|
+
policyRole: input.policyRole ?? null,
|
|
675
682
|
parentSessionId: input.parentSessionId ?? null,
|
|
676
683
|
sandboxGroupId: input.sandboxGroupId ?? null,
|
|
677
684
|
...(input.sandboxOs ? { sandboxOs: input.sandboxOs } : {}),
|
|
@@ -702,6 +709,7 @@ async function finishStartSession(
|
|
|
702
709
|
bus: EventBus;
|
|
703
710
|
workflowClient: SessionWorkflowClient;
|
|
704
711
|
initialMessage: string;
|
|
712
|
+
deferInitialTurn?: boolean;
|
|
705
713
|
turnInstructions?: string | null;
|
|
706
714
|
resources: ResourceRef[];
|
|
707
715
|
tools: ToolRef[];
|
|
@@ -781,6 +789,7 @@ async function finishStartSession(
|
|
|
781
789
|
}
|
|
782
790
|
: null,
|
|
783
791
|
consumeNewSessionDraft: input.consumeNewSessionDraft ?? null,
|
|
792
|
+
deferInitialTurn: input.deferInitialTurn === true,
|
|
784
793
|
});
|
|
785
794
|
await publishDurableSessionEvents(input.bus, session.workspaceId, session.id, started.events);
|
|
786
795
|
if (started.workflowWakeRevision !== null) {
|
|
@@ -1255,9 +1264,10 @@ export async function createSessionForRequest(
|
|
|
1255
1264
|
payload.variableSetId,
|
|
1256
1265
|
)
|
|
1257
1266
|
: null;
|
|
1258
|
-
// RIG BINDING (M3). Resolve the rig this session rides —
|
|
1259
|
-
//
|
|
1260
|
-
// —
|
|
1267
|
+
// RIG BINDING (M3). Resolve the rig this session rides — a UUID binds that
|
|
1268
|
+
// rig, null explicitly opts out, and omission inherits the workspace default
|
|
1269
|
+
// (workspaces.default_rig_id) — then FREEZE both the rig id and its currently-
|
|
1270
|
+
// ACTIVE version onto the row.
|
|
1261
1271
|
// The session then rides that exact version for its whole life; a later
|
|
1262
1272
|
// promote never moves it. Rig-less (both null) when neither resolves, which is
|
|
1263
1273
|
// byte-for-byte today's behavior (zero extra work, zero row change).
|
|
@@ -1265,7 +1275,8 @@ export async function createSessionForRequest(
|
|
|
1265
1275
|
// - A stale workspace-default rig (deleted → FK-nulled, or somehow with no
|
|
1266
1276
|
// active version) degrades SILENTLY to rig-less: an operator-side default
|
|
1267
1277
|
// must never brick every create in the workspace.
|
|
1268
|
-
const requestedRigId =
|
|
1278
|
+
const requestedRigId =
|
|
1279
|
+
payload.rigId === undefined ? await getWorkspaceDefaultRigId(db, workspaceId) : payload.rigId;
|
|
1269
1280
|
let frozenRigId: string | null = null;
|
|
1270
1281
|
let frozenRigVersionId: string | null = null;
|
|
1271
1282
|
if (requestedRigId) {
|
|
@@ -1598,13 +1609,15 @@ export async function createSessionForRequest(
|
|
|
1598
1609
|
}
|
|
1599
1610
|
}
|
|
1600
1611
|
}
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1612
|
+
if (payload.startMode !== "realtime") {
|
|
1613
|
+
await requireLimit(deps, {
|
|
1614
|
+
accountId: grant.accountId,
|
|
1615
|
+
workspaceId,
|
|
1616
|
+
action: "agent_run:create",
|
|
1617
|
+
quantity: 1,
|
|
1618
|
+
model,
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1608
1621
|
const creationInitiator = creationInitiatorForGrant(grant);
|
|
1609
1622
|
let session: CreateSessionResponse;
|
|
1610
1623
|
try {
|
|
@@ -1615,7 +1628,8 @@ export async function createSessionForRequest(
|
|
|
1615
1628
|
workflowClient,
|
|
1616
1629
|
accountId: grant.accountId,
|
|
1617
1630
|
workspaceId,
|
|
1618
|
-
initialMessage: payload.initialMessage,
|
|
1631
|
+
initialMessage: payload.initialMessage ?? "",
|
|
1632
|
+
deferInitialTurn: payload.startMode === "realtime",
|
|
1619
1633
|
turnInstructions: payload.turnInstructions ?? null,
|
|
1620
1634
|
resources,
|
|
1621
1635
|
skills,
|
|
@@ -1651,6 +1665,7 @@ export async function createSessionForRequest(
|
|
|
1651
1665
|
// contracts schema). Persisted on the row; composed system-level at turn
|
|
1652
1666
|
// time. Not surfaced as an event.
|
|
1653
1667
|
instructions: payload.instructions ?? null,
|
|
1668
|
+
policyRole: payload.policyRole ?? null,
|
|
1654
1669
|
firstPartyMcpPermissions,
|
|
1655
1670
|
firstPartyMcpTools,
|
|
1656
1671
|
mcpServers: sessionMcpServers.dbServers,
|
|
@@ -1687,21 +1702,23 @@ export async function createSessionForRequest(
|
|
|
1687
1702
|
}
|
|
1688
1703
|
throw error;
|
|
1689
1704
|
}
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
+
if (payload.startMode !== "realtime") {
|
|
1706
|
+
await recordWorkspaceUsage(deps, {
|
|
1707
|
+
accountId: grant.accountId,
|
|
1708
|
+
workspaceId,
|
|
1709
|
+
subjectId: grant.subjectId,
|
|
1710
|
+
eventType: "agent_run.created",
|
|
1711
|
+
quantity: 1,
|
|
1712
|
+
unit: "run",
|
|
1713
|
+
sourceResourceType: "session",
|
|
1714
|
+
sourceResourceId: session.id,
|
|
1715
|
+
sessionId: session.id,
|
|
1716
|
+
initiator: session.createdBy,
|
|
1717
|
+
initiatorContext: session.createdByContext,
|
|
1718
|
+
origin: creationInitiator.actor ? "system" : "user",
|
|
1719
|
+
idempotencyKey: `agent_run.created:${workspaceId}:${session.id}`,
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1705
1722
|
return session;
|
|
1706
1723
|
}
|
|
1707
1724
|
|
package/src/sandbox/fleet.ts
CHANGED
|
@@ -510,6 +510,8 @@ export type RunOnResult = {
|
|
|
510
510
|
target: string;
|
|
511
511
|
kind: string;
|
|
512
512
|
ok: boolean;
|
|
513
|
+
/** Display name of the target sandbox when known (from the sandboxes row). */
|
|
514
|
+
targetName?: string;
|
|
513
515
|
stdout?: string;
|
|
514
516
|
stderr?: string;
|
|
515
517
|
exitCode?: number | null;
|
|
@@ -628,6 +630,7 @@ export async function runOnSandbox(
|
|
|
628
630
|
if (sandbox.kind !== "selfhosted" || !sandbox.enrollmentId) {
|
|
629
631
|
return {
|
|
630
632
|
target,
|
|
633
|
+
targetName: sandbox.name,
|
|
631
634
|
kind: op.kind,
|
|
632
635
|
ok: false,
|
|
633
636
|
reason: `run_on routes one-off ops to enrolled selfhosted machines; ${sandbox.kind} targets are reached via the active sandbox (swap to it first)`,
|
|
@@ -635,10 +638,16 @@ export async function runOnSandbox(
|
|
|
635
638
|
}
|
|
636
639
|
const enrollment = await getEnrollment(services.db, ctx.workspaceId, sandbox.enrollmentId);
|
|
637
640
|
if (!enrollment || enrollment.status !== "active") {
|
|
638
|
-
return {
|
|
641
|
+
return {
|
|
642
|
+
target,
|
|
643
|
+
targetName: sandbox.name,
|
|
644
|
+
kind: op.kind,
|
|
645
|
+
ok: false,
|
|
646
|
+
reason: `sandbox ${target} is not enrolled/active`,
|
|
647
|
+
};
|
|
639
648
|
}
|
|
640
649
|
|
|
641
|
-
|
|
650
|
+
const result = await executeRunOnSelfhostedMachine(
|
|
642
651
|
{
|
|
643
652
|
workspaceId: ctx.workspaceId,
|
|
644
653
|
agentId: sandbox.enrollmentId,
|
|
@@ -650,6 +659,7 @@ export async function runOnSandbox(
|
|
|
650
659
|
target,
|
|
651
660
|
op,
|
|
652
661
|
);
|
|
662
|
+
return { ...result, targetName: sandbox.name };
|
|
653
663
|
}
|
|
654
664
|
|
|
655
665
|
export type ProvisionResult =
|