@mengine/medeo-tool 1.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # `@mengine/medeo-tool`
2
+
3
+ Node tool surface for editing a Medeo video document through the deterministic
4
+ edit sandbox.
5
+
6
+ The package owns the complete tool path:
7
+
8
+ - compact snapshot projection;
9
+ - trusted worker execution of an agent-authored JavaScript edit script;
10
+ - op-journal `ChangePlan` caching;
11
+ - versioned or per-op-preflight commit through `MengineDocSession`;
12
+ - session cache and shutdown.
13
+
14
+ A host supplies only environment facts: Mengine HTTP origin, optional request
15
+ identity headers, `fetch`, and a stable agent peer id.
16
+
17
+ ```ts
18
+ import { createMedeoTool } from '@mengine/medeo-tool';
19
+
20
+ const medeo = createMedeoTool({
21
+ httpOrigin: process.env.MENGINE_HTTP_ORIGIN!,
22
+ userId: () => process.env.MED_USER_ID,
23
+ peerId: () => process.env.MED_AGENT_PEER_ID,
24
+ });
25
+
26
+ const snapshot = await medeo.handle({ op: 'snapshot', doc_id: docId });
27
+ const run = await medeo.handle({
28
+ op: 'run-edit-script',
29
+ doc_id: docId,
30
+ script: 'await edit.deleteBgm({})',
31
+ });
32
+ if (!run.ok || run.op !== 'run-edit-script') throw new Error('edit script failed');
33
+ const commit = await medeo.handle({
34
+ op: 'commit-plan',
35
+ doc_id: docId,
36
+ plan_id: run.plan_id,
37
+ });
38
+
39
+ await medeo.close();
40
+ ```
41
+
42
+ The sandbox has no network, storage, clock, or generation access. Materialize
43
+ speech/media side effects in the host first and pass stable facts through
44
+ `inputs`.
@@ -0,0 +1,457 @@
1
+ import { JournalEntry, MengineDocSession, PartIdFactory, SemanticOpName, VideoDocument, fromVideoDocument } from "@mengine/medeo-client";
2
+ import { AddSpeechesInput, AddVideoClipsInput, AdjustBgmVolumeInput, AdjustSpeechVolumeInput, AdjustVideoClipDurationInput, AdjustVideoClipVolumeInput, ChangeSpeechScriptInput, ChangeSpeechVoiceInput, DeleteBgmInput, DeleteSpeechesInput, DeleteVideoClipsInput, MoveSpeechesInput, MoveVideoClipsInput, ReplaceVideoClipContentInput, SetBgmInput, SetCaptionStyleInput, SetCaptionVisibilityInput, SetVideoClipSpeedShiftInput } from "@mengine/medeo-client/schemas";
3
+
4
+ //#region src/document/compact-projection.d.ts
5
+ /**
6
+ * Compact text projection of a `VideoDocument` for sandbox ChangePlan
7
+ * `preview` (and pipeline dry-run preview). Pure, runtime-neutral: solves
8
+ * via `solveVideoDocument`, emits one header line plus one row per timeline
9
+ * item (library orphans are never rendered). Row intervals and per-kind
10
+ * effective durations align with `toReadViewPartLibrary` /
11
+ * `fromVideoDocument`.
12
+ */
13
+ interface CompactProjectionOptions {
14
+ /** Only render these parts (header still reports the full timeline total). Default = all. */
15
+ onlyPartIds?: ReadonlySet<string>;
16
+ /** Caption text preview truncation length. Default 24. */
17
+ textPreviewLength?: number;
18
+ }
19
+ /**
20
+ * Render a `VideoDocument` as compact text: one header line plus one row per
21
+ * timeline part (optionally filtered by `onlyPartIds`). Deterministic and
22
+ * side-effect free — same document always yields the same string.
23
+ */
24
+ declare function renderCompactProjection(document: VideoDocument, options?: CompactProjectionOptions): string;
25
+ //#endregion
26
+ //#region src/sandbox/preview.d.ts
27
+ /** Extract every part id a journal entry touches (payload refs + minted ids). */
28
+ declare function collectAffectedPartIds(journal: readonly JournalEntry[]): Set<string>;
29
+ /**
30
+ * Render a ChangePlan preview: header + rows for journal-affected parts only.
31
+ * Empty journal → empty `onlyPartIds` (header alone), matching the T2 contract.
32
+ */
33
+ declare function renderPreview(document: VideoDocument, journal: readonly JournalEntry[]): string;
34
+ //#endregion
35
+ //#region src/sandbox/script-session.d.ts
36
+ /**
37
+ * Runtime-neutral edit-sandbox session: `edit.*` / `timeline.*` / checkpoint
38
+ * facade over a forked `VideoDocument`, self-maintained journal, and console
39
+ * log buffer. No `node:*` imports — host/worker layers inject this into vm.
40
+ *
41
+ * Known gap (not solved here): `Math.random` / `Date.now` remain reachable in
42
+ * the vm; purity is by convention.
43
+ */
44
+ interface SandboxCheckpoint {
45
+ readonly index: number;
46
+ }
47
+ interface ChangePlan {
48
+ doc_id: string;
49
+ base_version: string;
50
+ ops: readonly JournalEntry[];
51
+ preview: string;
52
+ logs: string[];
53
+ }
54
+ interface EditSandboxSessionOptions {
55
+ idFactory?: PartIdFactory;
56
+ onEntry?: (entry: JournalEntry) => void;
57
+ onLog?: (line: string) => void;
58
+ /** Notify host that the streamed journal was truncated to `index` (rollback). */
59
+ onTruncate?: (index: number) => void;
60
+ }
61
+ interface TimelineClipDescriptor {
62
+ id: string;
63
+ start_ms: number;
64
+ end_ms: number;
65
+ duration_ms: number;
66
+ speed_shift: unknown;
67
+ volume: number | undefined;
68
+ media_id: string | undefined;
69
+ }
70
+ interface TimelinePartDescriptor {
71
+ id: string;
72
+ kind: string;
73
+ lane: string;
74
+ start_ms: number;
75
+ end_ms: number;
76
+ duration_ms: number;
77
+ part: unknown;
78
+ }
79
+ /** Session core for one forked document; globals stay identity-stable across rollback. */
80
+ declare class EditSandboxSession {
81
+ private readonly original;
82
+ private readonly idFactory;
83
+ private readonly onEntry;
84
+ private readonly onLog;
85
+ private readonly onTruncate;
86
+ private current;
87
+ /** Adapter journal length already accounted for — new slices are real commits. */
88
+ private adapterJournalSeen;
89
+ private readonly entries;
90
+ private readonly logs;
91
+ private logBytes;
92
+ private logCapped;
93
+ readonly edit: EditFacade;
94
+ readonly timeline: TimelineFacade;
95
+ readonly console: ConsoleShim;
96
+ readonly checkpoint: () => SandboxCheckpoint;
97
+ readonly rollbackTo: (cp: SandboxCheckpoint) => void;
98
+ constructor(document: VideoDocument, options?: EditSandboxSessionOptions);
99
+ /** Assemble a ChangePlan from the self-maintained journal + current preview. */
100
+ buildPlan(baseVersion: string): ChangePlan;
101
+ getEntries(): readonly JournalEntry[];
102
+ getLogs(): readonly string[];
103
+ private boot;
104
+ private doRollbackTo;
105
+ private captureNewEntries;
106
+ private appendLog;
107
+ private buildConsoleShim;
108
+ private buildEditFacade;
109
+ private buildTimelineFacade;
110
+ private clipsInRange;
111
+ private part;
112
+ }
113
+ interface EditFacade {
114
+ addSpeeches: (input: AddSpeechesInput) => Promise<void>;
115
+ addVideoClips: (input: AddVideoClipsInput) => Promise<void>;
116
+ adjustBgmVolume: (input: AdjustBgmVolumeInput) => Promise<void>;
117
+ adjustSpeechVolume: (input: AdjustSpeechVolumeInput) => Promise<void>;
118
+ adjustVideoClipDuration: (input: AdjustVideoClipDurationInput) => Promise<void>;
119
+ adjustVideoClipVolume: (input: AdjustVideoClipVolumeInput) => Promise<void>;
120
+ changeSpeechScript: (input: ChangeSpeechScriptInput) => Promise<void>;
121
+ changeSpeechVoice: (input: ChangeSpeechVoiceInput) => Promise<void>;
122
+ deleteBgm: (input: DeleteBgmInput) => Promise<void>;
123
+ deleteSpeeches: (input: DeleteSpeechesInput) => Promise<void>;
124
+ deleteVideoClips: (input: DeleteVideoClipsInput) => Promise<void>;
125
+ moveSpeeches: (input: MoveSpeechesInput) => Promise<void>;
126
+ moveVideoClips: (input: MoveVideoClipsInput) => Promise<void>;
127
+ replaceVideoClipContent: (input: ReplaceVideoClipContentInput) => Promise<void>;
128
+ setBgm: (input: SetBgmInput) => Promise<void>;
129
+ setCaptionStyle: (input: SetCaptionStyleInput) => Promise<void>;
130
+ setCaptionVisibility: (input: SetCaptionVisibilityInput) => Promise<void>;
131
+ setVideoClipSpeedShift: (input: SetVideoClipSpeedShiftInput) => Promise<void>;
132
+ }
133
+ interface TimelineFacade {
134
+ snapshot: () => ReturnType<typeof fromVideoDocument>;
135
+ clipsInRange: (startMs: number, endMs: number) => TimelineClipDescriptor[];
136
+ part: (id: string) => TimelinePartDescriptor | null;
137
+ }
138
+ interface ConsoleShim {
139
+ log: (...args: unknown[]) => void;
140
+ info: (...args: unknown[]) => void;
141
+ warn: (...args: unknown[]) => void;
142
+ error: (...args: unknown[]) => void;
143
+ }
144
+ //#endregion
145
+ //#region src/sandbox/node-host.d.ts
146
+ /**
147
+ * Host API for running an agent edit script in an isolated Node worker.
148
+ *
149
+ * Requires Node.js >= 24.15 (engines) so the worker can load TypeScript via
150
+ * `--experimental-transform-types`. Do not inherit `process.execArgv` — vitest
151
+ * injects loaders that break worker boot.
152
+ */
153
+ interface RunEditScriptOptions {
154
+ document: VideoDocument;
155
+ baseVersion: string;
156
+ script: string;
157
+ inputs?: Record<string, unknown>;
158
+ /** Deterministic id mint label for tests; omit to use the default ULID factory. */
159
+ idLabel?: string;
160
+ /** Hard wall-clock timeout; default 2000 ms. */
161
+ timeoutMs?: number;
162
+ /** V8 old-generation ceiling for the worker; default 256 MB. */
163
+ memoryLimitMb?: number;
164
+ /** Override worker module URL (defaults to sibling `worker-entry.ts`). */
165
+ workerEntryUrl?: URL;
166
+ }
167
+ type EditScriptResult = {
168
+ ok: true;
169
+ plan: ChangePlan; /** Script execution time after worker readiness; excludes cold start. */
170
+ durationMs: number;
171
+ } | {
172
+ ok: false;
173
+ phase: 'parse' | 'runtime' | 'timeout' | 'memory';
174
+ error: {
175
+ message: string;
176
+ line?: number;
177
+ column?: number;
178
+ stack?: string;
179
+ };
180
+ partial: {
181
+ ops: readonly JournalEntry[];
182
+ logs: string[];
183
+ };
184
+ };
185
+ /** Run `script` against a forked document snapshot; always resolves (never rejects). */
186
+ declare function runEditScript(options: RunEditScriptOptions): Promise<EditScriptResult>;
187
+ //#endregion
188
+ //#region src/prompt.d.ts
189
+ declare const MEDEO_TOOL_DESCRIPTION: string;
190
+ //#endregion
191
+ //#region src/schema.d.ts
192
+ declare const MEDEO_TOOL_NAME = "medeo";
193
+ type MedeoToolOp = 'snapshot' | 'run-edit-script' | 'commit-plan';
194
+ /**
195
+ * JSON Schema for the host-facing three-op `medeo` tool surface.
196
+ *
197
+ * The schema intentionally does not return or accept the full op journal:
198
+ * journals stay in the tool process and are referenced by `plan_id`. This keeps
199
+ * large intermediate products out of model context while preserving the exact
200
+ * journal used for commit.
201
+ */
202
+ declare const MEDEO_TOOL_PARAMETERS: {
203
+ readonly type: 'object';
204
+ readonly required: readonly ['op', 'doc_id'];
205
+ readonly additionalProperties: false;
206
+ readonly properties: {
207
+ readonly op: {
208
+ readonly type: 'string';
209
+ readonly enum: readonly ['snapshot', 'run-edit-script', 'commit-plan'];
210
+ readonly description: 'Which Medeo document operation to run.';
211
+ };
212
+ readonly doc_id: {
213
+ readonly type: 'string';
214
+ readonly minLength: 1;
215
+ readonly description: 'Medeo document id. Copy it from the host context; never invent it.';
216
+ };
217
+ readonly script: {
218
+ readonly type: 'string';
219
+ readonly minLength: 1;
220
+ readonly description: 'JavaScript body for run-edit-script. It receives edit, timeline, checkpoint, rollbackTo, inputs, and console; perform all calculations in the script.';
221
+ };
222
+ readonly inputs: {
223
+ readonly type: 'object';
224
+ readonly description: 'Pre-materialized, side-effect-free values passed into the script. Generation and network IO must happen in the host before this call.';
225
+ };
226
+ readonly timeout_ms: {
227
+ readonly type: 'integer';
228
+ readonly minimum: 1;
229
+ readonly description: 'Maximum script wall-clock time after worker startup (default 2000).';
230
+ };
231
+ readonly memory_limit_mb: {
232
+ readonly type: 'integer';
233
+ readonly minimum: 16;
234
+ readonly description: 'Worker old-generation memory ceiling in MB (default 256).';
235
+ };
236
+ readonly auto_commit: {
237
+ readonly type: 'boolean';
238
+ readonly description: 'Commit the returned plan immediately after the sandbox succeeds. Default false: return preview plus plan_id for explicit commit.';
239
+ };
240
+ readonly plan_id: {
241
+ readonly type: 'string';
242
+ readonly minLength: 1;
243
+ readonly description: 'Plan id returned by run-edit-script; required by commit-plan.';
244
+ };
245
+ readonly validation: {
246
+ readonly type: 'string';
247
+ readonly enum: readonly ['version', 'preflight'];
248
+ readonly description: 'commit-plan mode: version rejects any concurrent change; preflight revalidates each op against the current snapshot.';
249
+ };
250
+ };
251
+ readonly oneOf: readonly [{
252
+ readonly required: readonly ['op', 'doc_id'];
253
+ readonly properties: {
254
+ readonly op: {
255
+ readonly const: 'snapshot';
256
+ };
257
+ readonly doc_id: {
258
+ readonly $ref: '#/properties/doc_id';
259
+ };
260
+ };
261
+ readonly additionalProperties: false;
262
+ }, {
263
+ readonly required: readonly ['op', 'doc_id', 'script'];
264
+ readonly properties: {
265
+ readonly op: {
266
+ readonly const: 'run-edit-script';
267
+ };
268
+ readonly doc_id: {
269
+ readonly $ref: '#/properties/doc_id';
270
+ };
271
+ readonly script: {
272
+ readonly $ref: '#/properties/script';
273
+ };
274
+ readonly inputs: {
275
+ readonly $ref: '#/properties/inputs';
276
+ };
277
+ readonly timeout_ms: {
278
+ readonly $ref: '#/properties/timeout_ms';
279
+ };
280
+ readonly memory_limit_mb: {
281
+ readonly $ref: '#/properties/memory_limit_mb';
282
+ };
283
+ readonly auto_commit: {
284
+ readonly $ref: '#/properties/auto_commit';
285
+ };
286
+ };
287
+ readonly additionalProperties: false;
288
+ }, {
289
+ readonly required: readonly ['op', 'doc_id', 'plan_id'];
290
+ readonly properties: {
291
+ readonly op: {
292
+ readonly const: 'commit-plan';
293
+ };
294
+ readonly doc_id: {
295
+ readonly $ref: '#/properties/doc_id';
296
+ };
297
+ readonly plan_id: {
298
+ readonly $ref: '#/properties/plan_id';
299
+ };
300
+ readonly validation: {
301
+ readonly $ref: '#/properties/validation';
302
+ };
303
+ };
304
+ readonly additionalProperties: false;
305
+ }];
306
+ };
307
+ //#endregion
308
+ //#region src/session/commit-plan.d.ts
309
+ /**
310
+ * A sandbox journal plus the opaque version token taken at fork time.
311
+ * `commitPlan` rejects the whole plan when the live session has moved on
312
+ * (phase-1 version gate), or localizes a business conflict to a journal
313
+ * entry under `{ validation: 'preflight' }`.
314
+ */
315
+ interface CommitPlan {
316
+ /** `session.version()` at the moment the sandbox was forked. */
317
+ base_version: string;
318
+ ops: readonly JournalEntry[];
319
+ }
320
+ type CommitPlanResult = {
321
+ kind: 'committed';
322
+ ops_applied: number;
323
+ } | {
324
+ kind: 'rejected';
325
+ reason: 'version_mismatch';
326
+ expected: string;
327
+ actual: string;
328
+ } | {
329
+ kind: 'rejected';
330
+ reason: 'op_conflict'; /** Failing entry index in the journal — agent rerun anchor. */
331
+ index: number;
332
+ op_kind: SemanticOpName; /** Validator message, passed through verbatim (never a raw Error). */
333
+ message: string;
334
+ };
335
+ interface CommitPlanOptions {
336
+ /** `'version'` (default, phase-1 hard gate) | `'preflight'` (phase-2 per-op revalidation). */
337
+ validation?: 'version' | 'preflight';
338
+ }
339
+ /**
340
+ * Replay a sandbox journal into a live session through its document adapter
341
+ * (SemanticEditor → Loro → mengine-server).
342
+ *
343
+ * - Default / `{ validation: 'version' }`: if `session.version()` ≠
344
+ * `plan.base_version`, reject with zero writes.
345
+ * - `{ validation: 'preflight' }`: skip the version gate; revalidate each op
346
+ * against a PlainMemoryAdapter seeded from the current live snapshot, then
347
+ * replay for real. A SchemaValidator failure becomes `op_conflict` with the
348
+ * failing entry's index. Journal integrity errors (unrecorded/unconsumed
349
+ * ids) still propagate as throws in both modes.
350
+ */
351
+ declare function commitPlan(session: MengineDocSession, plan: CommitPlan, options?: CommitPlanOptions): Promise<CommitPlanResult>;
352
+ //#endregion
353
+ //#region src/host-tool.d.ts
354
+ type ContextualValue<T> = T | ((docId: string) => T | undefined);
355
+ interface CreateMedeoToolOptions {
356
+ /**
357
+ * Mengine HTTP origin for a document. The host owns environment routing
358
+ * (local/stg/prd/lane) and may return a different origin per document.
359
+ * Sessions cache by doc id, so the origin must remain stable for that doc.
360
+ */
361
+ httpOrigin: ContextualValue<string>;
362
+ /** Optional bearer token, evaluated for each HTTP request. */
363
+ authToken?: ContextualValue<string>;
364
+ /** Optional end-user id header, evaluated for each HTTP request. */
365
+ userId?: ContextualValue<string>;
366
+ /** Stable agent peer id. Supply a host-scoped value so audit provenance is durable. */
367
+ peerId?: ContextualValue<string>;
368
+ fetchImpl?: typeof fetch;
369
+ sseReconnectDelayMs?: number;
370
+ /** Defaults passed to runEditScript; each call may override them. */
371
+ sandbox?: {
372
+ timeoutMs?: number;
373
+ memoryLimitMb?: number;
374
+ };
375
+ /** Maximum cached plans; oldest plans are evicted (default 16). */
376
+ maxPlans?: number;
377
+ }
378
+ type MedeoToolInput = {
379
+ op: 'snapshot';
380
+ doc_id: string;
381
+ } | {
382
+ op: 'run-edit-script';
383
+ doc_id: string;
384
+ script: string;
385
+ inputs?: Record<string, unknown>;
386
+ timeout_ms?: number;
387
+ memory_limit_mb?: number;
388
+ auto_commit?: boolean;
389
+ } | {
390
+ op: 'commit-plan';
391
+ doc_id: string;
392
+ plan_id: string;
393
+ validation?: 'version' | 'preflight';
394
+ };
395
+ type MedeoToolResult = {
396
+ ok: true;
397
+ op: 'snapshot';
398
+ doc_id: string;
399
+ version: string;
400
+ preview: string;
401
+ } | {
402
+ ok: true;
403
+ op: 'run-edit-script';
404
+ doc_id: string;
405
+ plan_id: string;
406
+ base_version: string;
407
+ ops_count: number;
408
+ preview: string;
409
+ logs: string[];
410
+ duration_ms: number;
411
+ committed?: boolean;
412
+ commit_result?: CommitPlanResult;
413
+ } | {
414
+ ok: false;
415
+ op: 'run-edit-script';
416
+ doc_id: string;
417
+ phase: 'parse' | 'runtime' | 'timeout' | 'memory';
418
+ error: {
419
+ message: string;
420
+ line?: number;
421
+ column?: number;
422
+ stack?: string;
423
+ };
424
+ partial: {
425
+ ops_count: number;
426
+ logs: string[];
427
+ };
428
+ } | {
429
+ ok: true;
430
+ op: 'commit-plan';
431
+ doc_id: string;
432
+ plan_id: string;
433
+ committed: boolean;
434
+ result: CommitPlanResult;
435
+ } | {
436
+ ok: false;
437
+ op: MedeoToolOp;
438
+ error: string;
439
+ };
440
+ interface MedeoTool {
441
+ name: typeof MEDEO_TOOL_NAME;
442
+ description: typeof MEDEO_TOOL_DESCRIPTION;
443
+ parameters: typeof MEDEO_TOOL_PARAMETERS;
444
+ handle(input: unknown): Promise<MedeoToolResult>;
445
+ close(): Promise<void>;
446
+ }
447
+ /**
448
+ * Create the self-contained Medeo LLM tool.
449
+ *
450
+ * The package owns session construction, compact projection, sandbox execution,
451
+ * plan caching, commit, and shutdown. The host supplies only environment facts:
452
+ * HTTP origin, credentials, fetch implementation, and a stable peer id.
453
+ */
454
+ declare function createMedeoTool(options: CreateMedeoToolOptions): MedeoTool;
455
+ //#endregion
456
+ export { type ChangePlan, type CommitPlan, type CommitPlanOptions, type CommitPlanResult, type CompactProjectionOptions, type ConsoleShim, type CreateMedeoToolOptions, type EditFacade, EditSandboxSession, type EditSandboxSessionOptions, type EditScriptResult, MEDEO_TOOL_DESCRIPTION, MEDEO_TOOL_NAME, MEDEO_TOOL_PARAMETERS, type MedeoTool, type MedeoToolInput, type MedeoToolOp, type MedeoToolResult, type RunEditScriptOptions, type SandboxCheckpoint, type TimelineClipDescriptor, type TimelineFacade, type TimelinePartDescriptor, collectAffectedPartIds, commitPlan, createMedeoTool, renderCompactProjection, renderPreview, runEditScript };
457
+ //# sourceMappingURL=index.d.mts.map