@nodaro/shared 1.12.0 → 1.13.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nodaro/shared",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Shared types, model catalog, wire contracts, and structural vocabularies for the Nodaro platform and SDK.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -12,6 +12,7 @@ import {
12
12
  effectiveReasoningEffort,
13
13
  } from "../llm-models.js"
14
14
  import type { LlmModelDef, LlmTier, LlmFeature } from "../llm-models.js"
15
+ import { PIPELINE_PINNABLE_SCRIPT_LLMS } from "../pipeline-types.js"
15
16
 
16
17
  // The provider-$ per-token rate table and `calculateLlmCost` moved to
17
18
  // backend/src/lib/pricing/llm-cost.ts (S5) — its tests live in
@@ -128,6 +129,32 @@ describe("LLM_MODEL_IDS", () => {
128
129
  // getLlmModel
129
130
  // ---------------------------------------------------------------------------
130
131
  describe("getLlmModel", () => {
132
+ // Dash-alias resolution: wire contracts (PIPELINE_PINNABLE_SCRIPT_LLMS,
133
+ // provider slugs, persisted configs) carry dash forms while LLM_MODELS keys
134
+ // canonical dot ids — getLlmModel must accept both or the film pipeline's
135
+ // own script default throws "Unknown LLM model" at run time.
136
+ it("resolves dash-form aliases to their canonical dot-form models", () => {
137
+ expect(getLlmModel("claude-sonnet-4-6")?.id).toBe("claude-sonnet-4.6")
138
+ expect(getLlmModel("claude-opus-4-7")?.id).toBe("claude-opus-4.7")
139
+ expect(getLlmModel("claude-haiku-4-5")?.id).toBe("claude-haiku-4.5")
140
+ })
141
+
142
+ it("resolves every PIPELINE_PINNABLE_SCRIPT_LLMS member (the film pipeline's pin surface)", () => {
143
+ for (const id of PIPELINE_PINNABLE_SCRIPT_LLMS) {
144
+ expect(getLlmModel(id), `pinnable script llm ${id} must resolve`).toBeDefined()
145
+ }
146
+ })
147
+
148
+ it("resolves provider slugs as historical aliases", () => {
149
+ const dated = LLM_MODELS.find((m) => m.directFallbackModel && m.directFallbackModel !== m.id)
150
+ if (dated) expect(getLlmModel(dated.directFallbackModel!)?.id).toBe(dated.id)
151
+ })
152
+
153
+ it("still returns undefined for a genuinely unknown id", () => {
154
+ expect(getLlmModel("claude-sonnet-9-9")).toBeUndefined()
155
+ expect(getLlmModel("not-a-model")).toBeUndefined()
156
+ })
157
+
131
158
  it('returns model def for "gemini-3-flash"', () => {
132
159
  const model = getLlmModel("gemini-3-flash")
133
160
  expect(model).toBeDefined()
package/src/index.ts CHANGED
@@ -467,6 +467,7 @@ export type { LocationCatalogRef } from "./location-preset-catalog-map.js"
467
467
 
468
468
  export {
469
469
  PARAMETER_NODE_TYPES,
470
+ HINT_EXEMPT_PARAMETER_TYPES,
470
471
  getParameterValue,
471
472
  } from "./parameter-node-value.js"
472
473
 
package/src/llm-models.ts CHANGED
@@ -327,8 +327,29 @@ export function getLlmModalityCaps(modelId: string | undefined): { image: boolea
327
327
  return LLM_MODALITY_CAPS[modelId] ?? { image: true, video: false, audio: false }
328
328
  }
329
329
 
330
+ /**
331
+ * Dash-form aliases resolve to their canonical dot-form ids. Several wire
332
+ * contracts carry dash forms (`PIPELINE_PINNABLE_SCRIPT_LLMS`, provider slugs,
333
+ * configs persisted before the id scheme settled), while `LLM_MODELS` keys the
334
+ * canonical `major.minor` form — an exact-only lookup makes every such caller
335
+ * throw "Unknown LLM model" at run time. Normalizing here (instead of editing
336
+ * the enums) keeps stored configs and published-package consumers valid.
337
+ */
338
+ function dashAliasToCanonical(id: string): string {
339
+ return id.replace(/-(\d+)-(\d+)$/, "-$1.$2")
340
+ }
341
+
330
342
  export function getLlmModel(id: string): LlmModelDef | undefined {
331
- return LLM_MODELS.find((m) => m.id === id)
343
+ const exact = LLM_MODELS.find((m) => m.id === id)
344
+ if (exact) return exact
345
+ const canonical = dashAliasToCanonical(id)
346
+ if (canonical !== id) {
347
+ const aliased = LLM_MODELS.find((m) => m.id === canonical)
348
+ if (aliased) return aliased
349
+ }
350
+ // Last resort: provider slugs double as historical aliases (e.g. the
351
+ // dated Anthropic slugs) — accept any model whose slug matches exactly.
352
+ return LLM_MODELS.find((m) => m.kieSlugOrModel === id || m.directFallbackModel === id)
332
353
  }
333
354
 
334
355
  export function getLlmTier(id: string): LlmTier {
@@ -57,6 +57,26 @@ export const PARAMETER_NODE_TYPES: ReadonlySet<string> = new Set([
57
57
  "voice-delivery",
58
58
  ])
59
59
 
60
+ /**
61
+ * Parameter types that intentionally produce NO prompt hint from
62
+ * `getParameterPromptHint` (in `@nodaro/prompts`). They carry pure runtime
63
+ * parameters — counts, durations, aspect ratios, legacy motion intensity —
64
+ * consumed by the executor directly, never appended to a downstream prompt.
65
+ *
66
+ * Consumers that treat "parameter node" as "text producer" (the `{Label}`
67
+ * auto-fill in `main-text-handle.ts`, ref-map builders) must exclude these:
68
+ * their extracted output is undefined, so an auto-filled `{Label}` would stay
69
+ * in the outgoing prompt as literal brace text. Guarded by
70
+ * `parameter-registry-sync.test.ts` (each member really returns "") and
71
+ * `main-text-handle.test.ts` (members are not text-producing).
72
+ */
73
+ export const HINT_EXEMPT_PARAMETER_TYPES: ReadonlySet<string> = new Set([
74
+ "motion",
75
+ "scene-count",
76
+ "duration",
77
+ "aspect-ratio",
78
+ ])
79
+
60
80
  export function getParameterValue(
61
81
  data: Record<string, unknown>,
62
82
  nodeType: string,