@slatesvideo/shared 0.4.5 → 0.4.6
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/operations/index.d.ts +7 -1
- package/dist/operations/index.js +93 -13
- package/package.json +1 -1
|
@@ -25,7 +25,9 @@ export declare const getWorkspaceState: Operation<{
|
|
|
25
25
|
}>;
|
|
26
26
|
export declare const getMe: Operation<Record<string, never>>;
|
|
27
27
|
export declare const getCreditBalance: Operation<Record<string, never>>;
|
|
28
|
-
export declare const listAvailableModels: Operation<
|
|
28
|
+
export declare const listAvailableModels: Operation<{
|
|
29
|
+
filter?: string;
|
|
30
|
+
}>;
|
|
29
31
|
export declare const estimateGenerationCost: Operation<{
|
|
30
32
|
model: string;
|
|
31
33
|
quantity?: number;
|
|
@@ -39,6 +41,9 @@ export declare const getProject: Operation<{
|
|
|
39
41
|
}>;
|
|
40
42
|
export declare const listAssets: Operation<{
|
|
41
43
|
projectId: string;
|
|
44
|
+
type?: 'image' | 'video' | 'audio';
|
|
45
|
+
search?: string;
|
|
46
|
+
limit?: number;
|
|
42
47
|
}>;
|
|
43
48
|
export declare const getAssetImage: Operation<{
|
|
44
49
|
id: string;
|
|
@@ -216,6 +221,7 @@ export declare const generateMotionTransfer: Operation<{
|
|
|
216
221
|
}>;
|
|
217
222
|
export declare const getGenerationStatus: Operation<{
|
|
218
223
|
generationId: string;
|
|
224
|
+
waitSeconds?: number;
|
|
219
225
|
}>;
|
|
220
226
|
export declare const listGenerations: Operation<{
|
|
221
227
|
projectId?: string;
|
package/dist/operations/index.js
CHANGED
|
@@ -22,7 +22,9 @@ export function defaultContext() {
|
|
|
22
22
|
// ── Helpers ─────────────────────────────────────────────────────
|
|
23
23
|
function ok(data, text) {
|
|
24
24
|
return {
|
|
25
|
-
|
|
25
|
+
// Compact JSON — pretty-printing (indent 2) cost ~10-15% extra tokens
|
|
26
|
+
// on every tool result the calling LLM reads.
|
|
27
|
+
text: text ?? JSON.stringify(data),
|
|
26
28
|
data,
|
|
27
29
|
};
|
|
28
30
|
}
|
|
@@ -77,11 +79,25 @@ export const getCreditBalance = {
|
|
|
77
79
|
};
|
|
78
80
|
export const listAvailableModels = {
|
|
79
81
|
id: 'slates_list_available_models',
|
|
80
|
-
description: '
|
|
81
|
-
input: z.object({
|
|
82
|
-
|
|
82
|
+
description: 'Registry of generation model cost keys with per-call credit cost in cents, as a compact "key cents" table. Optional `filter` substring (e.g. "kling" or "nano-banana") keeps the result small — prefer it. For a single known model, slates_estimate_generation_cost is cheaper still.',
|
|
83
|
+
input: z.object({
|
|
84
|
+
filter: z.string().optional().describe('Substring match on the model key, e.g. "kling-v3" or "seedance"'),
|
|
85
|
+
}),
|
|
86
|
+
async run(input, ctx) {
|
|
83
87
|
const r = await ctx.cloud().get('/api/agent/models');
|
|
84
|
-
|
|
88
|
+
let models = r.models;
|
|
89
|
+
if (input.filter) {
|
|
90
|
+
const q = input.filter.toLowerCase();
|
|
91
|
+
models = models.filter((m) => m.model.toLowerCase().includes(q));
|
|
92
|
+
}
|
|
93
|
+
// Compact text table — "key cents" lines are ~5x denser than the raw
|
|
94
|
+
// JSON registry (the full pretty-printed dump was an ~8k-token leak).
|
|
95
|
+
const table = models.map((m) => `${m.model} ${m.cost_cents}`).join('\n');
|
|
96
|
+
return {
|
|
97
|
+
text: `${models.length} model cost keys (cents per generation)${input.filter ? ` matching "${input.filter}"` : ''}:\n` +
|
|
98
|
+
table,
|
|
99
|
+
data: { count: models.length, credit_markup: r.credit_markup },
|
|
100
|
+
};
|
|
85
101
|
},
|
|
86
102
|
};
|
|
87
103
|
export const estimateGenerationCost = {
|
|
@@ -138,15 +154,56 @@ export const getProject = {
|
|
|
138
154
|
},
|
|
139
155
|
};
|
|
140
156
|
// ── Assets ──────────────────────────────────────────────────────
|
|
157
|
+
/** Compact projection of a raw asset row — the full row (prompt, settings,
|
|
158
|
+
* paths, thumbnails) is 20-50x heavier and was the single biggest context
|
|
159
|
+
* leak in early agent sessions (494 assets ≈ 130KB ≈ 33k tokens in ONE
|
|
160
|
+
* tool result). Every op that embeds asset lists uses this. */
|
|
161
|
+
function compactAsset(a) {
|
|
162
|
+
const r = a;
|
|
163
|
+
const prompt = typeof r.prompt === 'string' ? r.prompt : '';
|
|
164
|
+
return {
|
|
165
|
+
id: r.id,
|
|
166
|
+
code: r.code ?? null,
|
|
167
|
+
label: r.label ?? (prompt ? prompt.slice(0, 40) : null),
|
|
168
|
+
type: r.type,
|
|
169
|
+
created_at: r.createdAt ?? r.created_at ?? undefined,
|
|
170
|
+
};
|
|
171
|
+
}
|
|
141
172
|
export const listAssets = {
|
|
142
173
|
id: 'slates_list_assets',
|
|
143
|
-
description: 'List
|
|
144
|
-
input: z.object({
|
|
174
|
+
description: 'List assets in a Slates project as COMPACT rows (id, code, label, type) — newest first, default limit 50. Each asset carries its short code (IMG-A12 / VID-V3 / AUD-S1 — the badge the user sees on the gallery card) and label. When the user names an asset by code ("use IMG-A36 as the reference"), pass it as `search` to resolve the assetId. Always speak about assets by code + label, never by UUID. NOTE: generate_* results already return the new asset ids — do NOT call this to find an asset you just created.',
|
|
175
|
+
input: z.object({
|
|
176
|
+
projectId: z.string().uuid(),
|
|
177
|
+
type: z.enum(['image', 'video', 'audio']).optional().describe('Only this asset type'),
|
|
178
|
+
search: z.string().optional().describe('Case-insensitive match on code or label (e.g. "IMG-A36" or "sunset")'),
|
|
179
|
+
limit: z.number().int().min(1).max(500).optional().describe('Max rows (default 50, newest first)'),
|
|
180
|
+
}),
|
|
145
181
|
async run(input, ctx) {
|
|
146
182
|
const r = await ctx.desktop().get('/agent/assets', {
|
|
147
183
|
projectId: input.projectId,
|
|
148
184
|
});
|
|
149
|
-
|
|
185
|
+
const all = (r.assets ?? []).map(compactAsset);
|
|
186
|
+
let rows = all;
|
|
187
|
+
if (input.type)
|
|
188
|
+
rows = rows.filter((a) => a.type === input.type);
|
|
189
|
+
if (input.search) {
|
|
190
|
+
const q = input.search.toLowerCase();
|
|
191
|
+
rows = rows.filter((a) => String(a.code ?? '').toLowerCase().includes(q) ||
|
|
192
|
+
String(a.label ?? '').toLowerCase().includes(q));
|
|
193
|
+
}
|
|
194
|
+
// Newest first, then cap. (created_at is ISO — lexicographic sort works.)
|
|
195
|
+
rows = rows
|
|
196
|
+
.slice()
|
|
197
|
+
.sort((a, b) => String(b.created_at ?? '').localeCompare(String(a.created_at ?? '')));
|
|
198
|
+
const limit = input.limit ?? 50;
|
|
199
|
+
const truncated = rows.length > limit;
|
|
200
|
+
rows = rows.slice(0, limit);
|
|
201
|
+
return ok({
|
|
202
|
+
total_matching: truncated ? undefined : rows.length,
|
|
203
|
+
total_in_project: all.length,
|
|
204
|
+
truncated,
|
|
205
|
+
assets: rows.map(({ created_at: _drop, ...rest }) => rest),
|
|
206
|
+
});
|
|
150
207
|
},
|
|
151
208
|
};
|
|
152
209
|
export const getAssetImage = {
|
|
@@ -760,7 +817,10 @@ export const generateImage = {
|
|
|
760
817
|
resolution,
|
|
761
818
|
cost_cents: totalCents,
|
|
762
819
|
cost_dollars: (totalCents / 100).toFixed(2),
|
|
763
|
-
|
|
820
|
+
// Compact refs only — the full rows (prompt/settings/paths) were a
|
|
821
|
+
// multi-KB leak per generation and everything needed downstream is
|
|
822
|
+
// the id/code/label.
|
|
823
|
+
assets: assetList.map(compactAsset),
|
|
764
824
|
generationIds: result.generationIds ?? (result.generationId ? [result.generationId] : []),
|
|
765
825
|
...(partialFailure
|
|
766
826
|
? { partial: true, error: result.error ?? 'unknown error', requested_count: requestedCount }
|
|
@@ -1455,12 +1515,31 @@ export const generateMotionTransfer = {
|
|
|
1455
1515
|
// ── Generation status (background mode) ─────────────────────────
|
|
1456
1516
|
export const getGenerationStatus = {
|
|
1457
1517
|
id: 'slates_get_generation_status',
|
|
1458
|
-
description: 'Poll one generation by id. Returns status (pending/processing/completed/failed/cancelled), the error message on failure, and the finished asset record (with id, code, filePath) on completion. Use after submitting any generate_* op with background=true
|
|
1459
|
-
input: z.object({
|
|
1518
|
+
description: 'Poll one generation by id. Returns status (pending/processing/completed/failed/cancelled), the error message on failure, and the finished asset record (with id, code, filePath) on completion. Use after submitting any generate_* op with background=true. ALWAYS pass waitSeconds (use 45) — the call long-polls internally and returns early the moment the generation reaches a terminal state, so ONE call replaces a dozen rapid polls (each poll turn re-reads your whole context; rapid polling is the #1 orchestration-cost leak). Video generations commonly take 1-5 minutes: expect 1-4 long-poll calls, never a tight loop. Generations survive app restarts (the desktop resumes in-flight provider jobs on boot).',
|
|
1519
|
+
input: z.object({
|
|
1520
|
+
generationId: z.string().uuid(),
|
|
1521
|
+
waitSeconds: z
|
|
1522
|
+
.number()
|
|
1523
|
+
.int()
|
|
1524
|
+
.min(0)
|
|
1525
|
+
.max(50)
|
|
1526
|
+
.optional()
|
|
1527
|
+
.describe('Long-poll: block up to N seconds, returning early on completion/failure. Use 45.'),
|
|
1528
|
+
}),
|
|
1460
1529
|
async run(input, ctx) {
|
|
1461
1530
|
const desktop = ctx.desktop();
|
|
1462
1531
|
await desktop.requireCapability('background-generation', 'background generation');
|
|
1463
|
-
|
|
1532
|
+
const deadline = Date.now() + Math.min(Math.max(input.waitSeconds ?? 0, 0), 50) * 1000;
|
|
1533
|
+
for (;;) {
|
|
1534
|
+
const r = await desktop.get('/agent/generation/status', {
|
|
1535
|
+
id: input.generationId,
|
|
1536
|
+
});
|
|
1537
|
+
const status = r.status;
|
|
1538
|
+
const terminal = status === 'completed' || status === 'failed' || status === 'cancelled';
|
|
1539
|
+
if (terminal || Date.now() >= deadline)
|
|
1540
|
+
return ok(r);
|
|
1541
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(3000, deadline - Date.now())));
|
|
1542
|
+
}
|
|
1464
1543
|
},
|
|
1465
1544
|
};
|
|
1466
1545
|
export const listGenerations = {
|
|
@@ -1477,7 +1556,8 @@ export const listGenerations = {
|
|
|
1477
1556
|
return ok(await desktop.get('/agent/generation/list', {
|
|
1478
1557
|
projectId: input.projectId,
|
|
1479
1558
|
status: input.status,
|
|
1480
|
-
|
|
1559
|
+
// Default cap — an unbounded history dump is a context leak.
|
|
1560
|
+
limit: input.limit ?? 20,
|
|
1481
1561
|
}));
|
|
1482
1562
|
},
|
|
1483
1563
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slatesvideo/shared",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
4
4
|
"description": "Shared operations layer for the Slates MCP server and CLI: auth, cloud/desktop clients, and the single tool surface both consume. Most users want @slatesvideo/mcp-server or @slatesvideo/cli instead.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|