@sudobility/shapeshyft_engine 1.0.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 (83) hide show
  1. package/CLAUDE.md +27 -0
  2. package/README.md +11 -0
  3. package/dist/config/providers.d.ts +111 -0
  4. package/dist/config/providers.d.ts.map +1 -0
  5. package/dist/config/providers.js +1535 -0
  6. package/dist/config/providers.js.map +1 -0
  7. package/dist/index.d.ts +27 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +27 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/lib/api-helper.d.ts +35 -0
  12. package/dist/lib/api-helper.d.ts.map +1 -0
  13. package/dist/lib/api-helper.js +123 -0
  14. package/dist/lib/api-helper.js.map +1 -0
  15. package/dist/lib/capability-validator.d.ts +36 -0
  16. package/dist/lib/capability-validator.d.ts.map +1 -0
  17. package/dist/lib/capability-validator.js +140 -0
  18. package/dist/lib/capability-validator.js.map +1 -0
  19. package/dist/lib/media-constants.d.ts +55 -0
  20. package/dist/lib/media-constants.d.ts.map +1 -0
  21. package/dist/lib/media-constants.js +166 -0
  22. package/dist/lib/media-constants.js.map +1 -0
  23. package/dist/lib/media-conversion.d.ts +36 -0
  24. package/dist/lib/media-conversion.d.ts.map +1 -0
  25. package/dist/lib/media-conversion.js +87 -0
  26. package/dist/lib/media-conversion.js.map +1 -0
  27. package/dist/lib/media-utils.d.ts +35 -0
  28. package/dist/lib/media-utils.d.ts.map +1 -0
  29. package/dist/lib/media-utils.js +173 -0
  30. package/dist/lib/media-utils.js.map +1 -0
  31. package/dist/lib/output-limit.d.ts +38 -0
  32. package/dist/lib/output-limit.d.ts.map +1 -0
  33. package/dist/lib/output-limit.js +54 -0
  34. package/dist/lib/output-limit.js.map +1 -0
  35. package/dist/lib/prompt-builder.d.ts +94 -0
  36. package/dist/lib/prompt-builder.d.ts.map +1 -0
  37. package/dist/lib/prompt-builder.js +408 -0
  38. package/dist/lib/prompt-builder.js.map +1 -0
  39. package/dist/lib/reserved-fields.d.ts +41 -0
  40. package/dist/lib/reserved-fields.d.ts.map +1 -0
  41. package/dist/lib/reserved-fields.js +47 -0
  42. package/dist/lib/reserved-fields.js.map +1 -0
  43. package/dist/services/llm/anthropic.d.ts +16 -0
  44. package/dist/services/llm/anthropic.d.ts.map +1 -0
  45. package/dist/services/llm/anthropic.js +154 -0
  46. package/dist/services/llm/anthropic.js.map +1 -0
  47. package/dist/services/llm/custom.d.ts +51 -0
  48. package/dist/services/llm/custom.d.ts.map +1 -0
  49. package/dist/services/llm/custom.js +419 -0
  50. package/dist/services/llm/custom.js.map +1 -0
  51. package/dist/services/llm/extract-json.d.ts +17 -0
  52. package/dist/services/llm/extract-json.d.ts.map +1 -0
  53. package/dist/services/llm/extract-json.js +60 -0
  54. package/dist/services/llm/extract-json.js.map +1 -0
  55. package/dist/services/llm/finish-reason.d.ts +21 -0
  56. package/dist/services/llm/finish-reason.d.ts.map +1 -0
  57. package/dist/services/llm/finish-reason.js +55 -0
  58. package/dist/services/llm/finish-reason.js.map +1 -0
  59. package/dist/services/llm/gemini.d.ts +26 -0
  60. package/dist/services/llm/gemini.d.ts.map +1 -0
  61. package/dist/services/llm/gemini.js +178 -0
  62. package/dist/services/llm/gemini.js.map +1 -0
  63. package/dist/services/llm/groq.d.ts +28 -0
  64. package/dist/services/llm/groq.d.ts.map +1 -0
  65. package/dist/services/llm/groq.js +237 -0
  66. package/dist/services/llm/groq.js.map +1 -0
  67. package/dist/services/llm/index.d.ts +19 -0
  68. package/dist/services/llm/index.d.ts.map +1 -0
  69. package/dist/services/llm/index.js +88 -0
  70. package/dist/services/llm/index.js.map +1 -0
  71. package/dist/services/llm/openai.d.ts +101 -0
  72. package/dist/services/llm/openai.d.ts.map +1 -0
  73. package/dist/services/llm/openai.js +561 -0
  74. package/dist/services/llm/openai.js.map +1 -0
  75. package/dist/services/llm/types.d.ts +110 -0
  76. package/dist/services/llm/types.d.ts.map +1 -0
  77. package/dist/services/llm/types.js +16 -0
  78. package/dist/services/llm/types.js.map +1 -0
  79. package/dist/types/index.d.ts +812 -0
  80. package/dist/types/index.d.ts.map +1 -0
  81. package/dist/types/index.js +366 -0
  82. package/dist/types/index.js.map +1 -0
  83. package/package.json +93 -0
@@ -0,0 +1,812 @@
1
+ /**
2
+ * @sudobility/shapeshyft_engine/types
3
+ * Product-neutral domain types shared by ShapeShyft and ShapeRouter.
4
+ *
5
+ * No runtime imports: frontend packages re-export this module.
6
+ */
7
+ export type { ApiResponse, BaseResponse, NetworkClient, Optional, PaginatedResponse, PaginationInfo, PaginationOptions, } from '@sudobility/types';
8
+ import type { Optional, BaseResponse } from '@sudobility/types';
9
+ export type LlmProvider = 'openai' | 'anthropic' | 'gemini' | 'mistral' | 'cohere' | 'groq' | 'xai' | 'deepseek' | 'perplexity' | 'lm_studio';
10
+ export type HttpMethod = 'GET' | 'POST';
11
+ /**
12
+ * Media type for multimodal content
13
+ */
14
+ export type MediaType = 'image' | 'audio' | 'video';
15
+ /** OpenAI model options (verified 2026-08-18) */
16
+ export type OpenAiModel = 'gpt-5.6-sol' | 'gpt-5.6-terra' | 'gpt-5.6-luna' | 'gpt-5.5' | 'gpt-5.4' | 'gpt-5.4-mini' | 'gpt-5.4-nano' | 'gpt-5' | 'gpt-5-mini' | 'gpt-5-nano' | 'gpt-4.1' | 'gpt-4.1-mini' | 'gpt-4.1-nano' | 'gpt-4o' | 'gpt-4o-mini';
17
+ /** Anthropic model options (verified 2026-08-18) */
18
+ export type AnthropicModel = 'claude-fable-5' | 'claude-opus-5' | 'claude-sonnet-5' | 'claude-haiku-4-5' | 'claude-opus-4-8' | 'claude-opus-4-7' | 'claude-opus-4-6' | 'claude-sonnet-4-6' | 'claude-opus-4-5-20251101' | 'claude-sonnet-4-5-20250929';
19
+ /** Google Gemini model options (verified 2026-08-18) */
20
+ export type GeminiModel = 'gemini-3.7-flash' | 'gemini-3.6-flash' | 'gemini-3.5-flash' | 'gemini-3.5-flash-lite' | 'gemini-3.1-flash-lite' | 'gemini-3.1-pro-preview' | 'gemini-3-flash-preview' | 'gemini-3.1-flash-image' | 'gemini-3.1-flash-lite-image' | 'gemini-3-pro-image' | 'gemini-2.5-pro' | 'gemini-2.5-flash' | 'gemini-2.5-flash-lite' | 'gemini-2.5-flash-image' | 'gemini-2.5-flash-native-audio-preview-12-2025' | 'veo-3.1-generate-preview' | 'veo-3.1-lite-generate-preview';
21
+ /** Mistral AI model options (verified 2026-08-18) */
22
+ export type MistralModel = 'mistral-large-latest' | 'mistral-large-2512' | 'mistral-medium-latest' | 'mistral-small-latest' | 'mistral-small-2603' | 'ministral-14b-2512' | 'ministral-8b-2512' | 'ministral-3b-2512' | 'codestral-latest' | 'codestral-2508' | 'mistral-ocr-latest';
23
+ /** Cohere model options (verified 2026-08-18) */
24
+ export type CohereModel = 'command-a-plus-05-2026' | 'command-a-03-2025' | 'command-a-reasoning-08-2025' | 'command-a-vision-07-2025' | 'command-a-translate-08-2025' | 'command-r7b-12-2024' | 'command-r-plus-08-2024' | 'command-r-08-2024';
25
+ /** Groq model options (verified 2026-08-18) */
26
+ export type GroqModel = 'openai/gpt-oss-120b' | 'openai/gpt-oss-20b' | 'qwen/qwen3.6-27b' | 'minimaxai/minimax-m2.7' | 'groq/compound' | 'groq/compound-mini' | 'whisper-large-v3' | 'whisper-large-v3-turbo';
27
+ /** xAI (Grok) model options (verified 2026-08-18) */
28
+ export type XaiModel = 'grok-4.6' | 'grok-4.5' | 'grok-4.3' | 'grok-4.20-0309-reasoning' | 'grok-4.20-0309-non-reasoning' | 'grok-4.20-multi-agent-0309' | 'grok-build-0.1';
29
+ /** DeepSeek model options (verified 2026-08-18) */
30
+ export type DeepSeekModel = 'deepseek-v4-pro' | 'deepseek-v4-flash';
31
+ /** Perplexity model options (verified 2026-08-18) */
32
+ export type PerplexityModel = 'sonar' | 'sonar-pro' | 'sonar-pro-search' | 'sonar-reasoning-pro' | 'sonar-deep-research';
33
+ /** Custom LLM server models (suggested options; any string is valid) */
34
+ export type LlmServerModel = 'qwen3-8b' | 'qwen3-14b' | 'qwen3-30b-a3b' | 'qwen2.5-coder-14b-instruct' | 'mistral-7b-instruct-v0.3' | 'deepseek-r1-distill-qwen-7b' | 'gemma-3-4b-it' | 'gemma-3-12b-it' | 'gemma-3-27b-it' | 'qwen2.5-vl-3b-instruct' | 'qwen2.5-vl-7b-instruct' | 'qwen2.5-vl-32b-instruct' | 'qwen2.5-vl-72b-instruct' | 'glm-4v-9b' | 'pixtral-12b-2409' | 'olmocr-2-7b-1025' | 'janus-pro-7b' | string;
35
+ /** Union of all model types */
36
+ export type LlmModel = OpenAiModel | AnthropicModel | GeminiModel | MistralModel | CohereModel | GroqModel | XaiModel | DeepSeekModel | PerplexityModel | LlmServerModel;
37
+ /** List of available providers */
38
+ export declare const LLM_PROVIDERS: LlmProvider[];
39
+ /**
40
+ * Mapping of each LLM provider to its known valid model IDs.
41
+ * Useful for both server-side validation and client-side form validation.
42
+ *
43
+ * Note: `lm_studio` has an empty list because it accepts arbitrary
44
+ * user-supplied model names (any string is valid).
45
+ */
46
+ export declare const PROVIDER_MODELS: Record<LlmProvider, readonly string[]>;
47
+ /**
48
+ * Check whether a model ID is valid for the given provider.
49
+ * For `lm_studio`, any string is valid (returns true) since users
50
+ * can run arbitrary models on their local server.
51
+ *
52
+ * @param provider - The LLM provider to validate against
53
+ * @param model - The model ID string to check
54
+ * @returns true if the model is a known valid model for the provider
55
+ */
56
+ export declare function isValidModelForProvider(provider: LlmProvider, model: string): boolean;
57
+ /**
58
+ * Supported media input formats for different providers/models.
59
+ * - url: HTTP/HTTPS URLs to media files
60
+ * - base64: Base64-encoded binary data (data URLs)
61
+ * - gcs: Google Cloud Storage URIs (gs://bucket/path)
62
+ * - s3: AWS S3 URIs (s3://bucket/key)
63
+ * - file: Direct file upload (multipart form data)
64
+ */
65
+ export type MediaInputFormat = 'url' | 'base64' | 'gcs' | 's3' | 'file';
66
+ /**
67
+ * Media format support configuration for a model.
68
+ * Specifies which input formats are supported for each media type.
69
+ */
70
+ export interface MediaFormatSupport {
71
+ /** Supported formats for image input */
72
+ imageFormats?: MediaInputFormat[];
73
+ /** Supported formats for audio input */
74
+ audioFormats?: MediaInputFormat[];
75
+ /** Supported formats for video input */
76
+ videoFormats?: MediaInputFormat[];
77
+ }
78
+ /**
79
+ * Capabilities for a model's input and output modalities.
80
+ * undefined = unknown (user's responsibility to verify)
81
+ * true = supported
82
+ * false = not supported
83
+ */
84
+ export interface ModelCapabilities {
85
+ visionInput?: boolean;
86
+ audioInput?: boolean;
87
+ videoInput?: boolean;
88
+ imageOutput?: boolean;
89
+ audioOutput?: boolean;
90
+ videoOutput?: boolean;
91
+ webSearch?: boolean;
92
+ mediaFormats?: MediaFormatSupport;
93
+ }
94
+ /**
95
+ * Media content for LLM input (images, audio, video).
96
+ * Used to pass media to multimodal models.
97
+ */
98
+ export interface MediaContent {
99
+ /** Type of media */
100
+ type: MediaType;
101
+ /** Format of the data */
102
+ format: 'base64' | 'url';
103
+ /** MIME type (e.g., "image/png", "audio/mp3", "video/mp4") */
104
+ mimeType: string;
105
+ /** Base64 data (without prefix) or URL */
106
+ data: string;
107
+ /** Original field name from input (for debugging/logging) */
108
+ fieldName?: string;
109
+ }
110
+ /**
111
+ * Generated media from LLM output (Imagen, Veo, GPT-4o audio).
112
+ * Returned when models generate images, audio, or video.
113
+ */
114
+ export interface GeneratedMedia {
115
+ /** Type of generated media */
116
+ type: MediaType;
117
+ /** MIME type of the generated media */
118
+ mimeType: string;
119
+ /** Base64 data or URL depending on output format configuration */
120
+ data: string;
121
+ }
122
+ /**
123
+ * Required capabilities detected from a schema
124
+ */
125
+ export interface RequiredCapabilities {
126
+ visionInput?: boolean;
127
+ audioInput?: boolean;
128
+ videoInput?: boolean;
129
+ imageOutput?: boolean;
130
+ audioOutput?: boolean;
131
+ videoOutput?: boolean;
132
+ }
133
+ /**
134
+ * Detect required capabilities from input and output schemas.
135
+ * Returns which media capabilities are required.
136
+ */
137
+ export declare function detectRequiredCapabilities(inputSchema?: Record<string, unknown> | null, outputSchema?: Record<string, unknown> | null): RequiredCapabilities;
138
+ /**
139
+ * Model pricing structure with multimodal support.
140
+ * All costs are in cents.
141
+ *
142
+ * Text costs: per 1M tokens
143
+ * Image costs: per image
144
+ * Audio costs: per minute
145
+ * Video costs: per minute
146
+ */
147
+ export interface ModelPricing {
148
+ input: number;
149
+ output: number;
150
+ imageInput?: number;
151
+ imageOutput?: number;
152
+ audioInput?: number;
153
+ audioOutput?: number;
154
+ videoInput?: number;
155
+ videoOutput?: number;
156
+ }
157
+ /**
158
+ * Multimodal usage input for cost estimation
159
+ */
160
+ export interface MultimodalUsage {
161
+ inputTokens?: number;
162
+ outputTokens?: number;
163
+ imagesInput?: number;
164
+ imagesOutput?: number;
165
+ audioInputMinutes?: number;
166
+ audioOutputMinutes?: number;
167
+ videoInputMinutes?: number;
168
+ videoOutputMinutes?: number;
169
+ }
170
+ /**
171
+ * Estimate cost in cents for token usage (text only)
172
+ * @param pricing - Model pricing configuration
173
+ * @param inputTokens - Number of input tokens
174
+ * @param outputTokens - Number of output tokens
175
+ */
176
+ export declare function estimateCost(pricing: ModelPricing, inputTokens: number, outputTokens: number): number;
177
+ /**
178
+ * Estimate cost in cents for multimodal usage
179
+ * @param pricing - Model pricing configuration
180
+ * @param usage - Multimodal usage details
181
+ */
182
+ export declare function estimateMultimodalCost(pricing: ModelPricing, usage: MultimodalUsage): number;
183
+ /**
184
+ * Format cost in cents to a readable string (e.g., "$0.0015" or "$1.50")
185
+ */
186
+ export declare function formatCost(costCents: number): string;
187
+ /**
188
+ * Format cost per million tokens for display
189
+ */
190
+ export declare function formatCostPerMillion(pricing: ModelPricing): string;
191
+ export interface JsonSchema {
192
+ type?: string;
193
+ properties?: Record<string, JsonSchema>;
194
+ items?: JsonSchema;
195
+ required?: string[];
196
+ description?: string;
197
+ enum?: (string | number | boolean)[];
198
+ default?: unknown;
199
+ format?: string;
200
+ minimum?: number;
201
+ maximum?: number;
202
+ minLength?: number;
203
+ maxLength?: number;
204
+ pattern?: string;
205
+ additionalProperties?: boolean | JsonSchema;
206
+ [key: string]: unknown;
207
+ }
208
+ /**
209
+ * @description ShapeShyft user account, linked to Firebase Authentication.
210
+ * Created on first login and referenced by entity membership for multi-tenant access.
211
+ */
212
+ export interface User {
213
+ /** Internal database identifier */
214
+ id: string;
215
+ /** Firebase Authentication UID -- the primary external identity used to authenticate API requests */
216
+ firebase_uid: string;
217
+ /** User email address from Firebase Auth profile (may be null if auth provider omits it) */
218
+ email: string | null;
219
+ /** User display name from Firebase Auth profile */
220
+ display_name: string | null;
221
+ /** Timestamp when the user record was first created */
222
+ created_at: Date | null;
223
+ /** Timestamp of the most recent profile update */
224
+ updated_at: Date | null;
225
+ }
226
+ /**
227
+ * @description A ShapeShyft project that groups endpoints under a single API key.
228
+ * Projects are scoped to an entity and serve as the top-level organizational unit
229
+ * for managing AI endpoints.
230
+ */
231
+ export interface Project {
232
+ /** Unique identifier for this project */
233
+ uuid: string;
234
+ /** Entity (organization/personal) that owns this project */
235
+ entity_id: string;
236
+ /** URL-safe slug used in API paths (e.g., "my-project") */
237
+ project_name: string;
238
+ /** Human-readable project title shown in the UI */
239
+ display_name: string;
240
+ /** Optional description of the project's purpose */
241
+ description: string | null;
242
+ /** Whether this project is enabled; null treated as true */
243
+ is_active: boolean | null;
244
+ /** Truncated prefix of the project API key for display (e.g., "shyft_live_ab..."). Full key is never returned in Project responses. */
245
+ api_key_prefix: string | null;
246
+ /** Timestamp when the project API key was last generated or refreshed */
247
+ api_key_created_at: Date | null;
248
+ /** Timestamp when this project was created */
249
+ created_at: Date | null;
250
+ /** Timestamp of the most recent project update */
251
+ updated_at: Date | null;
252
+ }
253
+ /**
254
+ * Configuration for expected media output from an endpoint.
255
+ * Used to configure models like GPT-4o (audio), Imagen (images), Veo (video).
256
+ */
257
+ export interface MediaOutputConfig {
258
+ /** Whether the endpoint expects audio output */
259
+ audio?: boolean;
260
+ /** Whether the endpoint expects image output */
261
+ image?: boolean;
262
+ /** Whether the endpoint expects video output */
263
+ video?: boolean;
264
+ }
265
+ /**
266
+ * @description Endpoint fields common to every product. Products add their provider binding.
267
+ * Each endpoint defines a specific LLM interaction within a {@link Project}:
268
+ * the model, schemas, instructions, and access controls. Callers invoke
269
+ * endpoints via the project's API key.
270
+ */
271
+ export interface EndpointBase {
272
+ /** Unique identifier for this endpoint */
273
+ uuid: string;
274
+ /** Parent project UUID */
275
+ project_id: string;
276
+ /** URL-safe slug used in API paths (e.g., "analyze-text") */
277
+ endpoint_name: string;
278
+ /** Human-readable endpoint title shown in the UI */
279
+ display_name: string;
280
+ /** HTTP method accepted by this endpoint (GET for simple queries, POST for input payloads) */
281
+ http_method: HttpMethod;
282
+ /** LLM model identifier override; null uses the provider's default model */
283
+ model: string | null;
284
+ /** JSON Schema defining the expected input payload structure */
285
+ input_schema: JsonSchema | null;
286
+ /** JSON Schema defining the expected LLM output structure */
287
+ output_schema: JsonSchema | null;
288
+ /** System-level instructions prepended to the LLM prompt */
289
+ instructions: string | null;
290
+ /** Additional context appended to the LLM prompt for grounding */
291
+ context: string | null;
292
+ /** Whether this endpoint is enabled; null treated as true */
293
+ is_active: boolean | null;
294
+ /** Array of allowed IPv4 addresses. When null, all IPs are permitted (no restriction). */
295
+ ip_allowlist: string[] | null;
296
+ /** Declares which media types this endpoint is expected to generate (images, audio, video). Null means text-only output. */
297
+ expects_media_output: MediaOutputConfig | null;
298
+ /** Format for returning generated media: "base64" embeds data inline, "url" stores in cloud and returns a signed URL. Null means no media output. */
299
+ output_media_format: 'base64' | 'url' | null;
300
+ /** For audio/transcription endpoints (e.g., Whisper): the model used to extract structured data from the raw transcription text. Null means no post-processing. */
301
+ transcription_extraction_model: string | null;
302
+ /** Whether this endpoint uses web search for supported providers (OpenAI Responses API). */
303
+ web_search: boolean;
304
+ /**
305
+ * Sampling temperature for this endpoint's model.
306
+ *
307
+ * `null` means **say nothing**, which is what every endpoint did before this
308
+ * field existed, and the providers disagree about what that implies: OpenAI,
309
+ * Gemini and Groq apply their own default of 0, while Anthropic omits the
310
+ * parameter entirely because Opus 4.7+ and Sonnet 5 reject it outright. A 0
311
+ * stored here is therefore a real choice — repeatable answers — and not the
312
+ * same as leaving it unset.
313
+ *
314
+ * 0 to 2 is OpenAI's and Gemini's range; Anthropic's is 0 to 1.
315
+ */
316
+ temperature: number | null;
317
+ /**
318
+ * Ceiling on how many tokens the model may generate for one invocation.
319
+ *
320
+ * `null` means **no protection**: the generation runs until the model stops or
321
+ * the provider severs the connection, and the caller pays for everything
322
+ * produced on the way. Endpoints created before this field existed are null.
323
+ *
324
+ * A caller may lower this per invocation, never raise it -- see
325
+ * {@link AiExecutionRequest}.
326
+ */
327
+ max_output_tokens: number | null;
328
+ /** Lifetime number of invocations, counting both successes and failures. Incremented by the API on each call. */
329
+ call_count: number;
330
+ /** Timestamp when this endpoint was created */
331
+ created_at: Date | null;
332
+ /** Timestamp of the most recent endpoint update */
333
+ updated_at: Date | null;
334
+ }
335
+ /**
336
+ * @description A single API request log entry for usage tracking and billing.
337
+ * One record is created per endpoint invocation, capturing token counts,
338
+ * latency, cost, and caller metadata for analytics dashboards.
339
+ */
340
+ export interface UsageAnalytics {
341
+ /** Unique identifier for this analytics record */
342
+ uuid: string;
343
+ /** UUID of the endpoint that was invoked */
344
+ endpoint_id: string;
345
+ /** Timestamp when the request was received */
346
+ timestamp: Date;
347
+ /** Whether the LLM request completed successfully */
348
+ success: boolean;
349
+ /** Error message if the request failed; null on success */
350
+ error_message: string | null;
351
+ /** Number of input/prompt tokens consumed */
352
+ tokens_input: number | null;
353
+ /** Number of output/completion tokens generated */
354
+ tokens_output: number | null;
355
+ /** End-to-end request latency in milliseconds */
356
+ latency_ms: number | null;
357
+ /** Estimated cost of this request in cents (USD) */
358
+ estimated_cost_cents: number | null;
359
+ /** Arbitrary caller-supplied metadata (e.g., user_agent, ip, custom trace IDs). Stored as JSON and available for filtering in analytics queries. */
360
+ request_metadata: Record<string, unknown> | null;
361
+ }
362
+ export type StorageProvider = 'gcs' | 's3';
363
+ /**
364
+ * Storage configuration for an entity (safe version without credentials).
365
+ * Used for cloud storage of generated media.
366
+ */
367
+ export interface EntityStorageConfig {
368
+ uuid: string;
369
+ entity_id: string;
370
+ provider: StorageProvider;
371
+ bucket: string;
372
+ path_prefix: string | null;
373
+ created_at: Date | null;
374
+ updated_at: Date | null;
375
+ }
376
+ /**
377
+ * GCS service account credentials
378
+ */
379
+ export interface GCSCredentials {
380
+ type: 'service_account';
381
+ project_id: string;
382
+ private_key_id: string;
383
+ private_key: string;
384
+ client_email: string;
385
+ client_id: string;
386
+ auth_uri?: string;
387
+ token_uri?: string;
388
+ auth_provider_x509_cert_url?: string;
389
+ client_x509_cert_url?: string;
390
+ }
391
+ /**
392
+ * AWS S3 credentials
393
+ */
394
+ export interface S3Credentials {
395
+ access_key_id: string;
396
+ secret_access_key: string;
397
+ region: string;
398
+ }
399
+ export type StorageCredentials = GCSCredentials | S3Credentials;
400
+ /**
401
+ * Request to create or update storage configuration
402
+ */
403
+ export interface StorageConfigCreateRequest {
404
+ provider: StorageProvider;
405
+ bucket: string;
406
+ path_prefix?: string;
407
+ credentials: StorageCredentials;
408
+ }
409
+ export interface StorageConfigUpdateRequest {
410
+ bucket?: string;
411
+ path_prefix?: string | null;
412
+ credentials?: StorageCredentials;
413
+ }
414
+ /**
415
+ * @description User-level settings and organization preferences.
416
+ * Every authenticated user has settings; if none have been saved yet,
417
+ * the API returns auto-generated defaults with `is_default: true`.
418
+ */
419
+ export interface UserSettings {
420
+ /** Database row ID; null when settings are auto-generated defaults not yet persisted */
421
+ id: string | null;
422
+ /** Firebase Authentication UID linking these settings to a {@link User} */
423
+ firebase_uid: string;
424
+ /** Display name of the user's organization; null if not set */
425
+ organization_name: string | null;
426
+ /** URL-safe organization path used in routing (auto-generated from UID if not customized) */
427
+ organization_path: string;
428
+ /** Computed field (not stored in DB): true if settings are auto-generated defaults */
429
+ is_default: boolean;
430
+ /** Timestamp when these settings were first saved */
431
+ created_at: Date | null;
432
+ /** Timestamp of the most recent settings update */
433
+ updated_at: Date | null;
434
+ }
435
+ /**
436
+ * @description A personal API key that authenticates its owner against the
437
+ * admin routes, as an alternative to a Firebase ID token. A user may hold
438
+ * several. The secret itself is never present on this type -- see
439
+ * {@link UserApiKeyCreated} and {@link UserApiKeyRevealed} for the two responses
440
+ * that carry it.
441
+ *
442
+ * Not to be confused with a *project* API key (`sk_live_...`), which
443
+ * authenticates callers of a published AI endpoint. Personal keys are prefixed
444
+ * `shyft_`.
445
+ */
446
+ export interface UserApiKey {
447
+ /** Unique identifier for this key record */
448
+ uuid: string;
449
+ /** Firebase UID of the owner */
450
+ firebase_uid: string;
451
+ /** Human-readable label, e.g. "CLI on my laptop" */
452
+ key_name: string;
453
+ /** First characters of the key, for display (e.g. "shyft_ab12cd") */
454
+ key_prefix: string;
455
+ /** Whether the key is accepted; a deactivated key fails authentication */
456
+ is_active: boolean;
457
+ /** ISO 8601 timestamp of the most recent authenticated request, or null if unused */
458
+ last_used_at: string | null;
459
+ /** ISO 8601 timestamp when the key was created */
460
+ created_at: string | null;
461
+ /** ISO 8601 timestamp of the most recent update */
462
+ updated_at: string | null;
463
+ }
464
+ /**
465
+ * @description Response from creating a personal API key. This is the only
466
+ * response that returns the secret without being asked, and the value cannot be
467
+ * derived from any other endpoint except {@link UserApiKeyRevealed}.
468
+ */
469
+ export interface UserApiKeyCreated extends UserApiKey {
470
+ /** The full `shyft_...` key */
471
+ api_key: string;
472
+ }
473
+ /** @description Response from revealing an existing personal API key. */
474
+ export interface UserApiKeyRevealed {
475
+ /** The full `shyft_...` key */
476
+ api_key: string;
477
+ }
478
+ /**
479
+ * @description Identity of the authenticated caller, from `GET /users/me`.
480
+ * The only way an API-key client can learn its own Firebase UID, which the
481
+ * `/users/:userId/*` routes require.
482
+ */
483
+ export interface CurrentUser {
484
+ /** Firebase UID of the caller */
485
+ firebase_uid: string;
486
+ /** Caller's email, or null when unavailable */
487
+ email: string | null;
488
+ /** Whether the caller is a site admin */
489
+ siteAdmin: boolean;
490
+ /** Which credential authenticated this request */
491
+ auth_method: 'firebase' | 'api_key';
492
+ /** Display name from the Firebase profile, or null */
493
+ display_name: string | null;
494
+ }
495
+ export interface UserCreateRequest {
496
+ firebase_uid: string;
497
+ email: Optional<string>;
498
+ display_name: Optional<string>;
499
+ }
500
+ export interface UserUpdateRequest {
501
+ email: Optional<string>;
502
+ display_name: Optional<string>;
503
+ }
504
+ export interface UserApiKeyCreateRequest {
505
+ key_name: string;
506
+ }
507
+ export interface UserApiKeyUpdateRequest {
508
+ key_name: Optional<string>;
509
+ is_active: Optional<boolean>;
510
+ }
511
+ export interface UserSettingsUpdateRequest {
512
+ organization_name: Optional<string>;
513
+ organization_path: Optional<string>;
514
+ }
515
+ export interface ProjectCreateRequest {
516
+ project_name: string;
517
+ display_name: string;
518
+ description: Optional<string>;
519
+ }
520
+ export interface ProjectUpdateRequest {
521
+ project_name: Optional<string>;
522
+ display_name: Optional<string>;
523
+ description: Optional<string>;
524
+ is_active: Optional<boolean>;
525
+ }
526
+ export interface EndpointCreateRequestBase {
527
+ endpoint_name: string;
528
+ display_name: string;
529
+ http_method: Optional<HttpMethod>;
530
+ model: Optional<string>;
531
+ input_schema: Optional<JsonSchema>;
532
+ output_schema: Optional<JsonSchema>;
533
+ instructions: Optional<string>;
534
+ context: Optional<string>;
535
+ expects_media_output?: Optional<MediaOutputConfig>;
536
+ output_media_format?: Optional<'base64' | 'url'>;
537
+ transcription_extraction_model?: Optional<string>;
538
+ web_search?: Optional<boolean>;
539
+ /** Sampling temperature (0-2). Omit or pass null to leave it to the provider. */
540
+ temperature?: Optional<number>;
541
+ /**
542
+ * Output ceiling for this endpoint. Omit to receive
543
+ * {@link DEFAULT_MAX_OUTPUT_TOKENS}; pass `null` to explicitly opt out of
544
+ * runaway protection.
545
+ */
546
+ max_output_tokens?: Optional<number>;
547
+ }
548
+ export interface EndpointUpdateRequestBase {
549
+ endpoint_name?: Optional<string>;
550
+ display_name?: Optional<string>;
551
+ http_method?: Optional<HttpMethod>;
552
+ model?: Optional<string>;
553
+ input_schema?: Optional<JsonSchema>;
554
+ output_schema?: Optional<JsonSchema>;
555
+ instructions?: Optional<string>;
556
+ context?: Optional<string>;
557
+ is_active?: Optional<boolean>;
558
+ ip_allowlist?: Optional<string[]>;
559
+ expects_media_output?: Optional<MediaOutputConfig>;
560
+ output_media_format?: Optional<'base64' | 'url'>;
561
+ transcription_extraction_model?: Optional<string>;
562
+ web_search?: Optional<boolean>;
563
+ /** Sampling temperature (0-2). `null` clears it, leaving sampling to the provider. */
564
+ temperature?: Optional<number>;
565
+ /**
566
+ * Output ceiling for this endpoint. Omit to leave unchanged; pass `null` to
567
+ * remove the ceiling.
568
+ */
569
+ max_output_tokens?: Optional<number>;
570
+ }
571
+ /**
572
+ * Utility type for boolean-like query string parameters.
573
+ * URL query params are always strings, so boolean values are represented
574
+ * as the literal strings `'true'` or `'false'`, or `undefined` when absent.
575
+ */
576
+ export type BooleanQueryParam = 'true' | 'false' | undefined;
577
+ export interface ProjectQueryParams {
578
+ is_active: BooleanQueryParam;
579
+ }
580
+ export interface EndpointQueryParams {
581
+ is_active: BooleanQueryParam;
582
+ }
583
+ export interface UsageAnalyticsQueryParams {
584
+ endpoint_id: Optional<string>;
585
+ project_id: Optional<string>;
586
+ start_date: Optional<string>;
587
+ end_date: Optional<string>;
588
+ success: BooleanQueryParam;
589
+ }
590
+ export interface UsageAggregate {
591
+ total_requests: number;
592
+ successful_requests: number;
593
+ failed_requests: number;
594
+ total_tokens_input: number;
595
+ total_tokens_output: number;
596
+ total_estimated_cost_cents: number;
597
+ average_latency_ms: number;
598
+ }
599
+ export interface UsageByEndpoint extends UsageAggregate {
600
+ endpoint_id: string;
601
+ endpoint_name: string;
602
+ }
603
+ export interface UsageByDate extends UsageAggregate {
604
+ date: string;
605
+ }
606
+ /** Compound response from analytics API endpoint */
607
+ export interface AnalyticsResponse {
608
+ aggregate: UsageAggregate;
609
+ by_endpoint: UsageByEndpoint[];
610
+ }
611
+ export interface LlmRequest {
612
+ prompt: string;
613
+ system_prompt: Optional<string>;
614
+ output_schema: JsonSchema;
615
+ model: Optional<string>;
616
+ temperature: Optional<number>;
617
+ max_tokens: Optional<number>;
618
+ }
619
+ export interface LlmResponse {
620
+ content: unknown;
621
+ raw_response: string;
622
+ usage: {
623
+ prompt_tokens: number;
624
+ completion_tokens: number;
625
+ total_tokens: number;
626
+ };
627
+ model: string;
628
+ provider: LlmProvider;
629
+ }
630
+ /**
631
+ * Why the model stopped generating, normalized across providers.
632
+ *
633
+ * Providers spell this differently -- OpenAI `finish_reason`, Anthropic
634
+ * `stop_reason`, Gemini `finishReason` -- and use different vocabularies. These
635
+ * are the normalized values ShapeShyft reports.
636
+ */
637
+ export declare const FINISH_REASONS: readonly ["stop", "length", "content_filter", "tool_calls", "other"];
638
+ /** Why the model stopped generating. See {@link FINISH_REASONS}. */
639
+ export type FinishReason = (typeof FINISH_REASONS)[number];
640
+ /**
641
+ * Output ceiling applied to newly created endpoints when none is supplied.
642
+ *
643
+ * Chosen to be comfortably above a normal structured answer while still turning
644
+ * a runaway generation into a failure measured in seconds rather than the
645
+ * ~15 minutes a provider timeout takes. Endpoints may raise it, lower it, or set
646
+ * it to `null` to opt out entirely.
647
+ *
648
+ * This is a default for *new* endpoints only. It is never applied retroactively:
649
+ * an endpoint whose `max_output_tokens` is already `null` stays unprotected.
650
+ */
651
+ export declare const DEFAULT_MAX_OUTPUT_TOKENS = 8000;
652
+ export interface AiExecutionRequest {
653
+ input: unknown;
654
+ /**
655
+ * Lower the endpoint's output ceiling for this one call.
656
+ *
657
+ * Clamped to the endpoint's own ceiling, so this can only ever ask for
658
+ * *fewer* tokens -- it is not a way to escape an operator's limit. Ignored
659
+ * when the endpoint has no ceiling of its own.
660
+ */
661
+ max_output_tokens?: Optional<number>;
662
+ }
663
+ export interface AiExecutionResponse {
664
+ output: unknown;
665
+ usage: {
666
+ tokens_input: number;
667
+ tokens_output: number;
668
+ latency_ms: number;
669
+ estimated_cost_cents: number;
670
+ /**
671
+ * Why the model stopped. Absent when the provider did not report one.
672
+ * `'length'` means the answer was cut off at the ceiling, which is the
673
+ * difference between "the model ran away" and "the model returned
674
+ * something unparseable" -- different faults with different correct fixes.
675
+ */
676
+ finish_reason?: FinishReason;
677
+ };
678
+ /**
679
+ * True when generation stopped at a token ceiling. `output` is then a
680
+ * truncated answer that will usually fail schema validation.
681
+ */
682
+ truncated?: boolean;
683
+ /** Generated media (images, audio, video) from generative models */
684
+ generated_media?: GeneratedMedia[];
685
+ }
686
+ /** Response from /prompt endpoint - returns just the generated prompt */
687
+ export interface AiPromptResponse {
688
+ prompt: string;
689
+ }
690
+ /** Response when refreshing/generating a project API key */
691
+ export interface RefreshApiKeyResponse {
692
+ /** Full API key (only returned on generation/refresh) */
693
+ api_key: string;
694
+ /** Key prefix for display (e.g., "sk_live_ab...") */
695
+ api_key_prefix: string;
696
+ /** When the key was created/refreshed */
697
+ api_key_created_at: string;
698
+ }
699
+ /** Response when fetching the full API key */
700
+ export interface GetApiKeyResponse {
701
+ /** Full decrypted API key */
702
+ api_key: string;
703
+ }
704
+ /** Input for ApiHelper.prompt() */
705
+ export interface PromptInput {
706
+ inputData: unknown;
707
+ outputSchema: JsonSchema | null;
708
+ instructions: string | null;
709
+ context: string | null;
710
+ provider: LlmProvider;
711
+ }
712
+ /** Input for ApiHelper.request() */
713
+ export interface ApiHelperRequestInput {
714
+ prompt: string;
715
+ outputSchema: JsonSchema;
716
+ provider: LlmProvider;
717
+ providerConfig: {
718
+ apiKey?: string;
719
+ endpointUrl?: string;
720
+ model?: string;
721
+ };
722
+ options?: {
723
+ model?: string;
724
+ temperature?: number;
725
+ maxTokens?: number;
726
+ };
727
+ }
728
+ /** Output from ApiHelper.request() */
729
+ export interface ApiHelperRequestOutput {
730
+ apiPayload: Record<string, unknown>;
731
+ endpointUrl: string;
732
+ provider: LlmProvider;
733
+ }
734
+ /**
735
+ * Create a typed success response wrapping the given data.
736
+ *
737
+ * @example
738
+ * ```typescript
739
+ * import { successResponse, type Project } from './index.js';
740
+ *
741
+ * const project: Project = { uuid: '...', entity_id: '...', project_name: 'my-project', display_name: 'My Project', description: null, is_active: true, api_key_prefix: null, api_key_created_at: null, created_at: new Date(), updated_at: new Date() };
742
+ * const response = successResponse<Project>(project);
743
+ * // { success: true, data: { uuid: '...', project_name: 'my-project', ... }, timestamp: '2026-01-15T...' }
744
+ * ```
745
+ */
746
+ export declare function successResponse<T>(data: T): BaseResponse<T>;
747
+ /**
748
+ * Create a typed error response with the given error message.
749
+ *
750
+ * @example
751
+ * ```typescript
752
+ * import { errorResponse } from './index.js';
753
+ *
754
+ * const response = errorResponse('Project not found');
755
+ * // { success: false, error: 'Project not found', timestamp: '2026-01-15T...' }
756
+ *
757
+ * // In an API handler:
758
+ * if (!project) {
759
+ * return c.json(errorResponse('Project not found'), 404);
760
+ * }
761
+ * ```
762
+ */
763
+ export declare function errorResponse(error: string): BaseResponse<never>;
764
+ export type ProjectListResponse = BaseResponse<Project[]>;
765
+ export type ProjectResponse = BaseResponse<Project>;
766
+ export type UserSettingsResponse = BaseResponse<UserSettings>;
767
+ export type AnalyticsApiResponse = BaseResponse<AnalyticsResponse>;
768
+ export type AiExecutionApiResponse = BaseResponse<AiExecutionResponse>;
769
+ export type AiPromptApiResponse = BaseResponse<AiPromptResponse>;
770
+ export type RefreshApiKeyApiResponse = BaseResponse<RefreshApiKeyResponse>;
771
+ export type GetApiKeyApiResponse = BaseResponse<GetApiKeyResponse>;
772
+ export type UserApiKeyListResponse = BaseResponse<UserApiKey[]>;
773
+ export type UserApiKeyResponse = BaseResponse<UserApiKey>;
774
+ export type UserApiKeyCreatedResponse = BaseResponse<UserApiKeyCreated>;
775
+ export type UserApiKeyRevealedResponse = BaseResponse<UserApiKeyRevealed>;
776
+ export type CurrentUserResponse = BaseResponse<CurrentUser>;
777
+ export type HealthCheckResponse = BaseResponse<HealthCheckData>;
778
+ export interface HealthCheckData {
779
+ name: string;
780
+ version: string;
781
+ status: string;
782
+ }
783
+ /**
784
+ * Provider configuration returned from the API
785
+ */
786
+ export interface ProviderConfig {
787
+ id: LlmProvider;
788
+ name: string;
789
+ description: string;
790
+ allowsCustomModel: boolean;
791
+ defaultModel: string;
792
+ requiresEndpointUrl: boolean;
793
+ }
794
+ /**
795
+ * Model information with capabilities and pricing
796
+ */
797
+ export interface ModelInfo {
798
+ id: string;
799
+ capabilities: ModelCapabilities;
800
+ pricing: ModelPricing;
801
+ }
802
+ /**
803
+ * Response from GET /providers/:provider/models
804
+ */
805
+ export interface ProviderModelsResponse {
806
+ provider: ProviderConfig;
807
+ models: ModelInfo[];
808
+ }
809
+ export type ProviderListResponse = BaseResponse<ProviderConfig[]>;
810
+ export type ProviderResponse = BaseResponse<ProviderConfig>;
811
+ export type ProviderModelsApiResponse = BaseResponse<ProviderModelsResponse>;
812
+ //# sourceMappingURL=index.d.ts.map