@aeye/core 0.5.4 → 0.6.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/README.md +51 -4
- package/aeye-core-schema.md +11 -7
- package/dist/common.d.ts +30 -5
- package/dist/common.d.ts.map +1 -1
- package/dist/common.js +134 -129
- package/dist/common.js.map +1 -1
- package/dist/delivery.d.ts +39 -0
- package/dist/delivery.d.ts.map +1 -0
- package/dist/delivery.js +127 -0
- package/dist/delivery.js.map +1 -0
- package/dist/errors.d.ts +60 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +84 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/prompt.d.ts +101 -9
- package/dist/prompt.d.ts.map +1 -1
- package/dist/prompt.js +163 -141
- package/dist/prompt.js.map +1 -1
- package/dist/schema/analyze.d.ts +94 -0
- package/dist/schema/analyze.d.ts.map +1 -0
- package/dist/schema/analyze.js +221 -0
- package/dist/schema/analyze.js.map +1 -0
- package/dist/schema/any-value.d.ts +32 -0
- package/dist/schema/any-value.d.ts.map +1 -0
- package/dist/schema/any-value.js +77 -0
- package/dist/schema/any-value.js.map +1 -0
- package/dist/schema/budget.d.ts +114 -0
- package/dist/schema/budget.d.ts.map +1 -0
- package/dist/schema/budget.js +223 -0
- package/dist/schema/budget.js.map +1 -0
- package/dist/schema/consistency.d.ts +27 -0
- package/dist/schema/consistency.d.ts.map +1 -0
- package/dist/schema/consistency.js +110 -0
- package/dist/schema/consistency.js.map +1 -0
- package/dist/schema/cycle-breaker.d.ts +14 -0
- package/dist/schema/cycle-breaker.d.ts.map +1 -0
- package/dist/schema/cycle-breaker.js +157 -0
- package/dist/schema/cycle-breaker.js.map +1 -0
- package/dist/schema/decode.d.ts +31 -0
- package/dist/schema/decode.d.ts.map +1 -0
- package/dist/schema/decode.js +207 -0
- package/dist/schema/decode.js.map +1 -0
- package/dist/schema/descriptor.d.ts +300 -0
- package/dist/schema/descriptor.d.ts.map +1 -0
- package/dist/schema/descriptor.js +15 -0
- package/dist/schema/descriptor.js.map +1 -0
- package/dist/schema/dialects/anthropic.d.ts +34 -0
- package/dist/schema/dialects/anthropic.d.ts.map +1 -0
- package/dist/schema/dialects/anthropic.js +77 -0
- package/dist/schema/dialects/anthropic.js.map +1 -0
- package/dist/schema/dialects/google.d.ts +47 -0
- package/dist/schema/dialects/google.d.ts.map +1 -0
- package/dist/schema/dialects/google.js +91 -0
- package/dist/schema/dialects/google.js.map +1 -0
- package/dist/schema/dialects/lenient.d.ts +4 -0
- package/dist/schema/dialects/lenient.d.ts.map +1 -0
- package/dist/schema/dialects/lenient.js +26 -0
- package/dist/schema/dialects/lenient.js.map +1 -0
- package/dist/schema/dialects/openai.d.ts +40 -0
- package/dist/schema/dialects/openai.d.ts.map +1 -0
- package/dist/schema/dialects/openai.js +81 -0
- package/dist/schema/dialects/openai.js.map +1 -0
- package/dist/schema/dialects/xai.d.ts +23 -0
- package/dist/schema/dialects/xai.d.ts.map +1 -0
- package/dist/schema/dialects/xai.js +53 -0
- package/dist/schema/dialects/xai.js.map +1 -0
- package/dist/schema/enum-values.d.ts +44 -0
- package/dist/schema/enum-values.d.ts.map +1 -0
- package/dist/schema/enum-values.js +56 -0
- package/dist/schema/enum-values.js.map +1 -0
- package/dist/schema/expressible.d.ts +59 -0
- package/dist/schema/expressible.d.ts.map +1 -0
- package/dist/schema/expressible.js +161 -0
- package/dist/schema/expressible.js.map +1 -0
- package/dist/schema/index.d.ts +20 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +20 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/json-schema.d.ts +64 -0
- package/dist/schema/json-schema.d.ts.map +1 -0
- package/dist/schema/json-schema.js +2 -0
- package/dist/schema/json-schema.js.map +1 -0
- package/dist/schema/registry.d.ts +73 -0
- package/dist/schema/registry.d.ts.map +1 -0
- package/dist/schema/registry.js +135 -0
- package/dist/schema/registry.js.map +1 -0
- package/dist/schema/strictify.d.ts +19 -0
- package/dist/schema/strictify.d.ts.map +1 -0
- package/dist/schema/strictify.js +237 -0
- package/dist/schema/strictify.js.map +1 -0
- package/dist/schema/to-json-schema.d.ts +29 -0
- package/dist/schema/to-json-schema.d.ts.map +1 -0
- package/dist/schema/to-json-schema.js +691 -0
- package/dist/schema/to-json-schema.js.map +1 -0
- package/dist/schema/walk-key.d.ts +24 -0
- package/dist/schema/walk-key.d.ts.map +1 -0
- package/dist/schema/walk-key.js +33 -0
- package/dist/schema/walk-key.js.map +1 -0
- package/dist/to.js +1 -1
- package/dist/to.js.map +1 -1
- package/dist/tool.d.ts +32 -3
- package/dist/tool.d.ts.map +1 -1
- package/dist/tool.js +41 -0
- package/dist/tool.js.map +1 -1
- package/dist/types.d.ts +265 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -1
- package/dist/types.js.map +1 -1
- package/package.json +72 -72
- package/dist/schema.d.ts +0 -840
- package/dist/schema.d.ts.map +0 -1
- package/dist/schema.js +0 -2478
- package/dist/schema.js.map +0 -1
package/README.md
CHANGED
|
@@ -408,6 +408,42 @@ const adaptivePrompt = new Prompt({
|
|
|
408
408
|
});
|
|
409
409
|
```
|
|
410
410
|
|
|
411
|
+
## Schema Fallbacks
|
|
412
|
+
|
|
413
|
+
A provider that rejects a schema throws `SchemaRejectedError` with a `target` naming the output or the tool. The prompt then steps down its `schemaFallbacks`, by default `SCHEMA_FALLBACKS`: the rejected schema goes non-strict, then the output moves to JSON mode with its schema in the prompt (`schemaDelivery: 'json'`), then to plain text with its schema in the prompt (`'prompt'`). Steps stay on the request for the rest of the run, and each emits a `schemaFallback` event.
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { Prompt, SCHEMA_FALLBACKS } from '@aeye/core';
|
|
417
|
+
|
|
418
|
+
const prompt = new Prompt({
|
|
419
|
+
name: 'extract',
|
|
420
|
+
description: 'Extracts fields',
|
|
421
|
+
content: 'Extract the fields from: {{text}}',
|
|
422
|
+
schema,
|
|
423
|
+
schemaFallbacks: SCHEMA_FALLBACKS.filter(step => step.name !== 'json'),
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Providers use `schemaRejection(request, error)` to classify a bad request and `deliverSchema(request)` to send a `json` or `prompt` schema without changing the prompt's request.
|
|
428
|
+
|
|
429
|
+
## Error Kinds
|
|
430
|
+
|
|
431
|
+
Every prompt failure has `kind: 'model' | 'tool'`. `ToolInputError` (an unknown tool or bad arguments) and `OutputValidationError` (output that isn't JSON or fails the schema or `validate`) are model mistakes, fed back to the model for another try. `ToolExecutionError` is a tool's own throw. They appear on the `toolError` event's `failure`, on tool result messages' `failure`, and on the `textReset` event's `error`. A prompt that gives up throws a `PromptError` whose `cause` is the last failure.
|
|
432
|
+
|
|
433
|
+
## Review
|
|
434
|
+
|
|
435
|
+
`review` judges the parsed, validated output before it's returned. Feedback becomes a user message and the model answers again, up to `reviewRetries` times; after that the prompt throws a `PromptError` caused by a `ReviewRejectedError` with the last output.
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
const answer = new Prompt({
|
|
439
|
+
name: 'answer',
|
|
440
|
+
description: 'Answers briefly',
|
|
441
|
+
content: 'Answer in under 20 words: {{question}}',
|
|
442
|
+
input: (input: { question: string }) => input,
|
|
443
|
+
review: (output) => output.split(' ').length < 20 ? { pass: true } : { feedback: 'Use fewer than 20 words.' },
|
|
444
|
+
});
|
|
445
|
+
```
|
|
446
|
+
|
|
411
447
|
## Model Capabilities
|
|
412
448
|
|
|
413
449
|
@aeye uses a capability system for automatic model selection. Models advertise their capabilities and the library selects the best match for each request:
|
|
@@ -421,6 +457,8 @@ const adaptivePrompt = new Prompt({
|
|
|
421
457
|
| `audio` | Text-to-speech |
|
|
422
458
|
| `hearing` | Speech-to-text |
|
|
423
459
|
| `embedding` | Text embeddings |
|
|
460
|
+
| `rerank` | Ordering documents by relevance |
|
|
461
|
+
| `decision` | Typed answers (probabilities, choices, scores) from decision models |
|
|
424
462
|
| `tools` | Function/tool calling |
|
|
425
463
|
| `json` | JSON output mode |
|
|
426
464
|
| `structured` | Structured outputs with schemas |
|
|
@@ -541,7 +579,10 @@ class Prompt<TContext, TMetadata, TName extends string, TInput extends object, T
|
|
|
541
579
|
- `content: string` - Handlebars template for the system/user message
|
|
542
580
|
- `input?: (input: TInput, ctx: Context<TContext, TMetadata>) => Record<string, any>` - Maps raw input to template variables
|
|
543
581
|
- `schema?: ZodType<TOutput> | ((input: TInput | undefined, ctx: Context<TContext, TMetadata>) => ZodType<TOutput> | false)` - Output schema; `false` disables structured output
|
|
544
|
-
- `strict?: boolean` -
|
|
582
|
+
- `strict?: boolean | number` - Strict tool inputs: `true` requires, `false` disables, a number is a preference priority (default: `1`)
|
|
583
|
+
- `format?: ToolTextFormat` - Take free text (`{ type: 'text' }`) or grammar-constrained text (`{ type: 'grammar', syntax: 'lark' | 'regex', definition }`) as `input` instead of JSON; use `TEXT_TOOL_SCHEMA` as the schema
|
|
584
|
+
- `defer?: boolean` - Load only when the model searches for it (OpenAI tool search)
|
|
585
|
+
- `async?: boolean` - The model keeps working while the tool runs (OpenAI Responses)
|
|
545
586
|
- `config?: Partial<Request> | ((input: TInput | undefined, ctx: Context<TContext, TMetadata>) => Partial<Request> | false)` - AI request overrides
|
|
546
587
|
- `tools?: TTools` - Tools the prompt may call
|
|
547
588
|
- `toolExecution?: 'sequential' | 'parallel' | 'immediate'` - Tool execution mode
|
|
@@ -549,8 +590,12 @@ class Prompt<TContext, TMetadata, TName extends string, TInput extends object, T
|
|
|
549
590
|
- `toolIterations?: number` - Max tool-calling iterations (default: 3)
|
|
550
591
|
- `toolsMax?: number` - Max successful tool calls
|
|
551
592
|
- `outputRetries?: number` - Retry count for invalid structured outputs
|
|
593
|
+
- `schemaDelivery?: 'auto' | 'structured' | 'json' | 'prompt'` - How the output schema reaches the model (default: `'auto'`)
|
|
594
|
+
- `schemaFallbacks?: readonly SchemaFallback[]` - Steps taken when a provider rejects a schema (default: the context's, then `SCHEMA_FALLBACKS`)
|
|
552
595
|
- `metadata?: TMetadata` - Static metadata for this prompt
|
|
553
596
|
- `validate?: (output: TOutput, ctx: Context<TContext, TMetadata>) => void | Promise<void>` - Post-parse validation
|
|
597
|
+
- `review?: (output: TDecoded, context: PromptReviewContext) => PromptReview | Promise<PromptReview>` - Review the valid output: `{ pass: true }` or `{ feedback }` for another round
|
|
598
|
+
- `reviewRetries?: number` - Rounds the model gets to answer review feedback (default: 1)
|
|
554
599
|
- `applicable?: (ctx: Context<TContext, TMetadata>) => boolean | Promise<boolean>` - Availability check
|
|
555
600
|
|
|
556
601
|
**Methods:**
|
|
@@ -626,6 +671,8 @@ interface CoreContextFields {
|
|
|
626
671
|
outputRetries?: number;
|
|
627
672
|
// Number of context-trimming retries (default: 1)
|
|
628
673
|
forgetRetries?: number;
|
|
674
|
+
// Steps a prompt takes when a provider rejects a schema (default: SCHEMA_FALLBACKS)
|
|
675
|
+
schemaFallbacks?: readonly SchemaFallback[];
|
|
629
676
|
|
|
630
677
|
// Abort signal for cancellation
|
|
631
678
|
signal?: AbortSignal;
|
|
@@ -644,9 +691,9 @@ interface Request {
|
|
|
644
691
|
maxTokens?: number;
|
|
645
692
|
stop?: string | string[];
|
|
646
693
|
tools?: ToolDefinition[];
|
|
647
|
-
toolChoice?: 'auto' | 'required' | 'none' | {
|
|
648
|
-
responseFormat?: 'text' | 'json' | { type:
|
|
649
|
-
reason?: { effort?: '
|
|
694
|
+
toolChoice?: 'auto' | 'required' | 'none' | { tool: string } | { allowed: string[]; required?: boolean };
|
|
695
|
+
responseFormat?: 'text' | 'json' | { type: ZodType; strict: boolean | number };
|
|
696
|
+
reason?: { effort?: ReasoningEffort; maxTokens?: number; summary?: 'auto' | 'concise' | 'detailed'; exclude?: boolean };
|
|
650
697
|
frequencyPenalty?: number;
|
|
651
698
|
presencePenalty?: number;
|
|
652
699
|
seed?: number;
|
package/aeye-core-schema.md
CHANGED
|
@@ -35,7 +35,7 @@ A descriptor (see `src/schema.ts` line ~26 for the fully documented interface) d
|
|
|
35
35
|
| `supportsRecursion` | Whether `$ref` self-reference works. |
|
|
36
36
|
| `maxStrictTools` / `maxStrictOptionalParams` / `maxStrictUnionTypes` | Per-request slot budgets (`undefined` = no documented limit). |
|
|
37
37
|
| `schemaSizeLimits` | Per-SCHEMA size ceilings — properties, nesting, total string characters, enum values (`undefined` = no documented limit) — see below. |
|
|
38
|
-
| `maxEnumValues` | Opt-in ceiling on how many values ONE emitted `enum` may carry (`undefined` = no cap,
|
|
38
|
+
| `maxEnumValues` | Opt-in ceiling on how many values ONE emitted `enum` may carry (`undefined` = no cap). `GOOGLE_STRICT`/`GOOGLE_NON_STRICT` declare 40, a MEASURED response to a real provider rejection; every other built-in declares none — see below. |
|
|
39
39
|
|
|
40
40
|
### `schemaSizeLimits` — how BIG one strict schema may be
|
|
41
41
|
|
|
@@ -60,7 +60,7 @@ Scope is Structured Outputs — a tool carrying `strict: true`, or a `json_schem
|
|
|
60
60
|
|
|
61
61
|
The measurement is taken from the **Zod** schema rather than from the emitted JSON, so where an encoding is descriptor-dependent it counts the widest one (a record as its `{key, value}` pair form, a tuple as its numeric-key form). Over-counting costs strictness on a schema that would have fitted; under-counting costs an HTTP 400, so the rounding goes up. `$defs` entry names are not counted: they are generated at emit time, few, and short against a 120,000-character budget.
|
|
62
62
|
|
|
63
|
-
### `maxEnumValues` — an opt-in dialect ceiling that WIDENS, and why
|
|
63
|
+
### `maxEnumValues` — an opt-in dialect ceiling that WIDENS, and why only Google sets one
|
|
64
64
|
|
|
65
65
|
Some providers may reject a schema whose `enum` is simply too long. That is **not** one of the per-request budgets above: those are strict-mode allowances the `SchemaBudget` spends across a whole request, degrading an item that no longer fits to the family's non-strict descriptor, whereas this one would fire whatever the strictness, so it is enforced structurally at the point an `enum` is emitted.
|
|
66
66
|
|
|
@@ -75,15 +75,19 @@ Truncating would make the values past the cap **unreachable** — the wire schem
|
|
|
75
75
|
|
|
76
76
|
The trade is enforcement: a widened node no longer rejects a value structurally, so whatever validates the model's output afterwards must. `Tool.parse` does — it runs against the ORIGINAL zod schema, whose `enum` is untouched — so a hallucinated member comes back as a normal, re-promptable validation error.
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
**`GOOGLE_STRICT`/`GOOGLE_NON_STRICT` declare `maxEnumValues: 40`. Every other built-in declares no cap.** The field exists because a large `enum` was believed to make Gemini answer `400 INVALID_ARGUMENT`. An initial round of measurement against `google/gemini-3-flash-preview` through OpenRouter (2026-08-23) looked like it disproved that: single-parameter enums at 50/64/72/80/96/128/256/512/1024/**2048** SYNTHETIC values (`name_0`, `name_1`, …) all returned HTTP 200, as did an eleven-tool roster modelled on a real kind-authoring agent with a 96-value enum on one tool.
|
|
79
79
|
|
|
80
|
-
A
|
|
80
|
+
**That conclusion was wrong, because none of it used the CONTENT of a real session.** A third round replayed the exact wire bytes of an actual product request — `fn_load`'s `names` array, enum-constrained to a real session's 98 known component/fn names (`default_renderer`, `QueryWidget`, `ConfirmPrompt`, `list_widget_types`, …) — and it 400'd, reproducibly, twice, byte-for-byte identical to what was actually sent. Bisecting that real value list: 90 values passes, 93 fails. Bisecting what differs from the earlier synthetic probes: 98 SHORT synthetic values (284 total characters) pass; 206 short values matching the real list's total character count (714 characters) also pass; only the real, longer, identifier-shaped values fail, and only past ~92 of them. So the limit tracks neither raw member count nor total character/byte budget — most likely actual tokenized grammar-state count, which short repetitive synthetic strings compress far below what real identifier text does at the same count or character budget. This is why the first two rounds' synthetic and lightly-realistic probes never tripped it.
|
|
81
81
|
|
|
82
|
-
The
|
|
82
|
+
The widen-to-string fallback this field triggers was verified against the exact failing real schema: dropping `enum` and putting the same 98 values into the `description` of a plain string field returned HTTP 200 with the expected tool call — confirming the fallback mechanism actually fixes the failure it exists for, not just a synthetic stand-in.
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
`40` is not a measured edge — it is a conservative floor with roughly 2x margin under the real one (90 passes / 93 fails) measured on this one real value set. Given the failure tracks content, not just count, a different session's actual name list could plausibly fail at a different count; 40 was also the cap the product that surfaced this ran under in production for months, which is corroborating evidence it holds in practice, not just in this one measurement.
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
The reliability comparison from the earlier rounds still stands and is why a cap is preferable to leaving every enum uncapped "to be safe" at a much lower number: `enum` vs plain-string-with-full-list, 10 trials each over confusable near-duplicate names at 96 and 512 values, scored 10/10 on-target with zero off-list answers for BOTH encodings. So there is no reliability cost to raising this cap later if a higher safe value is measured — only downside risk to leaving it too high.
|
|
87
|
+
|
|
88
|
+
One trap for whoever measures this next: with `max_tokens` at 64, a forced-tool probe can come back `finish_reason: "length"` with no tool call and empty content, which reads exactly like a grammar that produced nothing. It usually is not — this model spends reasoning tokens first. Give a forced-tool probe room before calling an empty completion a failure.
|
|
89
|
+
|
|
90
|
+
So: **set this only where a provider is MEASURED to reject a large enum using the SESSION'S OWN real content, not synthetic stand-ins, and set it conservatively below the measured edge until more value sets are tested.** An `enum` that fits is the more correct encoding, because it is the one the model cannot answer outside of.
|
|
87
91
|
|
|
88
92
|
### `anyEncoding` — and what each mode requires
|
|
89
93
|
|
package/dist/common.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Chunk, Events, Model, ModelInput, Reasoning, Response, Runner, Usage } from "./types";
|
|
1
|
+
import { Chunk, Events, GeneratedAudio, Model, ModelInput, Reasoning, Response, Runner, Usage } from "./types";
|
|
2
2
|
/**
|
|
3
3
|
* A flexible function type that can be:
|
|
4
4
|
* - A direct value of type R
|
|
@@ -145,6 +145,14 @@ export declare function getModel(input: ModelInput | undefined): Model | undefin
|
|
|
145
145
|
* @returns The aggregated Response object.
|
|
146
146
|
*/
|
|
147
147
|
export declare function getResponseFromChunks(chunks: Chunk[], model?: ModelInput): Response;
|
|
148
|
+
/**
|
|
149
|
+
* Appends a partial audio chunk onto accumulated audio.
|
|
150
|
+
*
|
|
151
|
+
* @param target - The audio accumulated so far.
|
|
152
|
+
* @param add - The partial audio to append.
|
|
153
|
+
* @returns The combined audio.
|
|
154
|
+
*/
|
|
155
|
+
export declare function accumulateAudio(target: GeneratedAudio | undefined, add: GeneratedAudio): GeneratedAudio;
|
|
148
156
|
/**
|
|
149
157
|
* Generates a plain text representation of reasoning data.
|
|
150
158
|
*
|
|
@@ -153,13 +161,30 @@ export declare function getResponseFromChunks(chunks: Chunk[], model?: ModelInpu
|
|
|
153
161
|
*/
|
|
154
162
|
export declare function getReasoningText(reasoning: Reasoning | undefined): string;
|
|
155
163
|
/**
|
|
156
|
-
* Accumulates reasoning
|
|
164
|
+
* Accumulates streamed reasoning: the reasoning so far with the next part
|
|
165
|
+
* appended, as a new object that shares nothing mutable with either input.
|
|
166
|
+
*
|
|
167
|
+
* Providers stream reasoning as deltas, never repeating what was sent, so
|
|
168
|
+
* `content` and each detail's `text`, `summary` and `data` concatenate. A
|
|
169
|
+
* detail continues an earlier one of the same type with the same id (when
|
|
170
|
+
* both have one) or index: OpenRouter sends a block's text and later its
|
|
171
|
+
* signature at one index, and Gemini's text and encrypted reasoning share
|
|
172
|
+
* index 0 under different types. The provider is whichever part names it.
|
|
157
173
|
*
|
|
158
|
-
* @param target - The
|
|
159
|
-
* @param add - The
|
|
160
|
-
* @returns - The
|
|
174
|
+
* @param target - The reasoning accumulated so far.
|
|
175
|
+
* @param add - The reasoning to append.
|
|
176
|
+
* @returns - The accumulated reasoning.
|
|
161
177
|
*/
|
|
162
178
|
export declare function accumulateReasoning(target: Reasoning | undefined, add?: Reasoning): Reasoning | undefined;
|
|
179
|
+
/**
|
|
180
|
+
* Whether reasoning goes back to a provider: it came from there, or names no
|
|
181
|
+
* provider. Signed and encrypted reasoning only verifies where it was made.
|
|
182
|
+
*
|
|
183
|
+
* @param reasoning - The reasoning of an earlier assistant turn.
|
|
184
|
+
* @param provider - The provider the conversation goes to.
|
|
185
|
+
* @returns - Whether to replay the reasoning.
|
|
186
|
+
*/
|
|
187
|
+
export declare function replaysTo(reasoning: Reasoning | undefined, provider: string): reasoning is Reasoning;
|
|
163
188
|
/**
|
|
164
189
|
* Converts a Response object into an array of Chunk objects.
|
|
165
190
|
*
|
package/dist/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAmB,MAAM,EAAY,KAAK,EAAE,UAAU,EAAE,SAAS,EAAY,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../src/common.ts"],"names":[],"mappings":"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"}
|
package/dist/common.js
CHANGED
|
@@ -127,6 +127,22 @@ export async function consumeAll(gen) {
|
|
|
127
127
|
}
|
|
128
128
|
return results;
|
|
129
129
|
}
|
|
130
|
+
/**
|
|
131
|
+
* Adds every count in `add` onto `target`, treating a missing count as zero.
|
|
132
|
+
*
|
|
133
|
+
* @param target - The counts to add into (mutated).
|
|
134
|
+
* @param add - The counts to add.
|
|
135
|
+
* @returns The target.
|
|
136
|
+
*/
|
|
137
|
+
function sumCounts(target, add) {
|
|
138
|
+
for (const key in add) {
|
|
139
|
+
const value = add[key];
|
|
140
|
+
if (value !== undefined) {
|
|
141
|
+
target[key] = (target[key] ?? 0) + value;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return target;
|
|
145
|
+
}
|
|
130
146
|
/**
|
|
131
147
|
* Accumulates usage statistics by adding values from one Usage object to another.
|
|
132
148
|
* Handles the nested structure matching ModelPricing.
|
|
@@ -139,92 +155,40 @@ export function accumulateUsage(target, add) {
|
|
|
139
155
|
if (!add) {
|
|
140
156
|
return;
|
|
141
157
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (add.text.cached !== undefined) {
|
|
154
|
-
target.text.cached = (target.text.cached || 0) + add.text.cached;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
// Accumulate audio usage
|
|
158
|
-
if (add.audio) {
|
|
159
|
-
if (!target.audio) {
|
|
160
|
-
target.audio = {};
|
|
161
|
-
}
|
|
162
|
-
if (add.audio.input !== undefined) {
|
|
163
|
-
target.audio.input = (target.audio.input || 0) + add.audio.input;
|
|
164
|
-
}
|
|
165
|
-
if (add.audio.output !== undefined) {
|
|
166
|
-
target.audio.output = (target.audio.output || 0) + add.audio.output;
|
|
167
|
-
}
|
|
168
|
-
if (add.audio.seconds !== undefined) {
|
|
169
|
-
target.audio.seconds = (target.audio.seconds || 0) + add.audio.seconds;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
// Accumulate image usage
|
|
158
|
+
if (add.text)
|
|
159
|
+
target.text = sumCounts(target.text ?? {}, add.text);
|
|
160
|
+
if (add.audio)
|
|
161
|
+
target.audio = sumCounts(target.audio ?? {}, add.audio);
|
|
162
|
+
if (add.reasoning)
|
|
163
|
+
target.reasoning = sumCounts(target.reasoning ?? {}, add.reasoning);
|
|
164
|
+
if (add.embeddings)
|
|
165
|
+
target.embeddings = sumCounts(target.embeddings ?? {}, add.embeddings);
|
|
166
|
+
if (add.tools)
|
|
167
|
+
target.tools = sumCounts(target.tools ?? {}, add.tools);
|
|
168
|
+
// Image input is a count; image output merges by quality and size
|
|
173
169
|
if (add.image) {
|
|
174
|
-
|
|
175
|
-
target.image = { output: [] };
|
|
176
|
-
}
|
|
170
|
+
const image = target.image ?? (target.image = {});
|
|
177
171
|
if (add.image.input !== undefined) {
|
|
178
|
-
|
|
172
|
+
image.input = (image.input ?? 0) + add.image.input;
|
|
173
|
+
}
|
|
174
|
+
if (add.image.tokens !== undefined) {
|
|
175
|
+
image.tokens = (image.tokens ?? 0) + add.image.tokens;
|
|
179
176
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
for (const addOutput of add.image.output ?? []) {
|
|
178
|
+
const outputs = image.output ?? (image.output = []);
|
|
179
|
+
const existing = outputs.find(o => o.quality === addOutput.quality &&
|
|
180
|
+
o.size.width === addOutput.size.width &&
|
|
181
|
+
o.size.height === addOutput.size.height);
|
|
182
|
+
if (existing) {
|
|
183
|
+
existing.count += addOutput.count;
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
const existing = target.image.output.find(o => o.quality === addOutput.quality &&
|
|
187
|
-
o.size.width === addOutput.size.width &&
|
|
188
|
-
o.size.height === addOutput.size.height);
|
|
189
|
-
if (existing) {
|
|
190
|
-
existing.count += addOutput.count;
|
|
191
|
-
}
|
|
192
|
-
else {
|
|
193
|
-
target.image.output.push({ ...addOutput });
|
|
194
|
-
}
|
|
185
|
+
else {
|
|
186
|
+
outputs.push({ ...addOutput });
|
|
195
187
|
}
|
|
196
188
|
}
|
|
197
189
|
}
|
|
198
|
-
// Accumulate reasoning usage
|
|
199
|
-
if (add.reasoning) {
|
|
200
|
-
if (!target.reasoning) {
|
|
201
|
-
target.reasoning = {};
|
|
202
|
-
}
|
|
203
|
-
if (add.reasoning.input !== undefined) {
|
|
204
|
-
target.reasoning.input = (target.reasoning.input || 0) + add.reasoning.input;
|
|
205
|
-
}
|
|
206
|
-
if (add.reasoning.output !== undefined) {
|
|
207
|
-
target.reasoning.output = (target.reasoning.output || 0) + add.reasoning.output;
|
|
208
|
-
}
|
|
209
|
-
if (add.reasoning.cached !== undefined) {
|
|
210
|
-
target.reasoning.cached = (target.reasoning.cached || 0) + add.reasoning.cached;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
// Accumulate embeddings usage
|
|
214
|
-
if (add.embeddings) {
|
|
215
|
-
if (!target.embeddings) {
|
|
216
|
-
target.embeddings = {};
|
|
217
|
-
}
|
|
218
|
-
if (add.embeddings.count !== undefined) {
|
|
219
|
-
target.embeddings.count = (target.embeddings.count || 0) + add.embeddings.count;
|
|
220
|
-
}
|
|
221
|
-
if (add.embeddings.tokens !== undefined) {
|
|
222
|
-
target.embeddings.tokens = (target.embeddings.tokens || 0) + add.embeddings.tokens;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
// Accumulate cost
|
|
226
190
|
if (add.cost !== undefined) {
|
|
227
|
-
target.cost = (target.cost
|
|
191
|
+
target.cost = (target.cost ?? 0) + add.cost;
|
|
228
192
|
}
|
|
229
193
|
}
|
|
230
194
|
/**
|
|
@@ -309,7 +273,7 @@ export function getResponseFromChunks(chunks, model = 'unknown') {
|
|
|
309
273
|
resp.model = chunk.model;
|
|
310
274
|
}
|
|
311
275
|
if (chunk.refusal) {
|
|
312
|
-
resp.refusal = chunk.refusal;
|
|
276
|
+
resp.refusal = (resp.refusal ?? '') + chunk.refusal;
|
|
313
277
|
}
|
|
314
278
|
if (chunk.toolCall) {
|
|
315
279
|
resp.toolCalls = resp.toolCalls || [];
|
|
@@ -319,9 +283,48 @@ export function getResponseFromChunks(chunks, model = 'unknown') {
|
|
|
319
283
|
resp.usage = resp.usage || {};
|
|
320
284
|
accumulateUsage(resp.usage, chunk.usage);
|
|
321
285
|
}
|
|
286
|
+
if (chunk.citations) {
|
|
287
|
+
resp.citations = [...resp.citations ?? [], ...chunk.citations];
|
|
288
|
+
}
|
|
289
|
+
if (chunk.images) {
|
|
290
|
+
resp.images = [...resp.images ?? [], ...chunk.images];
|
|
291
|
+
}
|
|
292
|
+
if (chunk.audio) {
|
|
293
|
+
resp.audio = accumulateAudio(resp.audio, chunk.audio);
|
|
294
|
+
}
|
|
295
|
+
if (chunk.moderation) {
|
|
296
|
+
resp.moderation = { ...resp.moderation, ...chunk.moderation };
|
|
297
|
+
}
|
|
298
|
+
if (chunk.serviceTier) {
|
|
299
|
+
resp.serviceTier = chunk.serviceTier;
|
|
300
|
+
}
|
|
322
301
|
}
|
|
323
302
|
return resp;
|
|
324
303
|
}
|
|
304
|
+
/**
|
|
305
|
+
* The base64 encoding of two base64 strings' bytes joined. Each streamed part
|
|
306
|
+
* is encoded on its own, so a padded last block of the first is re-encoded
|
|
307
|
+
* with the bytes that follow.
|
|
308
|
+
*/
|
|
309
|
+
function joinBase64(x, y) {
|
|
310
|
+
return x.endsWith('=') ? x.slice(0, -4) + btoa(atob(x.slice(-4)) + atob(y)) : x + y;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Appends a partial audio chunk onto accumulated audio.
|
|
314
|
+
*
|
|
315
|
+
* @param target - The audio accumulated so far.
|
|
316
|
+
* @param add - The partial audio to append.
|
|
317
|
+
* @returns The combined audio.
|
|
318
|
+
*/
|
|
319
|
+
export function accumulateAudio(target, add) {
|
|
320
|
+
const join = (x, y, by) => x === undefined || y === undefined ? x ?? y : by(x, y);
|
|
321
|
+
return {
|
|
322
|
+
id: add.id ?? target?.id,
|
|
323
|
+
format: add.format ?? target?.format,
|
|
324
|
+
data: join(target?.data, add.data, joinBase64),
|
|
325
|
+
transcript: join(target?.transcript, add.transcript, (x, y) => x + y),
|
|
326
|
+
};
|
|
327
|
+
}
|
|
325
328
|
/**
|
|
326
329
|
* Generates a plain text representation of reasoning data.
|
|
327
330
|
*
|
|
@@ -348,66 +351,63 @@ export function getReasoningText(reasoning) {
|
|
|
348
351
|
}
|
|
349
352
|
return parts.join('\n\n');
|
|
350
353
|
}
|
|
351
|
-
|
|
352
|
-
function
|
|
353
|
-
|
|
354
|
-
return y;
|
|
355
|
-
}
|
|
356
|
-
if (!y) {
|
|
357
|
-
return x;
|
|
358
|
-
}
|
|
359
|
-
if (!x.includes(y) && !y.includes(x)) {
|
|
360
|
-
return x + y;
|
|
361
|
-
}
|
|
362
|
-
return x;
|
|
354
|
+
/** Two streamed pieces of text joined, either of which may be missing. */
|
|
355
|
+
function concat(x, y) {
|
|
356
|
+
return x && y ? x + y : x || y || undefined;
|
|
363
357
|
}
|
|
364
358
|
/**
|
|
365
|
-
* Accumulates reasoning
|
|
359
|
+
* Accumulates streamed reasoning: the reasoning so far with the next part
|
|
360
|
+
* appended, as a new object that shares nothing mutable with either input.
|
|
361
|
+
*
|
|
362
|
+
* Providers stream reasoning as deltas, never repeating what was sent, so
|
|
363
|
+
* `content` and each detail's `text`, `summary` and `data` concatenate. A
|
|
364
|
+
* detail continues an earlier one of the same type with the same id (when
|
|
365
|
+
* both have one) or index: OpenRouter sends a block's text and later its
|
|
366
|
+
* signature at one index, and Gemini's text and encrypted reasoning share
|
|
367
|
+
* index 0 under different types. The provider is whichever part names it.
|
|
366
368
|
*
|
|
367
|
-
* @param target - The
|
|
368
|
-
* @param add - The
|
|
369
|
-
* @returns - The
|
|
369
|
+
* @param target - The reasoning accumulated so far.
|
|
370
|
+
* @param add - The reasoning to append.
|
|
371
|
+
* @returns - The accumulated reasoning.
|
|
370
372
|
*/
|
|
371
373
|
export function accumulateReasoning(target, add) {
|
|
372
|
-
if (!target) {
|
|
373
|
-
return add;
|
|
374
|
-
}
|
|
375
374
|
if (!add) {
|
|
376
375
|
return target;
|
|
377
376
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
}
|
|
395
|
-
if (detail.text) {
|
|
396
|
-
existing.text = appendMaybe(existing.text, detail.text);
|
|
397
|
-
if (detail.signature) {
|
|
398
|
-
existing.signature = detail.signature;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
if (detail.summary) {
|
|
402
|
-
existing.summary = appendMaybe(existing.summary, detail.summary);
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
else {
|
|
406
|
-
target.details.push(detail);
|
|
407
|
-
}
|
|
377
|
+
const details = [...target?.details ?? []];
|
|
378
|
+
for (const detail of add.details ?? []) {
|
|
379
|
+
const at = details.findIndex(d => d.type === detail.type && (d.id && detail.id ? d.id === detail.id : d.index === detail.index));
|
|
380
|
+
if (at === -1) {
|
|
381
|
+
details.push(detail);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
const existing = details[at];
|
|
385
|
+
details[at] = {
|
|
386
|
+
...existing,
|
|
387
|
+
id: existing.id || detail.id,
|
|
388
|
+
text: concat(existing.text, detail.text),
|
|
389
|
+
summary: concat(existing.summary, detail.summary),
|
|
390
|
+
data: concat(existing.data, detail.data),
|
|
391
|
+
signature: detail.signature ?? existing.signature,
|
|
392
|
+
};
|
|
408
393
|
}
|
|
409
394
|
}
|
|
410
|
-
return
|
|
395
|
+
return {
|
|
396
|
+
content: concat(target?.content, add.content),
|
|
397
|
+
details: details.length ? details : undefined,
|
|
398
|
+
provider: target?.provider ?? add.provider,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Whether reasoning goes back to a provider: it came from there, or names no
|
|
403
|
+
* provider. Signed and encrypted reasoning only verifies where it was made.
|
|
404
|
+
*
|
|
405
|
+
* @param reasoning - The reasoning of an earlier assistant turn.
|
|
406
|
+
* @param provider - The provider the conversation goes to.
|
|
407
|
+
* @returns - Whether to replay the reasoning.
|
|
408
|
+
*/
|
|
409
|
+
export function replaysTo(reasoning, provider) {
|
|
410
|
+
return !!reasoning && (!reasoning.provider || reasoning.provider === provider);
|
|
411
411
|
}
|
|
412
412
|
/**
|
|
413
413
|
* Converts a Response object into an array of Chunk objects.
|
|
@@ -431,6 +431,11 @@ export function getChunksFromResponse(response) {
|
|
|
431
431
|
finishReason: response.finishReason,
|
|
432
432
|
usage: response.usage,
|
|
433
433
|
model: response.model,
|
|
434
|
+
citations: response.citations,
|
|
435
|
+
images: response.images,
|
|
436
|
+
audio: response.audio,
|
|
437
|
+
moderation: response.moderation,
|
|
438
|
+
serviceTier: response.serviceTier,
|
|
434
439
|
});
|
|
435
440
|
return chunks;
|
|
436
441
|
}
|