@larkup/tool-video-intelligence 0.2.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.
Files changed (54) hide show
  1. package/.env.example +150 -0
  2. package/LICENSE +176 -0
  3. package/README.md +281 -0
  4. package/compose.gpu.yaml +14 -0
  5. package/compose.yaml +71 -0
  6. package/dist/agent.d.ts +131 -0
  7. package/dist/agent.js +2087 -0
  8. package/dist/brief.d.ts +2 -0
  9. package/dist/brief.js +37 -0
  10. package/dist/client.d.ts +46 -0
  11. package/dist/client.js +139 -0
  12. package/dist/contracts.d.ts +331 -0
  13. package/dist/contracts.js +1 -0
  14. package/dist/index.d.ts +87 -0
  15. package/dist/index.js +391 -0
  16. package/dist/runtime.d.ts +96 -0
  17. package/dist/runtime.js +592 -0
  18. package/dist/ui.d.ts +82 -0
  19. package/dist/ui.js +87 -0
  20. package/package.json +84 -0
  21. package/runtime/Dockerfile +119 -0
  22. package/runtime/app/__init__.py +3 -0
  23. package/runtime/app/__main__.py +19 -0
  24. package/runtime/app/api/__init__.py +0 -0
  25. package/runtime/app/api/deps.py +69 -0
  26. package/runtime/app/api/v1.py +166 -0
  27. package/runtime/app/config.py +78 -0
  28. package/runtime/app/db/__init__.py +0 -0
  29. package/runtime/app/db/schemas.py +162 -0
  30. package/runtime/app/db/store.py +466 -0
  31. package/runtime/app/main.py +27 -0
  32. package/runtime/app/model_configuration.py +157 -0
  33. package/runtime/app/services/__init__.py +0 -0
  34. package/runtime/app/services/brain.py +2221 -0
  35. package/runtime/app/services/embedding.py +473 -0
  36. package/runtime/app/services/jobs.py +237 -0
  37. package/runtime/app/services/motion.py +66 -0
  38. package/runtime/app/services/pipeline.py +1911 -0
  39. package/runtime/app/services/scene.py +161 -0
  40. package/runtime/app/services/storage.py +44 -0
  41. package/runtime/app/services/transcription.py +667 -0
  42. package/runtime/app/services/vision.py +1441 -0
  43. package/runtime/app/utils/__init__.py +0 -0
  44. package/runtime/app/utils/timing.py +99 -0
  45. package/runtime/app/worker.py +20 -0
  46. package/runtime/pyproject.toml +56 -0
  47. package/runtime/requirements-cpu.txt +15 -0
  48. package/runtime/requirements-smoke.txt +7 -0
  49. package/runtime/requirements.txt +14 -0
  50. package/runtime/uv.lock +3637 -0
  51. package/scripts/grant-cloud-credits.sh +43 -0
  52. package/scripts/runtime.mjs +156 -0
  53. package/scripts/validate-indexing.mjs +168 -0
  54. package/tool.manifest.json +617 -0
@@ -0,0 +1,2 @@
1
+ import type { VideoIndexingBrief } from './contracts.js';
2
+ export declare function createVideoIndexingBrief(input?: Partial<VideoIndexingBrief>): VideoIndexingBrief;
package/dist/brief.js ADDED
@@ -0,0 +1,37 @@
1
+ const MODES = new Set(['fast', 'balanced', 'thorough']);
2
+ function normalizeMode(value) {
3
+ return MODES.has(value) ? value : 'balanced';
4
+ }
5
+ export function createVideoIndexingBrief(input = {}) {
6
+ const contentType = input.contentType?.trim().slice(0, 120) || 'general';
7
+ const indexingMode = normalizeMode(input.indexingMode);
8
+ const retainSourceHours = Number.isFinite(input.retainSourceHours)
9
+ ? Math.max(0, Math.min(720, Math.floor(input.retainSourceHours)))
10
+ : 0;
11
+ return {
12
+ goal: input.goal?.trim().slice(0, 4_000) || undefined,
13
+ contentType,
14
+ knownEntities: uniqueStrings(input.knownEntities, 50),
15
+ expectedQuestions: uniqueStrings(input.expectedQuestions, 20),
16
+ language: input.language?.trim().slice(0, 32) || 'auto',
17
+ importantRanges: (input.importantRanges ?? [])
18
+ .filter((range) => Number.isFinite(range.startSecs) &&
19
+ Number.isFinite(range.endSecs) &&
20
+ range.startSecs >= 0 &&
21
+ range.endSecs > range.startSecs)
22
+ .slice(0, 20)
23
+ .map((range) => ({
24
+ startSecs: range.startSecs,
25
+ endSecs: range.endSecs,
26
+ note: range.note?.trim().slice(0, 500) || undefined,
27
+ })),
28
+ indexingMode,
29
+ processingAuthorityConfirmed: input.processingAuthorityConfirmed === true,
30
+ retainSourceHours,
31
+ };
32
+ }
33
+ function uniqueStrings(values, limit) {
34
+ return [...new Set((values ?? []).map((value) => value.trim()).filter(Boolean))]
35
+ .slice(0, limit)
36
+ .map((value) => value.slice(0, 500));
37
+ }
@@ -0,0 +1,46 @@
1
+ import type { SubmitVideoJobRequest, VideoIntelligenceClientContract, VideoJob, VideoRuntimeMode, VideoServiceEntitlement, VideoServiceUsage } from './contracts.js';
2
+ export interface VideoIntelligenceClientOptions {
3
+ mode: VideoRuntimeMode;
4
+ endpoint?: string;
5
+ apiKey?: string;
6
+ fetch?: typeof globalThis.fetch;
7
+ timeoutMs?: number;
8
+ }
9
+ export declare class VideoIntelligenceClient implements VideoIntelligenceClientContract {
10
+ private readonly mode;
11
+ private readonly endpoint;
12
+ private readonly fetcher;
13
+ private readonly apiKey?;
14
+ private readonly timeoutMs;
15
+ constructor(options: VideoIntelligenceClientOptions);
16
+ health(): Promise<{
17
+ status: string;
18
+ version: string;
19
+ operators: Record<string, string>;
20
+ }>;
21
+ provisionDeviceAccess(installationId: string): Promise<{
22
+ apiKey: string;
23
+ entitlement: VideoServiceEntitlement;
24
+ }>;
25
+ upload(file: Blob, fileName: string): Promise<{
26
+ uploadId: string;
27
+ }>;
28
+ submitJob(request: SubmitVideoJobRequest): Promise<VideoJob>;
29
+ getJob(jobId: string): Promise<VideoJob>;
30
+ acknowledgeJobResult(jobId: string): Promise<{
31
+ status: string;
32
+ }>;
33
+ cancelJob(jobId: string): Promise<VideoJob>;
34
+ purgeJobData(jobId: string): Promise<void>;
35
+ /** Recovery path for an orphaned local asset. The service refuses ambiguity. */
36
+ cancelOnlyActiveJob(): Promise<{
37
+ status: string;
38
+ alreadyStopped?: boolean;
39
+ }>;
40
+ getUsage(): Promise<VideoServiceUsage>;
41
+ redeemAccessCode(code: string): Promise<{
42
+ apiKey: string;
43
+ entitlement: VideoServiceEntitlement;
44
+ }>;
45
+ private request;
46
+ }
package/dist/client.js ADDED
@@ -0,0 +1,139 @@
1
+ export class VideoIntelligenceClient {
2
+ mode;
3
+ endpoint;
4
+ fetcher;
5
+ apiKey;
6
+ timeoutMs;
7
+ constructor(options) {
8
+ this.mode = options.mode;
9
+ const defaultEndpoint = options.mode === 'local-docker' || options.mode === 'local-process'
10
+ ? 'http://127.0.0.1:8787'
11
+ : undefined;
12
+ if (!options.endpoint && !defaultEndpoint) {
13
+ throw new Error(`An endpoint is required for ${options.mode}.`);
14
+ }
15
+ this.endpoint = (options.endpoint ?? defaultEndpoint).replace(/\/$/, '');
16
+ this.fetcher = options.fetch ?? globalThis.fetch;
17
+ this.apiKey = options.apiKey;
18
+ this.timeoutMs = options.timeoutMs ?? 30_000;
19
+ }
20
+ async health() {
21
+ const health = await this.request('/v1/health');
22
+ const isManagedCloudHealth = health.runtime === 'managed-cloud' && typeof health.processingEnabled === 'boolean';
23
+ if (health.status !== 'ok' ||
24
+ typeof health.version !== 'string' ||
25
+ !health.version ||
26
+ ((!health.operators || typeof health.operators !== 'object') && !isManagedCloudHealth)) {
27
+ throw new Error('The endpoint did not identify itself as a Video Intelligence runtime.');
28
+ }
29
+ return {
30
+ status: health.status,
31
+ version: health.version,
32
+ operators: health.operators ?? {},
33
+ };
34
+ }
35
+ provisionDeviceAccess(installationId) {
36
+ return this.request('/v1/device-keys', {
37
+ method: 'POST',
38
+ body: JSON.stringify({ installationId }),
39
+ anonymous: true,
40
+ });
41
+ }
42
+ async upload(file, fileName) {
43
+ if (this.mode === 'managed-cloud') {
44
+ const initialized = await this.request('/v1/uploads', {
45
+ method: 'POST',
46
+ body: JSON.stringify({
47
+ fileName,
48
+ contentType: file.type || 'application/octet-stream',
49
+ sizeBytes: file.size,
50
+ }),
51
+ });
52
+ const uploaded = await this.fetcher(initialized.uploadUrl, {
53
+ method: 'PUT',
54
+ headers: initialized.uploadHeaders,
55
+ body: file,
56
+ });
57
+ if (!uploaded.ok)
58
+ throw new Error(`Video upload returned HTTP ${uploaded.status}.`);
59
+ return { uploadId: initialized.uploadId };
60
+ }
61
+ const form = new FormData();
62
+ form.append('file', file, fileName);
63
+ return this.request('/v1/uploads', { method: 'POST', body: form });
64
+ }
65
+ submitJob(request) {
66
+ return this.request('/v1/jobs', { method: 'POST', body: JSON.stringify(request) });
67
+ }
68
+ async getJob(jobId) {
69
+ const job = await this.request(`/v1/jobs/${encodeURIComponent(jobId)}`);
70
+ if (job.status === 'completed' && !job.result && job.resultUrl) {
71
+ const response = await this.fetcher(job.resultUrl);
72
+ if (!response.ok)
73
+ throw new Error(`Video result returned HTTP ${response.status}.`);
74
+ job.result = (await response.json());
75
+ }
76
+ return job;
77
+ }
78
+ acknowledgeJobResult(jobId) {
79
+ return this.request(`/v1/jobs/${encodeURIComponent(jobId)}/result/ack`, {
80
+ method: 'POST',
81
+ body: JSON.stringify({}),
82
+ });
83
+ }
84
+ cancelJob(jobId) {
85
+ return this.request(`/v1/jobs/${encodeURIComponent(jobId)}`, { method: 'DELETE' });
86
+ }
87
+ async purgeJobData(jobId) {
88
+ await this.request(`/v1/jobs/${encodeURIComponent(jobId)}/data`, { method: 'DELETE' });
89
+ }
90
+ /** Recovery path for an orphaned local asset. The service refuses ambiguity. */
91
+ cancelOnlyActiveJob() {
92
+ return this.request('/v1/jobs/active', { method: 'DELETE' });
93
+ }
94
+ getUsage() {
95
+ return this.request('/v1/usage');
96
+ }
97
+ redeemAccessCode(code) {
98
+ return this.request('/v1/access-codes/redeem', {
99
+ method: 'POST',
100
+ body: JSON.stringify({ code }),
101
+ anonymous: true,
102
+ });
103
+ }
104
+ async request(path, init = {}) {
105
+ const headers = new Headers(init.headers);
106
+ if (!(init.body instanceof FormData))
107
+ headers.set('Content-Type', 'application/json');
108
+ if (this.apiKey && !init.anonymous)
109
+ headers.set('Authorization', `Bearer ${this.apiKey}`);
110
+ const canRetry = !init.method || init.method === 'GET';
111
+ for (let attempt = 0;; attempt += 1) {
112
+ const controller = new AbortController();
113
+ const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
114
+ try {
115
+ const response = await this.fetcher(`${this.endpoint}${path}`, {
116
+ ...init,
117
+ headers,
118
+ signal: controller.signal,
119
+ });
120
+ const body = (await response.json().catch(() => ({})));
121
+ const retryAfter = response.headers.get('Retry-After');
122
+ if (response.status === 429 && canRetry && attempt < 2 && retryAfter !== null) {
123
+ const retryAfterSeconds = Number(retryAfter);
124
+ await new Promise((resolve) => setTimeout(resolve, Number.isFinite(retryAfterSeconds)
125
+ ? Math.max(0, Math.min(60, retryAfterSeconds)) * 1_000
126
+ : 60_000));
127
+ continue;
128
+ }
129
+ if (!response.ok) {
130
+ throw new Error(body.detail ?? body.error ?? `Video service returned HTTP ${response.status}.`);
131
+ }
132
+ return body;
133
+ }
134
+ finally {
135
+ clearTimeout(timeout);
136
+ }
137
+ }
138
+ }
139
+ }
@@ -0,0 +1,331 @@
1
+ /**
2
+ * 'local' is the user-facing/config-level mode (auto-detects Docker vs.
3
+ * native). 'local-docker' and 'local-process' remain the concrete kinds
4
+ * runtime.ts executes against once detection resolves 'local' to one of them.
5
+ */
6
+ export type VideoRuntimeMode = 'local' | 'local-docker' | 'local-process' | 'managed-cloud' | 'custom-remote';
7
+ export type LocalVideoRuntimeKind = 'local-docker' | 'local-process';
8
+ export type VideoIndexingMode = 'fast' | 'balanced' | 'thorough';
9
+ /** Optional free-form source description; it never selects a fixed pipeline. */
10
+ export type VideoContentType = string;
11
+ export type VideoJobStatus = 'queued' | 'running' | 'completed' | 'failed' | 'cancelled';
12
+ export interface VideoIndexingBrief {
13
+ goal?: string;
14
+ contentType: VideoContentType;
15
+ knownEntities: string[];
16
+ expectedQuestions: string[];
17
+ language: string;
18
+ importantRanges: Array<{
19
+ startSecs: number;
20
+ endSecs: number;
21
+ note?: string;
22
+ }>;
23
+ indexingMode: VideoIndexingMode;
24
+ /** Confirms authority or another lawful basis; it is not necessarily GDPR consent. */
25
+ processingAuthorityConfirmed: boolean;
26
+ retainSourceHours: number;
27
+ /** The app supplies transcript evidence itself, so the cloud GPU skips speech decoding. */
28
+ skipTranscription?: boolean;
29
+ /** A bounded verification must retain its direct visual evidence source. */
30
+ requireSemanticVision?: boolean;
31
+ /** Reads the requested range as one chronology instead of independent clips. */
32
+ continuousSequence?: boolean;
33
+ /** Bounded visual budget chosen by the retrieval agent for this inspection. */
34
+ maxFrames?: number;
35
+ }
36
+ export interface VideoSource {
37
+ uploadId?: string;
38
+ path?: string;
39
+ objectKey?: string;
40
+ url?: string;
41
+ fileName?: string;
42
+ mimeType?: string;
43
+ /** Required by managed runtimes to reserve quota before a GPU worker starts. */
44
+ durationSecs?: number;
45
+ }
46
+ export interface VideoProviderModelCredential {
47
+ provider: string;
48
+ apiKey: string;
49
+ model: string;
50
+ }
51
+ /** User-owned providers required by the pipeline regardless of compute location. */
52
+ export interface VideoJobModelConfiguration {
53
+ audio: VideoProviderModelCredential;
54
+ brain: VideoProviderModelCredential;
55
+ vision: VideoProviderModelCredential;
56
+ }
57
+ export interface SubmitVideoJobRequest {
58
+ source: VideoSource;
59
+ brief: VideoIndexingBrief;
60
+ /** Ephemeral BYOK bundle. Cloud control planes must never persist or log it. */
61
+ modelConfiguration?: VideoJobModelConfiguration;
62
+ idempotencyKey?: string;
63
+ webhookUrl?: string;
64
+ }
65
+ export interface VideoJobProgress {
66
+ stage: 'queued' | 'prepare' | 'probe' | 'decode' | 'transcribe' | 'ocr' | 'detect' | 'synthesize' | 'complete';
67
+ /** Progress across the whole job, monotonic and smoothed by the runtime. */
68
+ percent: number;
69
+ message: string;
70
+ /**
71
+ * Progress through `stage` alone, for a host that renders one bar per step.
72
+ * The runtime owns the mapping because only it knows how much of the job
73
+ * each stage represents; a host that derived this itself would need a copy
74
+ * of that budget and would silently break whenever the pipeline changed.
75
+ */
76
+ stagePercent?: number;
77
+ /** Monotonic worker update id; changing this proves the pipeline is alive. */
78
+ sequence?: number;
79
+ elapsedSeconds?: number;
80
+ /** Adaptive whole-worker ETA, recalibrated from measured throughput. */
81
+ estimatedRemainingSeconds?: number;
82
+ current?: number;
83
+ total?: number;
84
+ unit?: string;
85
+ }
86
+ export interface VideoUsageSummary {
87
+ sourceMinutes: number;
88
+ decodedFrames: number;
89
+ retainedFrames: number;
90
+ ocrFrames: number;
91
+ detectorFrames: number;
92
+ gpuSeconds: number;
93
+ }
94
+ export interface VideoJob {
95
+ id: string;
96
+ status: VideoJobStatus;
97
+ createdAt: string;
98
+ updatedAt: string;
99
+ progress: VideoJobProgress;
100
+ estimatedSourceMinutes: number;
101
+ result: VideoEvidenceBundle | null;
102
+ resultUrl?: string | null;
103
+ error: string | null;
104
+ }
105
+ export interface TranscriptEvidence {
106
+ startMs: number;
107
+ endMs: number;
108
+ text: string;
109
+ words: Array<{
110
+ startMs: number;
111
+ endMs: number;
112
+ text: string;
113
+ confidence: number;
114
+ }>;
115
+ }
116
+ export interface OcrEvidence {
117
+ text: string;
118
+ confidence: number;
119
+ box: number[][];
120
+ }
121
+ export interface TrackEvidence {
122
+ trackId: number;
123
+ classId: number;
124
+ label: string;
125
+ startMs: number;
126
+ endMs: number;
127
+ observations: number;
128
+ confidence: number;
129
+ }
130
+ export interface VisualObservation {
131
+ timeMs: number;
132
+ objects: Array<{
133
+ label: string;
134
+ classId: number;
135
+ trackId: number;
136
+ confidence: number;
137
+ box: [number, number, number, number];
138
+ }>;
139
+ ocr: OcrEvidence[];
140
+ }
141
+ /**
142
+ * Short on-screen text that stayed legible across several frames -- a title,
143
+ * a caption, a heading, a readout. It marks where a display existed and when
144
+ * it changed, so it is a source-navigation anchor rather than a fact.
145
+ */
146
+ export interface RecurringOverlayText {
147
+ text: string;
148
+ firstSeenMs: number;
149
+ lastSeenMs: number;
150
+ observations: number;
151
+ timestampsMs: number[];
152
+ confidence: number;
153
+ }
154
+ export interface VideoEvidenceBundle {
155
+ schemaVersion: 1;
156
+ jobId: string;
157
+ durationMs: number;
158
+ video: {
159
+ width: number;
160
+ height: number;
161
+ fps: number;
162
+ };
163
+ brief: VideoIndexingBrief;
164
+ transcript: TranscriptEvidence[];
165
+ detectedLanguage?: string;
166
+ visualObservations: VisualObservation[];
167
+ tracks: TrackEvidence[];
168
+ recurringOverlayText?: RecurringOverlayText[];
169
+ entities: Array<{
170
+ name: string;
171
+ kind: 'object' | 'visible-text';
172
+ mentions: number;
173
+ timestampsMs?: number[];
174
+ confidence?: number;
175
+ }>;
176
+ coverage: {
177
+ requested: VideoIndexingMode;
178
+ sourceFrames?: number;
179
+ decodedFrames: number;
180
+ analyzedFrames: number;
181
+ heavyOperatorsDisabled: boolean;
182
+ priorityRanges?: Array<{
183
+ startSecs: number;
184
+ endSecs: number;
185
+ reason: string;
186
+ }>;
187
+ semanticClips?: number;
188
+ };
189
+ agentPlan?: {
190
+ mode: VideoIndexingMode;
191
+ summary: string;
192
+ extractionFocus: string[];
193
+ useTranscript: boolean;
194
+ useOcr: boolean;
195
+ useObjectDetection: boolean;
196
+ useSemanticVision: boolean;
197
+ useVideoEmbeddings: boolean;
198
+ useSceneCuts: boolean;
199
+ sampleIntervalSecs: number;
200
+ prioritySampleIntervalSecs: number;
201
+ clipWindowSecs: number;
202
+ framesPerClip: number;
203
+ priorityRanges: Array<{
204
+ startSecs: number;
205
+ endSecs: number;
206
+ reason: string;
207
+ }>;
208
+ estimatedSeconds: number;
209
+ };
210
+ agentDiagnostics?: {
211
+ attempted: boolean;
212
+ provider: string;
213
+ model: string;
214
+ requests: number;
215
+ latencyMs: number;
216
+ fallback: boolean;
217
+ error?: string | null;
218
+ promptTokens?: number;
219
+ completionTokens?: number;
220
+ };
221
+ processingDiagnostics?: {
222
+ estimatedTotalSeconds: number;
223
+ elapsedSeconds: number;
224
+ estimateErrorSeconds: number;
225
+ };
226
+ transcriptionDiagnostics?: {
227
+ provider?: string | null;
228
+ fallbackProvider?: string | null;
229
+ fallbackUsed?: boolean;
230
+ chunkCount?: number;
231
+ completedChunks?: number;
232
+ chunkErrors?: number;
233
+ error?: string | null;
234
+ };
235
+ knowledgeSummary?: {
236
+ overview: string;
237
+ participants: Array<{
238
+ name: string;
239
+ role: string;
240
+ evidence: Array<{
241
+ startMs: number;
242
+ endMs: number;
243
+ }>;
244
+ }>;
245
+ stateHistory: Array<{
246
+ startMs: number;
247
+ endMs: number;
248
+ state: string;
249
+ confidence: 'direct' | 'partial';
250
+ }>;
251
+ keyEvents: Array<{
252
+ startMs: number;
253
+ endMs: number;
254
+ event: string;
255
+ confidence: 'direct' | 'partial';
256
+ }>;
257
+ narrative?: Array<{
258
+ startMs: number;
259
+ endMs: number;
260
+ text: string;
261
+ confidence: 'direct' | 'partial';
262
+ }>;
263
+ context: Array<{
264
+ fact: string;
265
+ evidence: Array<{
266
+ startMs: number;
267
+ endMs: number;
268
+ }>;
269
+ }>;
270
+ sourceItems?: Array<{
271
+ kind: 'question' | 'heading' | 'slide-item' | 'board-item' | 'list-item';
272
+ channel: 'spoken' | 'visible';
273
+ text: string;
274
+ answer: string;
275
+ startMs: number;
276
+ endMs: number;
277
+ }>;
278
+ uncertainties: string[];
279
+ };
280
+ answeringGuide: {
281
+ goal?: string;
282
+ importantEntities: string[];
283
+ questionsToPrepareFor: string[];
284
+ extractionFocus?: string[];
285
+ instruction: string;
286
+ };
287
+ }
288
+ export interface VideoServiceEntitlement {
289
+ plan: string;
290
+ sourceMinutesPerMonth: number | null;
291
+ maxConcurrentJobs: number;
292
+ }
293
+ export interface VideoServiceUsage {
294
+ periodStart: string;
295
+ periodEnd: string;
296
+ sourceMinutesUsed: number;
297
+ sourceMinutesLimit: number | null;
298
+ activeJobs: number;
299
+ /** Exact active jobs allow a host to recover only its own orphaned asset. */
300
+ activeJobIds?: string[];
301
+ concurrentJobsLimit: number;
302
+ }
303
+ export interface VideoIntelligenceClientContract {
304
+ health(): Promise<{
305
+ status: string;
306
+ version: string;
307
+ operators: Record<string, string>;
308
+ }>;
309
+ /** Creates or rotates the opaque cloud credential for one local Larkup installation. */
310
+ provisionDeviceAccess(installationId: string): Promise<{
311
+ apiKey: string;
312
+ entitlement: VideoServiceEntitlement;
313
+ }>;
314
+ upload(file: Blob, fileName: string): Promise<{
315
+ uploadId: string;
316
+ }>;
317
+ submitJob(request: SubmitVideoJobRequest): Promise<VideoJob>;
318
+ getJob(jobId: string): Promise<VideoJob>;
319
+ /** Deletes the temporary encrypted result after the caller has validated it. */
320
+ acknowledgeJobResult(jobId: string): Promise<{
321
+ status: string;
322
+ }>;
323
+ cancelJob(jobId: string): Promise<VideoJob>;
324
+ /** Removes a local runtime's durable source/result cache for a deleted asset. */
325
+ purgeJobData(jobId: string): Promise<void>;
326
+ getUsage(): Promise<VideoServiceUsage>;
327
+ redeemAccessCode(code: string): Promise<{
328
+ apiKey: string;
329
+ entitlement: VideoServiceEntitlement;
330
+ }>;
331
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,87 @@
1
+ import { type VideoIntelligenceAgentClient } from './agent.js';
2
+ import type { LocalVideoRuntimeKind } from './contracts.js';
3
+ export * from './brief.js';
4
+ export * from './agent.js';
5
+ export * from './client.js';
6
+ export * from './contracts.js';
7
+ export * from './runtime.js';
8
+ export * from './ui.js';
9
+ export declare const TOOL_META: {
10
+ readonly id: "video-intelligence";
11
+ readonly name: "Video Intelligence";
12
+ readonly version: "0.1.0";
13
+ };
14
+ export declare const TOOL_EXTENSION: {
15
+ id: "video-intelligence";
16
+ apiVersion: "1";
17
+ createClient: typeof createClientFromContext;
18
+ ensureRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<void>;
19
+ restartRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<void>;
20
+ /** Pulls the Docker image or installs uv + syncs Python deps, without starting anything. */
21
+ installRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<void>;
22
+ stopRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<void>;
23
+ verifyConfiguration(context: import("@larkup/marketplace/extension").ToolExtensionContext & {
24
+ verifyKey?: string;
25
+ }): Promise<void>;
26
+ removeRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<void>;
27
+ /** Docker/native detection, system suitability, and AI-model availability for the Install alert. */
28
+ getHostCapabilities(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<{
29
+ running: boolean;
30
+ gatewayKeyAvailable: boolean;
31
+ gatewayKeySource: string | null;
32
+ modelRequirement: {
33
+ configured: boolean;
34
+ message: string;
35
+ provider?: undefined;
36
+ model?: undefined;
37
+ } | {
38
+ configured: boolean;
39
+ provider: string | undefined;
40
+ model: string;
41
+ message: string;
42
+ };
43
+ docker: import("./runtime.js").DockerHostStatus;
44
+ native: import("./runtime.js").NativeHostStatus;
45
+ recommendedKind: LocalVideoRuntimeKind | null;
46
+ installed: boolean;
47
+ system: {
48
+ platform: NodeJS.Platform;
49
+ cpus: number;
50
+ totalMemGB: number;
51
+ freeMemGB: number;
52
+ };
53
+ acceleration: import("./runtime.js").LocalAcceleration;
54
+ suitability: {
55
+ level: "good" | "tight" | "unknown";
56
+ message: string;
57
+ };
58
+ }>;
59
+ provisionRuntime(context: import("@larkup/marketplace/extension").ToolExtensionContext): Promise<{
60
+ config: {
61
+ cloudInstallationId?: undefined;
62
+ cloudAccessKey?: undefined;
63
+ };
64
+ display?: undefined;
65
+ } | {
66
+ config: {
67
+ cloudInstallationId?: undefined;
68
+ cloudAccessKey?: undefined;
69
+ };
70
+ display: {
71
+ userId: string;
72
+ };
73
+ } | {
74
+ config: {
75
+ cloudInstallationId: string;
76
+ cloudAccessKey: string;
77
+ };
78
+ display: {
79
+ userId: string;
80
+ };
81
+ }>;
82
+ };
83
+ export default TOOL_EXTENSION;
84
+ declare function createClientFromContext(context: {
85
+ config: Record<string, unknown>;
86
+ fetch?: typeof globalThis.fetch;
87
+ }): VideoIntelligenceAgentClient;