( // Accept the wide public shape (`SystemPrompt<unknown>`) regardless of the // caller's `TMetadata`. Adapters know their own metadata shape; the // generic narrows the *output* so adapter code can read `p.metadata.X` // without an additional cast. prompts: ReadonlyArray<SystemPrompt> | undefined, )
| 68 | * `"undefined"` into the model's system prompt with no signal. |
| 69 | */ |
| 70 | export function normalizeSystemPrompts<TMetadata = unknown>( |
| 71 | // Accept the wide public shape (`SystemPrompt<unknown>`) regardless of the |
| 72 | // caller's `TMetadata`. Adapters know their own metadata shape; the |
| 73 | // generic narrows the *output* so adapter code can read `p.metadata.X` |
| 74 | // without an additional cast. |
| 75 | prompts: ReadonlyArray<SystemPrompt> | undefined, |
| 76 | ): Array<NormalizedSystemPrompt<TMetadata>> { |
| 77 | if (!prompts || prompts.length === 0) return [] |
| 78 | return prompts.map((p, i) => { |
| 79 | if (typeof p === 'string') return { content: p } |
| 80 | // Defence in depth: TypeScript narrows `p` to the object arm here, but |
| 81 | // this function is a public API boundary that callers can reach via |
| 82 | // plain JS or `as any`. Re-validate at runtime so we never stream a |
| 83 | // literal `"undefined"` into the model. |
| 84 | const candidate = p as unknown |
| 85 | if (candidate === null || typeof candidate !== 'object') { |
| 86 | throw new TypeError( |
| 87 | `systemPrompts[${i}]: expected a string or { content, metadata? }, got ${candidate === null ? 'null' : typeof candidate}`, |
| 88 | ) |
| 89 | } |
| 90 | const { content } = candidate as { content?: unknown } |
| 91 | if (typeof content !== 'string') { |
| 92 | throw new TypeError( |
| 93 | `systemPrompts[${i}]: content must be a string, got ${typeof content}`, |
| 94 | ) |
| 95 | } |
| 96 | return p as NormalizedSystemPrompt<TMetadata> |
| 97 | }) |
| 98 | } |
no outgoing calls
no test coverage detected