@opengeni/core 0.21.10 → 0.24.1
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/access/index.d.ts +1 -1
- package/dist/application/new-session-drafts.d.ts +1 -1
- package/dist/application/session-commands.d.ts +2 -2
- package/dist/billing/limits.d.ts +1 -1
- package/dist/chunk-6WKPWE5S.js +2380 -0
- package/dist/chunk-6WKPWE5S.js.map +1 -0
- package/dist/chunk-JJU6I5XD.js +2713 -0
- package/dist/chunk-JJU6I5XD.js.map +1 -0
- package/dist/chunk-NYPMQ7NO.js +2270 -0
- package/dist/chunk-NYPMQ7NO.js.map +1 -0
- package/dist/dependencies.d.ts +26 -6
- package/dist/domain/capabilities.d.ts +28 -3
- package/dist/domain/company-profile-durable-learning-adapter.d.ts +39 -0
- package/dist/domain/durable-learning-slack-publication.d.ts +72 -0
- package/dist/domain/editable-artifacts/agent-application.d.ts +192 -0
- package/dist/domain/editable-artifacts/durable-export-postgres.d.ts +4 -0
- package/dist/domain/editable-artifacts/durable-export.d.ts +212 -0
- package/dist/domain/editable-artifacts/errors.d.ts +47 -0
- package/dist/domain/editable-artifacts/hash.d.ts +11 -0
- package/dist/domain/editable-artifacts/in-memory.d.ts +99 -0
- package/dist/domain/editable-artifacts/index.d.ts +14 -0
- package/dist/domain/editable-artifacts/ports.d.ts +341 -0
- package/dist/domain/editable-artifacts/postgres-adapters.d.ts +13 -0
- package/dist/domain/editable-artifacts/service.d.ts +105 -0
- package/dist/domain/editable-artifacts/snapshot-compaction.d.ts +44 -0
- package/dist/domain/editable-artifacts/snapshot-verifier-genesis.d.ts +50 -0
- package/dist/domain/editable-artifacts/snapshot-verifier-materialization.d.ts +21 -0
- package/dist/domain/editable-artifacts/snapshot-verifier.d.ts +118 -0
- package/dist/domain/editable-artifacts/types.d.ts +410 -0
- package/dist/domain/memory-slack-delivery.d.ts +19 -0
- package/dist/domain/packs.d.ts +29 -1
- package/dist/domain/personal-connection-delegations.d.ts +9 -1
- package/dist/domain/scheduled-tasks.d.ts +2 -2
- package/dist/domain/session-tool-policy.d.ts +2 -2
- package/dist/domain/sessions.d.ts +14 -6
- package/dist/domain/skill-imports.d.ts +32 -0
- package/dist/domain/slack-publication-secret-safety.d.ts +8 -0
- package/dist/domain/timeline-annotations.d.ts +5 -0
- package/dist/domain/video-generation-capabilities.d.ts +9 -0
- package/dist/domain/video-generation.d.ts +47 -0
- package/dist/editable-artifact-live/application.d.ts +69 -0
- package/dist/editable-artifact-live/errors.d.ts +1 -0
- package/dist/editable-artifact-live/index.d.ts +8 -0
- package/dist/editable-artifact-live/outbox-dispatcher.d.ts +162 -0
- package/dist/editable-artifact-live/ports.d.ts +100 -0
- package/dist/editable-artifact-live/server.d.ts +71 -0
- package/dist/editable-artifact-live/ticket.d.ts +40 -0
- package/dist/editable-artifact-live/types.d.ts +213 -0
- package/dist/editable-artifact-live/wire.d.ts +34 -0
- package/dist/editable-artifact-live.d.ts +2 -0
- package/dist/editable-artifact-live.js +58 -0
- package/dist/editable-artifact-live.js.map +1 -0
- package/dist/editable-artifacts.d.ts +2 -0
- package/dist/editable-artifacts.js +179 -0
- package/dist/editable-artifacts.js.map +1 -0
- package/dist/index.d.ts +35 -26
- package/dist/index.js +2792 -609
- package/dist/index.js.map +1 -1
- package/dist/managed-session.d.ts +1 -1
- package/dist/rigs/index.d.ts +1 -1
- package/dist/rigs/provider-images.d.ts +31 -0
- package/dist/sandbox/routing.d.ts +1 -0
- package/dist/session-authorization.d.ts +1 -1
- package/dist/workflow-wake-contract.d.ts +7 -0
- package/package.json +18 -10
- package/src/application/new-session-drafts.ts +2 -0
- package/src/application/session-commands.ts +188 -107
- package/src/dependencies.ts +30 -2
- package/src/domain/capabilities.ts +604 -220
- package/src/domain/company-profile-durable-learning-adapter.ts +221 -0
- package/src/domain/durable-learning-slack-publication.ts +202 -0
- package/src/domain/editable-artifacts/agent-application.ts +687 -0
- package/src/domain/editable-artifacts/durable-export-postgres.ts +139 -0
- package/src/domain/editable-artifacts/durable-export.ts +734 -0
- package/src/domain/editable-artifacts/errors.ts +115 -0
- package/src/domain/editable-artifacts/hash.ts +131 -0
- package/src/domain/editable-artifacts/in-memory.ts +1662 -0
- package/src/domain/editable-artifacts/index.ts +14 -0
- package/src/domain/editable-artifacts/ports.ts +462 -0
- package/src/domain/editable-artifacts/postgres-adapters.ts +49 -0
- package/src/domain/editable-artifacts/service.ts +2402 -0
- package/src/domain/editable-artifacts/snapshot-compaction.ts +246 -0
- package/src/domain/editable-artifacts/snapshot-verifier-genesis.ts +235 -0
- package/src/domain/editable-artifacts/snapshot-verifier-materialization.ts +74 -0
- package/src/domain/editable-artifacts/snapshot-verifier.ts +687 -0
- package/src/domain/editable-artifacts/types.ts +835 -0
- package/src/domain/insights.ts +136 -33
- package/src/domain/memory-slack-delivery.ts +204 -0
- package/src/domain/memory-slack-publication.ts +5 -2
- package/src/domain/packs.ts +266 -5
- package/src/domain/personal-connection-delegations.ts +97 -6
- package/src/domain/scheduled-tasks.ts +155 -29
- package/src/domain/session-tool-policy.ts +8 -2
- package/src/domain/sessions.ts +274 -131
- package/src/domain/skill-imports.ts +350 -0
- package/src/domain/slack-publication-secret-safety.ts +42 -0
- package/src/domain/timeline-annotations.ts +204 -0
- package/src/domain/video-generation-capabilities.ts +69 -0
- package/src/domain/video-generation.ts +249 -0
- package/src/editable-artifact-live/application.ts +182 -0
- package/src/editable-artifact-live/errors.ts +4 -0
- package/src/editable-artifact-live/index.ts +8 -0
- package/src/editable-artifact-live/outbox-dispatcher.ts +916 -0
- package/src/editable-artifact-live/ports.ts +139 -0
- package/src/editable-artifact-live/server.ts +1707 -0
- package/src/editable-artifact-live/ticket.ts +217 -0
- package/src/editable-artifact-live/types.ts +286 -0
- package/src/editable-artifact-live/wire.ts +95 -0
- package/src/editable-artifact-live.ts +2 -0
- package/src/editable-artifacts.ts +2 -0
- package/src/index.ts +13 -0
- package/src/rigs/index.ts +26 -19
- package/src/rigs/provider-images.ts +110 -0
- package/src/sandbox/routing.ts +6 -3
- package/src/session-authorization.ts +3 -0
- package/src/workflow-wake-contract.ts +8 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import {
|
|
2
|
+
GenerateVideoToolInput,
|
|
3
|
+
VideoGenerationAspectRatio,
|
|
4
|
+
VideoGenerationResolution,
|
|
5
|
+
VideoGenerationSourceMode,
|
|
6
|
+
type GenerateVideoToolInput as GenerateVideoToolInputType,
|
|
7
|
+
type VideoGenerationFundingSource,
|
|
8
|
+
type VideoGenerationModelCapability,
|
|
9
|
+
} from "@opengeni/contracts";
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
|
|
12
|
+
export const VIDEO_GENERATION_ADAPTER_VERSION = "gateway-video-v4/1" as const;
|
|
13
|
+
|
|
14
|
+
export type SealedVideoReferenceRole =
|
|
15
|
+
| "first_frame"
|
|
16
|
+
| "last_frame"
|
|
17
|
+
| "image_reference"
|
|
18
|
+
| "video_reference";
|
|
19
|
+
|
|
20
|
+
export type SealedVideoReference = Readonly<{
|
|
21
|
+
role: SealedVideoReferenceRole;
|
|
22
|
+
contentSha256: string;
|
|
23
|
+
contentType: string;
|
|
24
|
+
byteSize: number;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
export type CanonicalVideoGenerationRequest = Readonly<{
|
|
28
|
+
schemaVersion: 1;
|
|
29
|
+
modelId: string;
|
|
30
|
+
prompt: string;
|
|
31
|
+
sourceMode: VideoGenerationSourceMode;
|
|
32
|
+
references: readonly SealedVideoReference[];
|
|
33
|
+
durationSeconds: number;
|
|
34
|
+
aspectRatio: VideoGenerationAspectRatio;
|
|
35
|
+
resolution: VideoGenerationResolution;
|
|
36
|
+
generateAudio: boolean;
|
|
37
|
+
}>;
|
|
38
|
+
|
|
39
|
+
export type VideoGenerationOperationState =
|
|
40
|
+
| "preparing"
|
|
41
|
+
| "prepared"
|
|
42
|
+
| "accepted"
|
|
43
|
+
| "submission_uncertain"
|
|
44
|
+
| "provider_started"
|
|
45
|
+
| "retaining"
|
|
46
|
+
| "completed"
|
|
47
|
+
| "provider_failed"
|
|
48
|
+
| "cancelled_before_submit"
|
|
49
|
+
| "outcome_unknown"
|
|
50
|
+
| "retention_failed";
|
|
51
|
+
|
|
52
|
+
const TERMINAL_STATES = new Set<VideoGenerationOperationState>([
|
|
53
|
+
"completed",
|
|
54
|
+
"provider_failed",
|
|
55
|
+
"cancelled_before_submit",
|
|
56
|
+
"outcome_unknown",
|
|
57
|
+
"retention_failed",
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
const ALLOWED_TRANSITIONS: Readonly<
|
|
61
|
+
Record<VideoGenerationOperationState, readonly VideoGenerationOperationState[]>
|
|
62
|
+
> = Object.freeze({
|
|
63
|
+
preparing: ["prepared", "cancelled_before_submit"],
|
|
64
|
+
prepared: ["accepted", "cancelled_before_submit"],
|
|
65
|
+
accepted: ["submission_uncertain", "provider_started", "cancelled_before_submit"],
|
|
66
|
+
submission_uncertain: ["provider_started", "outcome_unknown"],
|
|
67
|
+
provider_started: ["retaining", "provider_failed", "outcome_unknown"],
|
|
68
|
+
retaining: ["completed", "retention_failed"],
|
|
69
|
+
completed: [],
|
|
70
|
+
provider_failed: [],
|
|
71
|
+
cancelled_before_submit: [],
|
|
72
|
+
outcome_unknown: [],
|
|
73
|
+
retention_failed: [],
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
export function normalizeVideoGenerationRequest(input: {
|
|
77
|
+
toolInput: GenerateVideoToolInputType;
|
|
78
|
+
model: VideoGenerationModelCapability;
|
|
79
|
+
sealedReferences: readonly SealedVideoReference[];
|
|
80
|
+
}): CanonicalVideoGenerationRequest {
|
|
81
|
+
const toolInput = GenerateVideoToolInput.parse(input.toolInput);
|
|
82
|
+
if (toolInput.modelId !== undefined && toolInput.modelId !== input.model.modelId) {
|
|
83
|
+
throw new Error("Video generation model changed during admission");
|
|
84
|
+
}
|
|
85
|
+
const sourceMode = toolInput.source?.mode ?? "text";
|
|
86
|
+
if (!input.model.sourceModes.includes(sourceMode)) {
|
|
87
|
+
throw new Error(`Video generation source mode ${sourceMode} is unavailable`);
|
|
88
|
+
}
|
|
89
|
+
assertReferenceRoles(sourceMode, input.sealedReferences);
|
|
90
|
+
|
|
91
|
+
const durationSeconds = toolInput.durationSeconds ?? input.model.duration.minSeconds;
|
|
92
|
+
if (
|
|
93
|
+
durationSeconds < input.model.duration.minSeconds ||
|
|
94
|
+
durationSeconds > input.model.duration.maxSeconds ||
|
|
95
|
+
(durationSeconds - input.model.duration.minSeconds) % input.model.duration.stepSeconds !== 0
|
|
96
|
+
) {
|
|
97
|
+
throw new Error("Video generation duration is unavailable for the selected model");
|
|
98
|
+
}
|
|
99
|
+
const aspectRatio = toolInput.aspectRatio ?? input.model.aspectRatios[0];
|
|
100
|
+
const resolution = toolInput.resolution ?? input.model.resolutions[0];
|
|
101
|
+
if (!aspectRatio || !input.model.aspectRatios.includes(aspectRatio)) {
|
|
102
|
+
throw new Error("Video generation aspect ratio is unavailable for the selected model");
|
|
103
|
+
}
|
|
104
|
+
if (!resolution || !input.model.resolutions.includes(resolution)) {
|
|
105
|
+
throw new Error("Video generation resolution is unavailable for the selected model");
|
|
106
|
+
}
|
|
107
|
+
const generateAudio = toolInput.generateAudio ?? input.model.supportsAudio;
|
|
108
|
+
if (generateAudio && !input.model.supportsAudio) {
|
|
109
|
+
throw new Error("Audio generation is unavailable for the selected model");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
schemaVersion: 1,
|
|
114
|
+
modelId: input.model.modelId,
|
|
115
|
+
prompt: toolInput.prompt,
|
|
116
|
+
sourceMode,
|
|
117
|
+
references: Object.freeze(
|
|
118
|
+
input.sealedReferences.map((reference) => Object.freeze({ ...reference })),
|
|
119
|
+
),
|
|
120
|
+
durationSeconds,
|
|
121
|
+
aspectRatio,
|
|
122
|
+
resolution,
|
|
123
|
+
generateAudio,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function canonicalVideoGenerationRequestJson(
|
|
128
|
+
request: CanonicalVideoGenerationRequest,
|
|
129
|
+
): string {
|
|
130
|
+
return JSON.stringify({
|
|
131
|
+
schemaVersion: request.schemaVersion,
|
|
132
|
+
modelId: request.modelId,
|
|
133
|
+
prompt: request.prompt,
|
|
134
|
+
sourceMode: request.sourceMode,
|
|
135
|
+
references: request.references.map((reference) => ({
|
|
136
|
+
role: reference.role,
|
|
137
|
+
contentSha256: reference.contentSha256,
|
|
138
|
+
contentType: reference.contentType,
|
|
139
|
+
byteSize: reference.byteSize,
|
|
140
|
+
})),
|
|
141
|
+
durationSeconds: request.durationSeconds,
|
|
142
|
+
aspectRatio: request.aspectRatio,
|
|
143
|
+
resolution: request.resolution,
|
|
144
|
+
generateAudio: request.generateAudio,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function videoGenerationRequestDigest(request: CanonicalVideoGenerationRequest): string {
|
|
149
|
+
return sha256(
|
|
150
|
+
"opengeni:video-generation-request:v1\0",
|
|
151
|
+
canonicalVideoGenerationRequestJson(request),
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** Stable only for one logical tool call; intentional identical calls remain distinct. */
|
|
156
|
+
export function videoGenerationAdmissionKey(input: {
|
|
157
|
+
workspaceId: string;
|
|
158
|
+
sessionId: string;
|
|
159
|
+
turnId: string;
|
|
160
|
+
toolCallId: string;
|
|
161
|
+
}): string {
|
|
162
|
+
return sha256(
|
|
163
|
+
"opengeni:video-generation-admission:v1\0",
|
|
164
|
+
input.workspaceId,
|
|
165
|
+
input.sessionId,
|
|
166
|
+
input.turnId,
|
|
167
|
+
input.toolCallId,
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export function videoGenerationProviderIdempotencyKey(input: {
|
|
172
|
+
operationId: string;
|
|
173
|
+
requestDigest: string;
|
|
174
|
+
}): string {
|
|
175
|
+
return `ogvid_${sha256(
|
|
176
|
+
"opengeni:video-generation-provider-start:v1\0",
|
|
177
|
+
input.operationId,
|
|
178
|
+
input.requestDigest,
|
|
179
|
+
).slice(0, 48)}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export function videoGenerationCapabilityRevision(input: {
|
|
183
|
+
policyRevision: number;
|
|
184
|
+
fundingSource: VideoGenerationFundingSource;
|
|
185
|
+
credentialVersion: number;
|
|
186
|
+
modelIds: readonly string[];
|
|
187
|
+
}): string {
|
|
188
|
+
return sha256(
|
|
189
|
+
"opengeni:video-generation-capability:v1\0",
|
|
190
|
+
String(input.policyRevision),
|
|
191
|
+
input.fundingSource,
|
|
192
|
+
String(input.credentialVersion),
|
|
193
|
+
JSON.stringify([...input.modelIds].sort()),
|
|
194
|
+
VIDEO_GENERATION_ADAPTER_VERSION,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export function assertVideoGenerationTransition(
|
|
199
|
+
from: VideoGenerationOperationState,
|
|
200
|
+
to: VideoGenerationOperationState,
|
|
201
|
+
): void {
|
|
202
|
+
if (from === to) return;
|
|
203
|
+
if (!ALLOWED_TRANSITIONS[from].includes(to)) {
|
|
204
|
+
throw new Error(`Invalid video generation transition ${from} -> ${to}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function isTerminalVideoGenerationState(state: VideoGenerationOperationState): boolean {
|
|
209
|
+
return TERMINAL_STATES.has(state);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function assertReferenceRoles(
|
|
213
|
+
sourceMode: VideoGenerationSourceMode,
|
|
214
|
+
references: readonly SealedVideoReference[],
|
|
215
|
+
): void {
|
|
216
|
+
const expected: readonly SealedVideoReferenceRole[] =
|
|
217
|
+
sourceMode === "text"
|
|
218
|
+
? []
|
|
219
|
+
: sourceMode === "first_frame"
|
|
220
|
+
? ["first_frame"]
|
|
221
|
+
: sourceMode === "first_and_last_frames"
|
|
222
|
+
? ["first_frame", "last_frame"]
|
|
223
|
+
: sourceMode === "image_reference"
|
|
224
|
+
? ["image_reference"]
|
|
225
|
+
: ["video_reference"];
|
|
226
|
+
if (
|
|
227
|
+
references.length !== expected.length ||
|
|
228
|
+
references.some((reference, index) => reference.role !== expected[index])
|
|
229
|
+
) {
|
|
230
|
+
throw new Error(`Sealed references do not match video source mode ${sourceMode}`);
|
|
231
|
+
}
|
|
232
|
+
for (const reference of references) {
|
|
233
|
+
if (!/^[0-9a-f]{64}$/u.test(reference.contentSha256)) {
|
|
234
|
+
throw new Error("Video reference has an invalid SHA-256 digest");
|
|
235
|
+
}
|
|
236
|
+
if (!Number.isSafeInteger(reference.byteSize) || reference.byteSize <= 0) {
|
|
237
|
+
throw new Error("Video reference has an invalid byte size");
|
|
238
|
+
}
|
|
239
|
+
if (!reference.contentType.includes("/")) {
|
|
240
|
+
throw new Error("Video reference has an invalid content type");
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function sha256(prefix: string, ...parts: string[]): string {
|
|
246
|
+
const hash = createHash("sha256").update(prefix);
|
|
247
|
+
for (const part of parts) hash.update(part).update("\0");
|
|
248
|
+
return hash.digest("hex");
|
|
249
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { EditableArtifactService } from "../domain/editable-artifacts/service";
|
|
2
|
+
import { EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES } from "@opengeni/contracts/editable-artifacts";
|
|
3
|
+
import {
|
|
4
|
+
editableArtifactClientTransactionId,
|
|
5
|
+
editableArtifactId,
|
|
6
|
+
editableArtifactScope,
|
|
7
|
+
validateEditableArtifactActor,
|
|
8
|
+
type EditableArtifact,
|
|
9
|
+
type EditableArtifactActor,
|
|
10
|
+
type EditableArtifactClientTransactionId,
|
|
11
|
+
type EditableArtifactId,
|
|
12
|
+
type EditableArtifactModality,
|
|
13
|
+
type EditableArtifactOriginalImport,
|
|
14
|
+
type EditableArtifactScope,
|
|
15
|
+
type ImportEditableArtifactRequest,
|
|
16
|
+
} from "../domain/editable-artifacts/types";
|
|
17
|
+
import type {
|
|
18
|
+
EditableArtifactLiveSession,
|
|
19
|
+
EditableArtifactLiveServer,
|
|
20
|
+
OpenEditableArtifactLiveInput,
|
|
21
|
+
} from "./server";
|
|
22
|
+
import type { EditableArtifactLiveTicket } from "./types";
|
|
23
|
+
|
|
24
|
+
export type EditableArtifactLiveCompatibilityRequest = Readonly<{
|
|
25
|
+
artifact: EditableArtifact;
|
|
26
|
+
protocolVersion: number;
|
|
27
|
+
kernelVersion: string;
|
|
28
|
+
modelSchemaVersion: number;
|
|
29
|
+
}>;
|
|
30
|
+
|
|
31
|
+
/** A client/runtime protocol tuple cannot be served by the loaded kernel. */
|
|
32
|
+
export class EditableArtifactCompatibilityError extends Error {
|
|
33
|
+
readonly code = "unsupported_protocol" as const;
|
|
34
|
+
|
|
35
|
+
constructor(message = "Editable artifact runtime is incompatible") {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "EditableArtifactCompatibilityError";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Local runtime compatibility; unsupported native/WASM assets fail closed. */
|
|
42
|
+
export interface EditableArtifactLiveCompatibilityPort {
|
|
43
|
+
assertCompatible(input: EditableArtifactLiveCompatibilityRequest): Promise<void> | void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export type CreateEditableArtifactApplicationInput = Readonly<{
|
|
47
|
+
scope: EditableArtifactScope;
|
|
48
|
+
actor: EditableArtifactActor;
|
|
49
|
+
idempotencyKey: EditableArtifactClientTransactionId;
|
|
50
|
+
modality: EditableArtifactModality;
|
|
51
|
+
title: string;
|
|
52
|
+
signal?: AbortSignal;
|
|
53
|
+
}>;
|
|
54
|
+
|
|
55
|
+
export type ImportEditableArtifactApplicationInput = Readonly<{
|
|
56
|
+
scope: EditableArtifactScope;
|
|
57
|
+
actor: EditableArtifactActor;
|
|
58
|
+
idempotencyKey: EditableArtifactClientTransactionId;
|
|
59
|
+
modality: EditableArtifactModality;
|
|
60
|
+
title: string;
|
|
61
|
+
originalImport: EditableArtifactOriginalImport;
|
|
62
|
+
snapshot: ImportEditableArtifactRequest["snapshot"];
|
|
63
|
+
signal?: AbortSignal;
|
|
64
|
+
}>;
|
|
65
|
+
|
|
66
|
+
export type ReadEditableArtifactApplicationInput = Readonly<{
|
|
67
|
+
scope: EditableArtifactScope;
|
|
68
|
+
actor: EditableArtifactActor;
|
|
69
|
+
artifactId: EditableArtifactId;
|
|
70
|
+
}>;
|
|
71
|
+
|
|
72
|
+
export type MintEditableArtifactApplicationTicketInput = ReadEditableArtifactApplicationInput &
|
|
73
|
+
Readonly<{
|
|
74
|
+
protocolVersion: number;
|
|
75
|
+
kernelVersion: string;
|
|
76
|
+
modelSchemaVersion: number;
|
|
77
|
+
allowEdit: boolean;
|
|
78
|
+
}>;
|
|
79
|
+
|
|
80
|
+
/** Exact application seam used by standalone API and embedding hosts. */
|
|
81
|
+
export interface EditableArtifactApplicationPort {
|
|
82
|
+
createArtifact(input: CreateEditableArtifactApplicationInput): Promise<EditableArtifact>;
|
|
83
|
+
importArtifact(input: ImportEditableArtifactApplicationInput): Promise<EditableArtifact>;
|
|
84
|
+
readArtifact(input: ReadEditableArtifactApplicationInput): Promise<EditableArtifact>;
|
|
85
|
+
mintLiveTicket(
|
|
86
|
+
input: MintEditableArtifactApplicationTicketInput,
|
|
87
|
+
): Promise<EditableArtifactLiveTicket>;
|
|
88
|
+
openLive(input: OpenEditableArtifactLiveInput): Promise<EditableArtifactLiveSession>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class EditableArtifactApplication implements EditableArtifactApplicationPort {
|
|
92
|
+
constructor(
|
|
93
|
+
private readonly dependencies: Readonly<{
|
|
94
|
+
domain: EditableArtifactService;
|
|
95
|
+
live: EditableArtifactLiveServer;
|
|
96
|
+
compatibility: EditableArtifactLiveCompatibilityPort;
|
|
97
|
+
}>,
|
|
98
|
+
) {}
|
|
99
|
+
|
|
100
|
+
async createArtifact(input: CreateEditableArtifactApplicationInput): Promise<EditableArtifact> {
|
|
101
|
+
const scope = editableArtifactScope(input.scope);
|
|
102
|
+
validateEditableArtifactActor(input.actor);
|
|
103
|
+
const result = await this.dependencies.domain.createArtifact({
|
|
104
|
+
scope,
|
|
105
|
+
actor: Object.freeze({ ...input.actor }) as EditableArtifactActor,
|
|
106
|
+
request: {
|
|
107
|
+
idempotencyKey: editableArtifactClientTransactionId(input.idempotencyKey),
|
|
108
|
+
modality: input.modality,
|
|
109
|
+
title: input.title,
|
|
110
|
+
},
|
|
111
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
112
|
+
});
|
|
113
|
+
return result.artifact;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async importArtifact(input: ImportEditableArtifactApplicationInput): Promise<EditableArtifact> {
|
|
117
|
+
const scope = editableArtifactScope(input.scope);
|
|
118
|
+
validateEditableArtifactActor(input.actor);
|
|
119
|
+
const result = await this.dependencies.domain.importArtifact({
|
|
120
|
+
scope,
|
|
121
|
+
actor: Object.freeze({ ...input.actor }) as EditableArtifactActor,
|
|
122
|
+
request: {
|
|
123
|
+
idempotencyKey: editableArtifactClientTransactionId(input.idempotencyKey),
|
|
124
|
+
modality: input.modality,
|
|
125
|
+
title: input.title,
|
|
126
|
+
originalImport: input.originalImport,
|
|
127
|
+
snapshot: input.snapshot,
|
|
128
|
+
},
|
|
129
|
+
...(input.signal ? { signal: input.signal } : {}),
|
|
130
|
+
});
|
|
131
|
+
return result.artifact;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async readArtifact(input: ReadEditableArtifactApplicationInput): Promise<EditableArtifact> {
|
|
135
|
+
const scope = editableArtifactScope(input.scope);
|
|
136
|
+
const artifactId = editableArtifactId(input.artifactId);
|
|
137
|
+
validateEditableArtifactActor(input.actor);
|
|
138
|
+
return await this.dependencies.domain.getArtifact({
|
|
139
|
+
scope,
|
|
140
|
+
artifactId,
|
|
141
|
+
actor: Object.freeze({ ...input.actor }) as EditableArtifactActor,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async mintLiveTicket(
|
|
146
|
+
input: MintEditableArtifactApplicationTicketInput,
|
|
147
|
+
): Promise<EditableArtifactLiveTicket> {
|
|
148
|
+
const artifact = await this.readArtifact(input);
|
|
149
|
+
await this.dependencies.compatibility.assertCompatible({
|
|
150
|
+
artifact,
|
|
151
|
+
protocolVersion: positiveInteger(input.protocolVersion, "protocolVersion"),
|
|
152
|
+
kernelVersion: boundedVersion(input.kernelVersion, "kernelVersion"),
|
|
153
|
+
modelSchemaVersion: positiveInteger(input.modelSchemaVersion, "modelSchemaVersion"),
|
|
154
|
+
});
|
|
155
|
+
return await this.dependencies.live.mintTicket({
|
|
156
|
+
scope: artifact.scope,
|
|
157
|
+
artifactId: artifact.id,
|
|
158
|
+
modality: artifact.modality,
|
|
159
|
+
actor: input.actor,
|
|
160
|
+
allowEdit: input.allowEdit,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
openLive(input: OpenEditableArtifactLiveInput): Promise<EditableArtifactLiveSession> {
|
|
165
|
+
return this.dependencies.live.openLive(input);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function positiveInteger(value: number, label: string): number {
|
|
170
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
171
|
+
throw new TypeError(`${label} must be a positive safe integer`);
|
|
172
|
+
}
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function boundedVersion(value: string, label: string): string {
|
|
177
|
+
const bytes = new TextEncoder().encode(value).byteLength;
|
|
178
|
+
if (bytes < 1 || bytes > EDITABLE_ARTIFACT_KERNEL_VERSION_MAX_BYTES || value.trim() !== value) {
|
|
179
|
+
throw new TypeError(`${label} is malformed`);
|
|
180
|
+
}
|
|
181
|
+
return value;
|
|
182
|
+
}
|