getaiapi 1.0.0-alpha.3 → 1.0.0-alpha.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.
package/README.md CHANGED
@@ -115,6 +115,48 @@ const cutout = await generate({
115
115
  })
116
116
  ```
117
117
 
118
+ ## Async Job Control
119
+
120
+ For long-running jobs (video generation, training), you can submit a job and poll for status separately instead of blocking until completion.
121
+
122
+ ```typescript
123
+ import { submit, poll } from 'getaiapi'
124
+
125
+ // Submit — returns immediately with the provider's task ID
126
+ const job = await submit({
127
+ model: 'veo3.1',
128
+ prompt: 'a timelapse of a flower blooming',
129
+ })
130
+
131
+ console.log(job.id) // provider task ID
132
+ console.log(job.status) // 'pending' | 'processing' | 'completed'
133
+
134
+ // Poll — check status manually (call in a loop, on a timer, etc.)
135
+ let result = await poll(job)
136
+
137
+ while (result.status === 'pending' || result.status === 'processing') {
138
+ await new Promise(r => setTimeout(r, 2000))
139
+ result = await poll(job)
140
+ }
141
+
142
+ if (result.status === 'completed') {
143
+ console.log(result.outputs[0].url)
144
+ }
145
+ ```
146
+
147
+ Synchronous providers (like OpenRouter) return `status: 'completed'` from `submit()` immediately -- check status before polling.
148
+
149
+ `submitAndPoll()` is an alias for `generate()` that makes the blocking behavior explicit:
150
+
151
+ ```typescript
152
+ import { submitAndPoll } from 'getaiapi'
153
+
154
+ const result = await submitAndPoll({
155
+ model: 'flux-schnell',
156
+ prompt: 'a cat in space',
157
+ })
158
+ ```
159
+
118
160
  ## Configuration
119
161
 
120
162
  ### Option 1: Environment Variables
@@ -302,6 +344,40 @@ interface OutputItem {
302
344
  }
303
345
  ```
304
346
 
347
+ ### `submit(request: GenerateRequest): Promise<SubmitResponse>`
348
+
349
+ Submits a job to the provider and returns immediately without waiting for completion. Returns the provider's task ID and enough context to poll later.
350
+
351
+ ```typescript
352
+ interface SubmitResponse {
353
+ id: string // provider's task/request ID
354
+ model: string // canonical model name
355
+ provider: ProviderName // which provider handled it
356
+ endpoint: string // needed for polling
357
+ status: 'pending' | 'processing' | 'completed'
358
+ }
359
+ ```
360
+
361
+ ### `poll(job: SubmitResponse): Promise<PollResponse>`
362
+
363
+ Checks the status of a submitted job once. Returns current status, and includes mapped outputs and metadata when completed.
364
+
365
+ ```typescript
366
+ interface PollResponse {
367
+ id: string
368
+ model: string
369
+ provider: ProviderName
370
+ status: 'completed' | 'failed' | 'processing' | 'pending'
371
+ outputs?: OutputItem[] // populated when completed
372
+ metadata?: GenerateResponse['metadata'] // populated when completed
373
+ error?: string // populated when failed
374
+ }
375
+ ```
376
+
377
+ ### `submitAndPoll(request: GenerateRequest): Promise<GenerateResponse>`
378
+
379
+ Alias for `generate()`. Submits a job and polls until completion. Use this when you want the blocking behavior but want to be explicit about it.
380
+
305
381
  ### `listModels(filters?: ListModelsFilters): ModelEntry[]`
306
382
 
307
383
  Returns all models in the registry. Accepts optional filters:
@@ -71935,8 +71935,7 @@ var adapters = {
71935
71935
  "openrouter": openRouterAdapter
71936
71936
  };
71937
71937
  var DEFAULT_TIMEOUT_MS = 12e4;
71938
- async function generate(request) {
71939
- const startTime = Date.now();
71938
+ async function _prepare(request) {
71940
71939
  if (!request.model) throw new ValidationError("model", "model is required");
71941
71940
  const auth = new AuthManager();
71942
71941
  const model = resolveModel(request.model, auth.availableProviders());
@@ -71965,6 +71964,80 @@ async function generate(request) {
71965
71964
  });
71966
71965
  const adapter = adapters[binding.provider];
71967
71966
  const apiKey = auth.getKey(binding.provider);
71967
+ return { binding, adapter, apiKey, finalParams, model };
71968
+ }
71969
+ async function submit(request) {
71970
+ const { binding, adapter, apiKey, finalParams, model } = await _prepare(request);
71971
+ const timeoutMs = request.options?.timeout ?? DEFAULT_TIMEOUT_MS;
71972
+ const submitted = await withRetry(
71973
+ () => adapter.submit(binding.endpoint, finalParams, apiKey),
71974
+ { timeoutMs, provider: binding.provider, model: model.canonical_name }
71975
+ );
71976
+ return {
71977
+ id: submitted.id,
71978
+ model: model.canonical_name,
71979
+ provider: binding.provider,
71980
+ endpoint: binding.endpoint,
71981
+ status: submitted.status === "completed" ? "completed" : submitted.status
71982
+ };
71983
+ }
71984
+ async function poll(job) {
71985
+ const adapter = adapters[job.provider];
71986
+ if (!adapter) {
71987
+ throw new ValidationError("provider", `Unknown provider "${job.provider}"`);
71988
+ }
71989
+ const auth = new AuthManager();
71990
+ const apiKey = auth.getKey(job.provider);
71991
+ const result = await adapter.poll(job.id, apiKey, job.endpoint);
71992
+ if (result.status === "completed") {
71993
+ const model = resolveModel(job.model, auth.availableProviders());
71994
+ const binding = model.providers.find((p) => p.provider === job.provider);
71995
+ if (!binding) {
71996
+ throw new ProviderError(job.provider, job.model, 0, "Could not resolve provider binding for output mapping");
71997
+ }
71998
+ const outputs = mapOutput(result.output, binding.output_map);
71999
+ const rawOutput = typeof result.output === "object" && result.output !== null ? result.output : void 0;
72000
+ const metadata = {
72001
+ seed: rawOutput?.seed,
72002
+ safety_flagged: rawOutput ? Array.isArray(rawOutput.has_nsfw_concepts) ? rawOutput.has_nsfw_concepts.some((v) => v) : void 0 : void 0
72003
+ };
72004
+ if (rawOutput?.usage) {
72005
+ const usage = rawOutput.usage;
72006
+ metadata.tokens = usage.total_tokens;
72007
+ metadata.prompt_tokens = usage.prompt_tokens;
72008
+ metadata.completion_tokens = usage.completion_tokens;
72009
+ }
72010
+ return {
72011
+ id: job.id,
72012
+ model: job.model,
72013
+ provider: job.provider,
72014
+ status: "completed",
72015
+ outputs,
72016
+ metadata
72017
+ };
72018
+ }
72019
+ if (result.status === "failed") {
72020
+ return {
72021
+ id: job.id,
72022
+ model: job.model,
72023
+ provider: job.provider,
72024
+ status: "failed",
72025
+ error: result.error || "Generation failed"
72026
+ };
72027
+ }
72028
+ return {
72029
+ id: job.id,
72030
+ model: job.model,
72031
+ provider: job.provider,
72032
+ status: result.status
72033
+ };
72034
+ }
72035
+ async function submitAndPoll(request) {
72036
+ return generate(request);
72037
+ }
72038
+ async function generate(request) {
72039
+ const startTime = Date.now();
72040
+ const { binding, adapter, apiKey, finalParams, model } = await _prepare(request);
71968
72041
  const timeoutMs = request.options?.timeout ?? DEFAULT_TIMEOUT_MS;
71969
72042
  const submitted = await withRetry(
71970
72043
  () => adapter.submit(binding.endpoint, finalParams, apiKey),
@@ -72061,8 +72134,11 @@ export {
72061
72134
  uploadAsset,
72062
72135
  presignAsset,
72063
72136
  deleteAsset,
72137
+ submit,
72138
+ poll,
72139
+ submitAndPoll,
72064
72140
  generate,
72065
72141
  listModels,
72066
72142
  deriveCategory
72067
72143
  };
72068
- //# sourceMappingURL=chunk-HNBZJY7Z.js.map
72144
+ //# sourceMappingURL=chunk-DZVZ5HSO.js.map