@slatesvideo/shared 0.6.2 → 0.6.4

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 (77) hide show
  1. package/dist/api-url.d.ts +9 -0
  2. package/dist/api-url.js +9 -0
  3. package/dist/auth.d.ts +13 -1
  4. package/dist/auth.js +9 -5
  5. package/dist/clients/cloud.d.ts +3 -0
  6. package/dist/clients/cloud.js +34 -3
  7. package/dist/clients/desktop.js +3 -0
  8. package/dist/index.d.ts +8 -2
  9. package/dist/index.js +44 -1
  10. package/dist/operations/index.d.ts +243 -31
  11. package/dist/operations/index.js +1483 -154
  12. package/dist/operations/surface.d.ts +69 -0
  13. package/dist/operations/surface.js +227 -0
  14. package/dist/prompts/agent-doctrine.d.ts +36 -0
  15. package/dist/prompts/agent-doctrine.js +201 -0
  16. package/dist/prompts/asset-label.d.ts +23 -0
  17. package/dist/prompts/asset-label.js +70 -0
  18. package/dist/prompts/banned-tokens.d.ts +40 -0
  19. package/dist/prompts/banned-tokens.js +219 -0
  20. package/dist/prompts/character-sheet.d.ts +0 -2
  21. package/dist/prompts/character-sheet.js +0 -2
  22. package/dist/prompts/craft-cards.d.ts +20 -0
  23. package/dist/prompts/craft-cards.js +82 -0
  24. package/dist/prompts/environment-sheet.js +16 -0
  25. package/dist/prompts/index.d.ts +1 -0
  26. package/dist/prompts/index.js +4 -0
  27. package/dist/prompts/model-capabilities.d.ts +65 -1
  28. package/dist/prompts/model-capabilities.js +139 -2
  29. package/dist/prompts/model-facts.d.ts +20 -4
  30. package/dist/prompts/model-facts.js +95 -27
  31. package/dist/prompts/partials.generated.js +2 -1
  32. package/dist/prompts/prompting-tips.d.ts +1 -1
  33. package/dist/prompts/prompting-tips.js +123 -0
  34. package/dist/prompts/reference-composer.d.ts +36 -7
  35. package/dist/prompts/reference-composer.js +75 -20
  36. package/dist/prompts/reference-rules.d.ts +15 -26
  37. package/dist/prompts/reference-rules.js +15 -93
  38. package/dist/prompts/shot-grammar.d.ts +154 -0
  39. package/dist/prompts/shot-grammar.js +184 -0
  40. package/dist/prompts/shot-spec.d.ts +265 -0
  41. package/dist/prompts/shot-spec.js +303 -0
  42. package/dist/skills/content.js +25 -22
  43. package/exports/slates-prompt-builder/generated/SKILL.md +3 -3
  44. package/exports/slates-prompt-builder/generated/reference-content-policy.md +6 -0
  45. package/exports/slates-prompt-builder/generated/reference-kling.md +22 -0
  46. package/exports/slates-prompt-builder/generated/reference-nano-banana.md +17 -0
  47. package/exports/slates-prompt-builder/generated/reference-seedance.md +19 -1
  48. package/exports/slates-prompt-builder/generated/slates-prompt-builder-manifest.json +17 -17
  49. package/exports/slates-prompt-builder/generated/slates-prompt-builder.skill +0 -0
  50. package/package.json +83 -73
  51. package/skills/_partials/decision-log.md +5 -4
  52. package/skills/_partials/thresholds.md +19 -0
  53. package/skills/slates-content-policy.md +15 -1
  54. package/skills/slates-cost-discipline.md +26 -4
  55. package/skills/slates-model-selection.md +2 -2
  56. package/skills/slates-one-prompt-film.md +20 -12
  57. package/skills/slates-project-organization.md +1 -1
  58. package/skills/slates-prompting-elevenlabs.md +61 -2
  59. package/skills/slates-prompting-flux-2-max.md +39 -0
  60. package/skills/slates-prompting-gpt-image-2.md +109 -70
  61. package/skills/slates-prompting-inworld-tts.md +166 -0
  62. package/skills/slates-prompting-kling-v3.md +39 -0
  63. package/skills/slates-prompting-lip-sync.md +38 -0
  64. package/skills/slates-prompting-ltx-2-5.md +218 -0
  65. package/skills/slates-prompting-minimax-h3.md +39 -0
  66. package/skills/slates-prompting-motion-transfer.md +38 -0
  67. package/skills/slates-prompting-nano-banana-2.md +36 -0
  68. package/skills/slates-prompting-omni-flash.md +41 -0
  69. package/skills/slates-prompting-seed-audio.md +38 -0
  70. package/skills/slates-prompting-seedance-2-5.md +38 -0
  71. package/skills/slates-prompting-seedance.md +36 -1
  72. package/skills/slates-prompting-seedream-5-lite.md +38 -0
  73. package/skills/slates-prompting-veo-3.md +39 -0
  74. package/skills/slates-shot-variety.md +53 -0
  75. package/skills/slates-storyboard-from-script.md +31 -15
  76. package/skills/slates-style-prompting.md +1 -1
  77. package/skills/slates-vision-feedback-loop.md +1 -1
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The production API host. The one literal in the portfolio; every client
3
+ * imports it (the MCP cloud client, the CLI login, and the desktop once its
4
+ * `@slatesvideo/shared` dependency is bumped to a version carrying it).
5
+ * Kept in its own module so `clients/cloud.ts` can import it without a cycle
6
+ * through the barrel.
7
+ */
8
+ export declare const SLATES_API_URL = "https://slates-api.fly.dev";
9
+ //# sourceMappingURL=api-url.d.ts.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The production API host. The one literal in the portfolio; every client
3
+ * imports it (the MCP cloud client, the CLI login, and the desktop once its
4
+ * `@slatesvideo/shared` dependency is bumped to a version carrying it).
5
+ * Kept in its own module so `clients/cloud.ts` can import it without a cycle
6
+ * through the barrel.
7
+ */
8
+ export const SLATES_API_URL = 'https://slates-api.fly.dev';
9
+ //# sourceMappingURL=api-url.js.map
package/dist/auth.d.ts CHANGED
@@ -9,12 +9,24 @@ export interface AgentConnectionFile {
9
9
  port: number | null;
10
10
  token: string | null;
11
11
  };
12
+ /**
13
+ * The project `slates use` selected, filled into any op that takes
14
+ * `projectId` and was called without one.
15
+ *
16
+ * 🚨 CLI-OWNED, AND ONLY A DEFAULT. The desktop app owns the `desktop` half
17
+ * of this file and must never write here; an explicit `--projectId` always
18
+ * wins. It exists because every workspace op takes a UUID and an agent had to
19
+ * carry that UUID through the whole session by hand — which is exactly the
20
+ * kind of state a shell session is bad at holding.
21
+ */
22
+ defaultProjectId?: string | null;
12
23
  }
13
24
  export declare function readConnection(): AgentConnectionFile;
25
+ export declare function setDefaultProjectId(projectId: string | null): void;
26
+ export declare function readDefaultProjectId(): string | null;
14
27
  export declare function writeConnection(data: AgentConnectionFile): void;
15
28
  export declare function setCloudToken(token: string | null): void;
16
29
  export declare function clearCloudToken(): void;
17
- export declare function deleteConnection(): void;
18
30
  export declare class MissingCloudTokenError extends Error {
19
31
  code: string;
20
32
  constructor();
package/dist/auth.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { homedir } from 'node:os';
2
2
  import { join } from 'node:path';
3
- import { existsSync, readFileSync, writeFileSync, mkdirSync, unlinkSync, } from 'node:fs';
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync, } from 'node:fs';
4
4
  // Reads/writes ~/.slates/agent-connection.json — the single file the
5
5
  // Slates desktop app produces and the MCP/CLI consume.
6
6
  //
@@ -14,6 +14,7 @@ export const CONNECTION_FILE = join(AGENT_DIR, 'agent-connection.json');
14
14
  const EMPTY = {
15
15
  cloud: { token: null },
16
16
  desktop: { enabled: false, port: null, token: null },
17
+ defaultProjectId: null,
17
18
  };
18
19
  export function readConnection() {
19
20
  if (!existsSync(CONNECTION_FILE))
@@ -27,12 +28,19 @@ export function readConnection() {
27
28
  port: parsed.desktop?.port ?? null,
28
29
  token: parsed.desktop?.token ?? null,
29
30
  },
31
+ defaultProjectId: parsed.defaultProjectId ?? null,
30
32
  };
31
33
  }
32
34
  catch {
33
35
  return { ...EMPTY, cloud: { ...EMPTY.cloud }, desktop: { ...EMPTY.desktop } };
34
36
  }
35
37
  }
38
+ export function setDefaultProjectId(projectId) {
39
+ writeConnection({ ...readConnection(), defaultProjectId: projectId });
40
+ }
41
+ export function readDefaultProjectId() {
42
+ return readConnection().defaultProjectId ?? null;
43
+ }
36
44
  export function writeConnection(data) {
37
45
  if (!existsSync(AGENT_DIR))
38
46
  mkdirSync(AGENT_DIR, { recursive: true });
@@ -48,10 +56,6 @@ export function setCloudToken(token) {
48
56
  export function clearCloudToken() {
49
57
  setCloudToken(null);
50
58
  }
51
- export function deleteConnection() {
52
- if (existsSync(CONNECTION_FILE))
53
- unlinkSync(CONNECTION_FILE);
54
- }
55
59
  export class MissingCloudTokenError extends Error {
56
60
  code = 'CLOUD_TOKEN_MISSING';
57
61
  constructor() {
@@ -5,6 +5,9 @@ export declare class SlatesCloudClient {
5
5
  constructor(token?: string, baseUrl?: string);
6
6
  get<T>(path: string): Promise<T>;
7
7
  post<T>(path: string, body: unknown): Promise<T>;
8
+ /** Name the op's own path in the failure — "fetch failed" tells nobody which
9
+ * call died, and a timeout must not read as a network outage. */
10
+ private fetchOrFriendly;
8
11
  private handle;
9
12
  }
10
13
  export interface SlatesUserInfo {
@@ -1,5 +1,6 @@
1
1
  import { requireCloudToken } from '../auth.js';
2
- const FALLBACK_CLOUD_BASE_URL = 'https://slates-api.fly.dev';
2
+ import { SLATES_API_URL } from '../api-url.js';
3
+ const FALLBACK_CLOUD_BASE_URL = SLATES_API_URL;
3
4
  // The slates_sk_ bearer is attached to every cloud request. SLATES_CLOUD_BASE_URL
4
5
  // may override the host for dev/staging, but ONLY over https (or http to
5
6
  // localhost) — otherwise the token could be exfiltrated to an arbitrary host
@@ -27,6 +28,18 @@ export const DEFAULT_CLOUD_BASE_URL = resolveCloudBaseUrl();
27
28
  // Thin client for slates-api. Used for credit-aware ops that route through
28
29
  // the user's account (generation proxy, credits balance, model registry,
29
30
  // license checks). The desktop client below is the local equivalent.
31
+ /**
32
+ * 🚨 CLOUD REQUESTS HAD NO TIMEOUT AT ALL. A hung read hung the CLI forever and
33
+ * hung a Studio Agent tool call with it — no error, no retry, no way for the
34
+ * loop to notice. `fetch` has no default deadline; the desktop client at least
35
+ * inherited undici's 300s headers timeout.
36
+ *
37
+ * Two values, because two different things are being waited for: a registry or
38
+ * balance read that takes 30s is broken, while a generation SUBMIT legitimately
39
+ * waits on a provider queue.
40
+ */
41
+ const CLOUD_READ_TIMEOUT_MS = 30_000;
42
+ const CLOUD_SUBMIT_TIMEOUT_MS = 120_000;
30
43
  export class SlatesCloudClient {
31
44
  token;
32
45
  baseUrl;
@@ -35,22 +48,40 @@ export class SlatesCloudClient {
35
48
  this.baseUrl = baseUrl;
36
49
  }
37
50
  async get(path) {
38
- const res = await fetch(`${this.baseUrl}${path}`, {
51
+ const res = await this.fetchOrFriendly(path, `${this.baseUrl}${path}`, {
39
52
  headers: { Authorization: `Bearer ${this.token}` },
53
+ signal: AbortSignal.timeout(CLOUD_READ_TIMEOUT_MS),
40
54
  });
41
55
  return this.handle(path, res);
42
56
  }
43
57
  async post(path, body) {
44
- const res = await fetch(`${this.baseUrl}${path}`, {
58
+ const res = await this.fetchOrFriendly(path, `${this.baseUrl}${path}`, {
45
59
  method: 'POST',
46
60
  headers: {
47
61
  'Content-Type': 'application/json',
48
62
  Authorization: `Bearer ${this.token}`,
49
63
  },
50
64
  body: JSON.stringify(body),
65
+ signal: AbortSignal.timeout(CLOUD_SUBMIT_TIMEOUT_MS),
51
66
  });
52
67
  return this.handle(path, res);
53
68
  }
69
+ /** Name the op's own path in the failure — "fetch failed" tells nobody which
70
+ * call died, and a timeout must not read as a network outage. */
71
+ async fetchOrFriendly(path, url, init) {
72
+ try {
73
+ return await fetch(url, init);
74
+ }
75
+ catch (err) {
76
+ const name = err?.name;
77
+ if (name === 'TimeoutError' || name === 'AbortError') {
78
+ throw new Error(`slates-api ${path} timed out. The request may still have been received — ` +
79
+ `check before retrying anything that spends credits.`);
80
+ }
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ throw new Error(`slates-api ${path} could not be reached: ${message}`, { cause: err });
83
+ }
84
+ }
54
85
  async handle(path, res) {
55
86
  const text = await res.text();
56
87
  let parsed = null;
@@ -137,6 +137,9 @@ export class SlatesDesktopClient {
137
137
  // keep the full url
138
138
  }
139
139
  const message = err instanceof Error ? err.message : String(err);
140
+ // The ROUTE is in the message. "slates-desktop request failed" told the
141
+ // caller nothing about which of thirty-odd routes died, and a blocking
142
+ // render and a project list fail very differently.
140
143
  throw new Error(`slates-desktop request to ${path} failed: ${message}`, { cause: err });
141
144
  }
142
145
  }
package/dist/index.d.ts CHANGED
@@ -3,8 +3,14 @@ export { SlatesCloudClient, type SlatesUserInfo, type CreditsBalance, type Model
3
3
  export { SlatesDesktopClient, type DesktopHealth } from './clients/desktop.js';
4
4
  export { SKILLS } from './skills/content.js';
5
5
  export * as operations from './operations/index.js';
6
- export { ALL_OPERATIONS, VIDEO_MODELS, AUDIO_MODELS, defaultContext, type Operation, type OperationContext, type OperationResult } from './operations/index.js';
7
- export { MODEL_FACTS, getModelFact, multimodalRefSummary, multimodalRefModels, SEEDANCE_TASK_INTENT_WORDS, seedanceTaskIntentWords, type ModelFact, } from './prompts/model-facts.js';
6
+ export { ALL_OPERATIONS, VIDEO_MODELS, AUDIO_MODELS, IMAGE_MODELS, defaultContext, OperationCancelledError, type Operation, type OperationContext, type OperationResult, type OperationAnnotations, type OperationTier, type OperationGroup } from './operations/index.js';
7
+ export { CONFIRM_CREDITS, DEVIATION_FACTOR } from './operations/index.js';
8
+ export { toolDefinitions, toolDefinition, groupFor, tierFor, OPERATION_GROUPS, GROUP_SUMMARY, type ToolDefinition, } from './operations/index.js';
9
+ export { MODEL_FACTS, getModelFact, multimodalRefSummary, multimodalRefModels, describeRouting, SEEDANCE_TASK_INTENT_WORDS, seedanceTaskIntentWords, type ModelFact, } from './prompts/model-facts.js';
8
10
  export { MODEL_CAPABILITIES, ALL_ASPECT_RATIOS, AGENT_ROUTE_PROVIDER, getModelCapability, aspectRatiosFor, videoResolutionsFor, defaultVideoResolutionFor, durationsFor, durationValuesFor, aspectRatioUnion, videoResolutionUnion, durationBounds, checkAspectRatio, checkVideoResolution, checkDuration, describeAspectRatios, describeVideoResolutions, describeDurations, describeReferenceImageCaps, type AspectRatio, type VideoResolution, type ModelCapability, type DurationCapability, type VideoResolutionCapability, } from './prompts/model-capabilities.js';
11
+ export { buildAgentDoctrine, type AgentSurface } from './prompts/agent-doctrine.js';
12
+ export { BANNED_PROMPT_TOKENS, describeBannedTokens, findBannedTokens, bannedTokenWarning, bannedTokensForSkill, describeBannedTokensForSkill, type BannedToken, type BannedTokenScope, } from './prompts/banned-tokens.js';
13
+ export { CRAFT_CARDS, CRAFT_CARD_CEILING, craftCard, describeCraftCard } from './prompts/craft-cards.js';
9
14
  export { PROMPTING_TIPS, getPromptingTips, type PromptingTipsEntry, type PromptingTipCard, type PromptingTipsKey } from './prompts/prompting-tips.js';
15
+ export { SLATES_API_URL } from './api-url.js';
10
16
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -3,11 +3,23 @@ export { SlatesCloudClient } from './clients/cloud.js';
3
3
  export { SlatesDesktopClient } from './clients/desktop.js';
4
4
  export { SKILLS } from './skills/content.js';
5
5
  export * as operations from './operations/index.js';
6
- export { ALL_OPERATIONS, VIDEO_MODELS, AUDIO_MODELS, defaultContext } from './operations/index.js';
6
+ export { ALL_OPERATIONS, VIDEO_MODELS, AUDIO_MODELS, IMAGE_MODELS, defaultContext, OperationCancelledError } from './operations/index.js';
7
+ // The spend thresholds the DESKTOP and the SKILLS both quote. `CONFIRM_CREDITS`
8
+ // is the op-level confirm gate; `DEVIATION_FACTOR` is the Studio Agent's
9
+ // re-ask multiplier, which lived only in `loop.ts` while `slates-cost-discipline`
10
+ // told the agent a different number. One home, both readers.
11
+ export { CONFIRM_CREDITS, DEVIATION_FACTOR } from './operations/index.js';
12
+ // 🚨 THE ONE SCHEMA RENDERER + the tier/annotation tables. The desktop rendered
13
+ // `$refStrategy:'none'` and the MCP server rendered `openApi3`, so surface
14
+ // parity was proven of the ID SET and unproven of the BYTES. Both call this now.
15
+ export { toolDefinitions, toolDefinition, groupFor, tierFor, OPERATION_GROUPS, GROUP_SUMMARY, } from './operations/index.js';
7
16
  // Model routing/prompting facts — the SSOT the desktop Studio Agent system
8
17
  // prompt derives its MODEL ROUTING doctrine from (kind: image | video | audio,
9
18
  // default/premium/niche notes). Edit model-facts.ts, never prose copies.
10
19
  export { MODEL_FACTS, getModelFact, multimodalRefSummary, multimodalRefModels,
20
+ // THE routing renderer — the system prompt, the MCP instructions and the
21
+ // generate ops all call this one function, so routing prose exists once.
22
+ describeRouting,
11
23
  // Mirrored in slate/src/shared/pricing.ts — see the constant's own header for
12
24
  // why the mirror exists and why it must never drive a prompt rewrite.
13
25
  SEEDANCE_TASK_INTENT_WORDS, seedanceTaskIntentWords, } from './prompts/model-facts.js';
@@ -17,7 +29,38 @@ SEEDANCE_TASK_INTENT_WORDS, seedanceTaskIntentWords, } from './prompts/model-fac
17
29
  // the op surface validates against them and GENERATES its `.describe()` prose
18
30
  // from them. Never hand-type a capability fact an LLM will read.
19
31
  export { MODEL_CAPABILITIES, ALL_ASPECT_RATIOS, AGENT_ROUTE_PROVIDER, getModelCapability, aspectRatiosFor, videoResolutionsFor, defaultVideoResolutionFor, durationsFor, durationValuesFor, aspectRatioUnion, videoResolutionUnion, durationBounds, checkAspectRatio, checkVideoResolution, checkDuration, describeAspectRatios, describeVideoResolutions, describeDurations, describeReferenceImageCaps, } from './prompts/model-capabilities.js';
32
+ // 🚨 AGENT GUIDANCE SSOT — the working method, the hard rules and the guide
33
+ // index, as ONE string both surfaces consume: the desktop Studio Agent's whole
34
+ // system prompt (slate/src/main/studio-agent/context.ts) and the MCP server's
35
+ // `instructions`. Neither may author doctrine prose of its own; the guidance
36
+ // layer drifted for exactly as long as it had no single home.
37
+ //
38
+ // Exported from the ROOT barrel only, never from ./prompts — that subpath is
39
+ // bundled by the desktop RENDERER and must stay small and Node-free, and this
40
+ // module pulls in the whole embedded SKILLS record.
41
+ // Only what a CONSUMER calls. `buildSkillIndex`, `WORKING_METHOD` and
42
+ // `HARD_RULES` are used inside agent-doctrine.ts and by nothing else, so they
43
+ // stay off the public surface — an export nothing calls is an export nothing
44
+ // keeps honest, which is why `buildModelRouting` was deleted rather than left
45
+ // here "in case".
46
+ export { buildAgentDoctrine } from './prompts/agent-doctrine.js';
47
+ // Banned prompt tokens — EXTRACTED from the skills' own never-use lists and
48
+ // inlined into the generate ops' descriptions. Enforcement of "load the guide"
49
+ // that the model cannot skip, because a description is always in context.
50
+ export {
51
+ // BANNED_PROMPT_TOKENS + describeBannedTokens: the lockstep checker and the
52
+ // ops. findBannedTokens: the eval harness scorer. bannedTokenWarning: the ops.
53
+ // `bannedTokensFor` is internal to the module and stays there.
54
+ BANNED_PROMPT_TOKENS, describeBannedTokens, findBannedTokens, bannedTokenWarning,
55
+ // Per-model lists — the 13 skills the two cross-model lists never covered.
56
+ bannedTokensForSkill, describeBannedTokensForSkill, } from './prompts/banned-tokens.js';
57
+ // 🚨 CRAFT CARDS — the POSITIVE half of the guide, extracted from the skills'
58
+ // own `@card` blocks and delivered on the estimate result. The eval scorer reads
59
+ // CRAFT_CARDS to build its lever vocabulary, so the assertion can never be
60
+ // scored against a hand-retyped word list.
61
+ export { CRAFT_CARDS, CRAFT_CARD_CEILING, craftCard, describeCraftCard } from './prompts/craft-cards.js';
20
62
  // Per-model prompting tips — the SSOT for the desktop "See prompting tips"
21
63
  // modals. The desktop renders these; it never hand-writes tips content.
22
64
  export { PROMPTING_TIPS, getPromptingTips } from './prompts/prompting-tips.js';
65
+ export { SLATES_API_URL } from './api-url.js';
23
66
  //# sourceMappingURL=index.js.map
@@ -2,11 +2,30 @@ import { z } from 'zod';
2
2
  import { SlatesCloudClient } from '../clients/cloud.js';
3
3
  import { SlatesDesktopClient } from '../clients/desktop.js';
4
4
  import { type AspectRatio, type VideoResolution } from '../prompts/model-capabilities.js';
5
+ import { type OrderedAttachmentRole } from '../prompts/shot-spec.js';
5
6
  export interface OperationContext {
6
7
  cloud: () => SlatesCloudClient;
7
8
  desktop: () => SlatesDesktopClient;
9
+ /**
10
+ * Cancellation, propagated from the caller.
11
+ *
12
+ * 🚨 THIS IS WHAT MAKES "STOP" MEAN STOP. Escape in the desktop Studio Agent
13
+ * aborted the brain stream and marked the *remaining* tool calls cancelled,
14
+ * but the op already running got no signal at all — so a sequential batch
15
+ * (`slates_generate_from_shots`, the largest spender on the surface) kept
16
+ * firing generations after the user had cancelled. Ops that loop over items,
17
+ * or block on a long provider call, check it; everything else may ignore it.
18
+ *
19
+ * Optional so an older caller that does not pass one still type-checks.
20
+ */
21
+ signal?: AbortSignal;
8
22
  }
9
23
  export declare function defaultContext(): OperationContext;
24
+ /** Thrown by an op that noticed `ctx.signal` had aborted mid-work. */
25
+ export declare class OperationCancelledError extends Error {
26
+ code: string;
27
+ constructor(detail?: string);
28
+ }
10
29
  export interface OperationResult {
11
30
  text: string;
12
31
  images?: Array<{
@@ -20,16 +39,121 @@ export interface Operation<I> {
20
39
  description: string;
21
40
  input: z.ZodType<I>;
22
41
  run: (input: I, ctx: OperationContext) => Promise<OperationResult>;
42
+ /**
43
+ * This op causes a provider call the user pays for.
44
+ *
45
+ * 🚨 IT IS THE DESKTOP'S CONSENT GATE, DECLARED WHERE THE OP IS WRITTEN.
46
+ * `slate/src/main/studio-agent/loop.ts` refuses a billable name until
47
+ * `present_plan` has been approved, and refreshes the balance-derived spend
48
+ * after each one so the deviation pause can fire. That list used to live only
49
+ * in the desktop, one repo away from the op it gated — and both
50
+ * `slates_generate_audio` and `slates_generate_from_shots` shipped without an
51
+ * entry, so the in-app agent could spend on either with no approved plan and
52
+ * no ledger entry. Set it HERE, beside the description, and the desktop takes
53
+ * the union of this and its own list (union, so an older published package can
54
+ * only ever gate MORE, never less).
55
+ *
56
+ * Set it on anything that spends INDIRECTLY too —
57
+ * `slates_generate_from_shots` fires N generations of its own.
58
+ *
59
+ * NOT part of the tool schema: it never reaches the model, so it costs no
60
+ * prefix bytes.
61
+ */
62
+ billable?: boolean;
63
+ /**
64
+ * MCP tool annotations (spec 2025-06-18), emitted in ListTools.
65
+ *
66
+ * 🚨 THIS IS WHAT LETS A HOST TELL A READ FROM A DELETE. Without them a
67
+ * Claude Desktop or Cursor user is prompted for `slates_list_assets` exactly
68
+ * the way they are prompted for `slates_delete_project`, and the destructive
69
+ * ops get no extra warning — so every prompt looks the same and the user
70
+ * learns to click through all of them.
71
+ *
72
+ * Never hand-set: `annotate()` derives all four from the op id below, and
73
+ * `scripts/agent-surface-lockstep-check.mjs` re-derives them INDEPENDENTLY
74
+ * from the op's own transport verbs. A `readOnlyHint` on an op whose `run`
75
+ * body posts is a lie that lets a host auto-approve a mutation, so the check
76
+ * has to be able to catch it.
77
+ */
78
+ annotations?: OperationAnnotations;
79
+ /**
80
+ * Which tier of the desktop tool surface this op belongs to.
81
+ *
82
+ * `core` is sent on every Studio Agent turn; `extended` is deferred behind
83
+ * `slates_load_tools` and appended to the tool list for the rest of the run
84
+ * once a group loads. The MCP server registers everything as before — hosts
85
+ * there do their own deferral (Claude Code defers stdio tool schemas through
86
+ * its tool search) and a stdio server has no run to append to.
87
+ *
88
+ * Defaults to `core` when absent, so a new op is visible until someone
89
+ * deliberately defers it.
90
+ */
91
+ tier?: OperationTier;
92
+ /** The `slates_load_tools` group this op arrives in. Required on `extended`. */
93
+ group?: OperationGroup;
94
+ }
95
+ /** MCP tool annotations. All four are declared on every op — a missing hint is
96
+ * indistinguishable from `false` to a host, which is the wrong default for
97
+ * `destructiveHint`. */
98
+ export interface OperationAnnotations {
99
+ readOnlyHint: boolean;
100
+ destructiveHint: boolean;
101
+ idempotentHint: boolean;
102
+ openWorldHint: boolean;
23
103
  }
104
+ export type OperationTier = 'core' | 'extended';
105
+ export type OperationGroup = 'library' | 'timeline' | 'admin' | 'blender';
106
+ export declare const CONFIRM_CREDITS = 17;
107
+ /**
108
+ * The desktop deviation guard's ceiling multiplier: the Studio Agent pauses and
109
+ * re-asks when projected generation spend exceeds the approved ledger by more
110
+ * than this factor.
111
+ *
112
+ * 🚨 EXPORTED BECAUSE THE NUMBER IS QUOTED DOWNSTREAM. `slates-cost-discipline`
113
+ * told the agent the threshold was 25% while `loop.ts` paused at 20% — a skill
114
+ * contradicting the code on the one number that decides whether a run stops.
115
+ * The skill now renders it from here through `_partials/thresholds.md`; the
116
+ * desktop loop imports it instead of declaring its own.
117
+ */
118
+ export declare const DEVIATION_FACTOR = 1.2;
119
+ /**
120
+ * Per-surface bounds and defaults.
121
+ *
122
+ * 🚨 THESE FOUR NUMBERS PER SURFACE LIVE IN THREE REPOS. A change is a
123
+ * three-site edit, every time:
124
+ * 1. HERE (`audioCostKey`, the agent's pre-flight quote)
125
+ * 2. `slate/src/shared/pricing.ts` → MODEL_REGISTRY `audio.durationSeconds`
126
+ * (min/max/default), read by `clampAudioDuration` + `audioCreditKey`
127
+ * 3. `slates-api/src/lib/audio-keys.ts` → the server's fail-closed bounds
128
+ * `slates-api/scripts/pricing-consistency-check.mjs` §4 asserts 1 and 2 agree
129
+ * at EVERY value including out-of-range ones; the gate check covers 3.
130
+ *
131
+ * The MINs used to be missing here, and the clamp floor was a hardcoded 1. That
132
+ * made `slates_estimate_generation_cost({model:'seed-audio', duration:2})`
133
+ * quote a real `seed-audio-2s` price for a generation the desktop would bill as
134
+ * 3s and the proxy would REJECT outright. Same for an omitted duration, which
135
+ * quoted `seed-audio-1s` against the desktop's `seed-audio-15s`.
136
+ */
137
+ export declare const SEED_AUDIO_MIN_SECONDS = 3;
138
+ export declare const SEED_AUDIO_MAX_SECONDS = 120;
139
+ export declare const SEED_AUDIO_DEFAULT_SECONDS = 15;
140
+ export declare const ELEVEN_SFX_MIN_SECONDS = 1;
141
+ export declare const ELEVEN_SFX_MAX_SECONDS = 22;
142
+ export declare const ELEVEN_SFX_DEFAULT_SECONDS = 4;
143
+ export declare const TTS_MODEL: "inworld-tts-2";
144
+ export declare const TTS_BUCKET_CHARS = 250;
145
+ export declare const TTS_MAX_CHARACTERS: number;
146
+ export declare const TTS_BUCKET_COUNT: number;
24
147
  export declare const getWorkspaceState: Operation<{
25
148
  projectId?: string;
149
+ limit?: number;
26
150
  }>;
27
151
  export declare const getMe: Operation<Record<string, never>>;
28
152
  export declare const getCreditBalance: Operation<Record<string, never>>;
29
153
  export declare const listAvailableModels: Operation<{
30
154
  filter?: string;
31
155
  }>;
32
- export declare const VIDEO_MODELS: readonly ["kling-v3.0-std", "kling-v3.0-pro", "kling-v3.0-omni", "veo-3.1-fast", "veo-3.1-standard", "seedance-2", "seedance-2.5", "omni-flash", "minimax-h3", "minimax-h3-max"];
156
+ export declare const VIDEO_MODELS: readonly ["kling-v3.0-std", "kling-v3.0-pro", "kling-v3.0-omni", "veo-3.1-fast", "veo-3.1-standard", "seedance-2", "seedance-2.5", "omni-flash", "minimax-h3", "minimax-h3-max", "ltx-2-5", "ltx-2-5-pro"];
33
157
  type VideoModel = (typeof VIDEO_MODELS)[number];
34
158
  /** The exact `model` ids `slates_edit_video` accepts. Edit rows are deliberately
35
159
  * NOT in VIDEO_MODELS — they take a source clip, not frames. */
@@ -39,6 +163,9 @@ export declare const estimateGenerationCost: Operation<{
39
163
  model: string;
40
164
  quantity?: number;
41
165
  duration?: number;
166
+ /** inworld-tts-2 only — the character count of the text, which is what it
167
+ * bills on. That surface has no duration dimension at all. */
168
+ characters?: number;
42
169
  /** The FULL union — the runtime Zod enum is generated from MODEL_CAPABILITIES
43
170
  * and `assertVideoCapabilities` is the per-model narrowing authority. */
44
171
  videoResolution?: VideoResolution;
@@ -227,36 +354,14 @@ export declare function seedanceEditCostKey(input: {
227
354
  seedanceFace?: boolean;
228
355
  seedanceRealFace?: boolean;
229
356
  }): string;
230
- export declare const AUDIO_MODELS: readonly ["seed-audio", "eleven-sfx"];
357
+ export declare const AUDIO_MODELS: readonly ["seed-audio", "eleven-sfx", "inworld-tts-2"];
231
358
  export type AudioModel = (typeof AUDIO_MODELS)[number];
232
- /**
233
- * Per-surface bounds and defaults.
234
- *
235
- * 🚨 THESE FOUR NUMBERS PER SURFACE LIVE IN THREE REPOS. A change is a
236
- * three-site edit, every time:
237
- * 1. HERE (`audioCostKey`, the agent's pre-flight quote)
238
- * 2. `slate/src/shared/pricing.ts` → MODEL_REGISTRY `audio.durationSeconds`
239
- * (min/max/default), read by `clampAudioDuration` + `audioCreditKey`
240
- * 3. `slates-api/src/lib/audio-keys.ts` → the server's fail-closed bounds
241
- * `slates-api/scripts/pricing-consistency-check.mjs` §4 asserts 1 and 2 agree
242
- * at EVERY value including out-of-range ones; the gate check covers 3.
243
- *
244
- * The MINs used to be missing here, and the clamp floor was a hardcoded 1. That
245
- * made `slates_estimate_generation_cost({model:'seed-audio', duration:2})`
246
- * quote a real `seed-audio-2s` price for a generation the desktop would bill as
247
- * 3s and the proxy would REJECT outright. Same for an omitted duration, which
248
- * quoted `seed-audio-1s` against the desktop's `seed-audio-15s`.
249
- */
250
- export declare const SEED_AUDIO_MIN_SECONDS = 3;
251
- export declare const SEED_AUDIO_MAX_SECONDS = 120;
252
- export declare const SEED_AUDIO_DEFAULT_SECONDS = 15;
253
- export declare const ELEVEN_SFX_MIN_SECONDS = 1;
254
- export declare const ELEVEN_SFX_MAX_SECONDS = 22;
255
- export declare const ELEVEN_SFX_DEFAULT_SECONDS = 4;
256
359
  export declare function audioCostKey(input: {
257
360
  model: AudioModel;
258
361
  /** seed-audio + eleven-sfx: the REQUESTED duration in seconds (ceiled). */
259
362
  durationSeconds?: number;
363
+ /** inworld-tts-2 ONLY: the character count of the text being spoken. */
364
+ characters?: number;
260
365
  }): string;
261
366
  export declare const generateVideo: Operation<{
262
367
  prompt: string;
@@ -294,6 +399,9 @@ export declare const generateAudio: Operation<{
294
399
  prompt: string;
295
400
  durationSeconds?: number;
296
401
  voice?: string;
402
+ voiceId?: string;
403
+ voiceReferenceAssetId?: string;
404
+ voiceDescription?: string;
297
405
  speed?: number;
298
406
  volume?: number;
299
407
  pitch?: number;
@@ -505,8 +613,6 @@ export declare const updateFrame: Operation<{
505
613
  assetId?: string | null;
506
614
  sceneId?: string | null;
507
615
  position?: number;
508
- frameType?: 'first' | 'last' | 'ingredient' | null;
509
- motionPrompt?: string | null;
510
616
  }>;
511
617
  /**
512
618
  * Batch form of `slates_update_frame`.
@@ -529,15 +635,121 @@ export declare const batchUpdateFrames: Operation<{
529
635
  assetId?: string | null;
530
636
  sceneId?: string | null;
531
637
  position?: number;
532
- frameType?: 'first' | 'last' | 'ingredient' | null;
533
- motionPrompt?: string | null;
534
638
  }[];
535
639
  }>;
536
640
  export declare const deleteFrame: Operation<{
537
641
  frameId: string;
538
642
  }>;
643
+ interface ShotOpScript {
644
+ speaker?: string | null;
645
+ line?: string | null;
646
+ delivery?: string | null;
647
+ action?: string | null;
648
+ prop?: string | null;
649
+ shotSize?: string | null;
650
+ camera?: string | null;
651
+ continues?: boolean;
652
+ }
653
+ interface ShotOpRefs {
654
+ refs?: Partial<Record<OrderedAttachmentRole, string[]>>;
655
+ firstFrameAssetId?: string;
656
+ lastFrameAssetId?: string;
657
+ audioRefSpokenText?: string[];
658
+ characterIds?: string[];
659
+ environmentIds?: string[];
660
+ styleIds?: string[];
661
+ }
662
+ interface ShotOpParams {
663
+ aspectRatio?: AspectRatio;
664
+ duration?: number;
665
+ videoResolution?: VideoResolution;
666
+ imageResolution?: '1k' | '2k' | '3k' | '4k';
667
+ gptQuality?: 'medium' | 'high';
668
+ imageQuantity?: number;
669
+ negativePrompt?: string;
670
+ sound?: boolean;
671
+ seedanceFace?: boolean;
672
+ audioDurationSeconds?: number;
673
+ }
674
+ export declare const createShot: Operation<ShotOpRefs & ShotOpScript & {
675
+ projectId: string;
676
+ name?: string;
677
+ prompt: string;
678
+ model?: string;
679
+ params?: ShotOpParams;
680
+ frameId?: string;
681
+ sceneId?: string;
682
+ }>;
683
+ export declare const updateShot: Operation<ShotOpRefs & ShotOpScript & {
684
+ shotId: string;
685
+ projectId: string;
686
+ name?: string;
687
+ prompt?: string;
688
+ model?: string;
689
+ params?: ShotOpParams;
690
+ attachFrameId?: string;
691
+ detachFrameId?: string;
692
+ posterAssetId?: string | null;
693
+ }>;
694
+ export declare const duplicateShot: Operation<{
695
+ shotId: string;
696
+ name?: string;
697
+ prompt?: string;
698
+ model?: string;
699
+ params?: ShotOpParams;
700
+ frameId?: string | null;
701
+ }>;
702
+ export declare const listShots: Operation<{
703
+ projectId: string;
704
+ storyboardId?: string;
705
+ frameId?: string;
706
+ }>;
707
+ export declare const getShot: Operation<{
708
+ shotId: string;
709
+ }>;
710
+ /**
711
+ * SPLIT and MERGE — the chop decision, and the only two cross-row operations on
712
+ * this surface.
713
+ *
714
+ * 🔑 THIS IS THE EXECUTIVE CALL, AND IT IS WHY THEY ARE OPS. *"Sometimes you
715
+ * might be using more dialogue in one single 30-second generation. Sometimes it
716
+ * might just be a 4-second generation of one line."* Merging five lines into
717
+ * one long take or splitting them into five short ones changes the rhythm AND
718
+ * the price, and the agent has to be able to re-chop what it wrote.
719
+ *
720
+ * 🚨 NEITHER EDITS TEXT AS A SIDE EFFECT. Split moves the text after a caret
721
+ * the caller placed; merge joins two texts at their boundary. Nothing else in
722
+ * either row is rewritten. That property is what keeps a finished script
723
+ * finished, and it is the acceptance test for anything added here later.
724
+ */
725
+ export declare const splitShot: Operation<{
726
+ shotId: string;
727
+ caret?: number;
728
+ }>;
729
+ export declare const mergeShots: Operation<{
730
+ firstId: string;
731
+ secondId: string;
732
+ }>;
733
+ export declare const generateFromShots: Operation<{
734
+ shotIds: string[];
735
+ confirm?: boolean;
736
+ }>;
539
737
  export declare const getPromptingGuide: Operation<{
540
738
  topic: string;
739
+ depth?: 'card' | 'full';
740
+ }>;
741
+ /**
742
+ * The one op that changes what OTHER ops are visible.
743
+ *
744
+ * 🚨 IT EXISTS BECAUSE THE SURFACE IS 112 KB AND EVERY TURN PAYS FOR ALL OF IT.
745
+ * The desktop Studio Agent sends `core` plus this; a group arrives when the
746
+ * work needs it and stays for the rest of the run. On the MCP surface every op
747
+ * is registered up front (a stdio server has no run to append to), so this
748
+ * returns the same definitions as a plain listing — useful either way, since
749
+ * it is also how an agent asks "what else can you do".
750
+ */
751
+ export declare const loadTools: Operation<{
752
+ group: OperationGroup;
541
753
  }>;
542
754
  export declare const blenderStatus: Operation<Record<string, never>>;
543
755
  export declare const blenderExecute: Operation<{
@@ -563,5 +775,5 @@ export declare const blenderRenderBlocking: Operation<{
563
775
  basename?: string;
564
776
  }>;
565
777
  export declare const ALL_OPERATIONS: ReadonlyArray<Operation<unknown>>;
566
- export {};
778
+ export { toolDefinitions, toolDefinition, groupFor, tierFor, OPERATION_GROUPS, GROUP_SUMMARY, type ToolDefinition } from './surface.js';
567
779
  //# sourceMappingURL=index.d.ts.map