@fayegram-ai/decision-bridge 0.1.1 → 0.1.3
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/CHANGELOG.md +24 -0
- package/CONTRIBUTING.md +5 -3
- package/README.md +26 -10
- package/SECURITY.md +18 -11
- package/docs/README.md +19 -5
- package/docs/development/ARCHITECTURE.md +36 -7
- package/docs/development/DESIGN.md +21 -3
- package/docs/development/RELEASING.md +7 -3
- package/docs/development/REPOSITORY_LAYOUT.md +2 -0
- package/docs/development/TESTING.md +31 -3
- package/docs/guides/BROWSER.md +8 -0
- package/docs/guides/CLOUDFLARE_DECISIONS.md +24 -46
- package/docs/guides/CUSTOMIZATION.md +8 -2
- package/docs/guides/CUSTOM_GENERATIVE.md +5 -3
- package/docs/guides/CUSTOM_PROVIDERS.md +5 -3
- package/docs/guides/EXTRACTION.md +125 -0
- package/docs/guides/GETTING_STARTED.md +8 -4
- package/docs/guides/JEV.md +167 -0
- package/docs/guides/LIVE_DECISIONS.md +163 -0
- package/docs/guides/OPENAI_DECISIONS.md +52 -24
- package/docs/guides/PLATFORMS.md +3 -3
- package/docs/guides/SWITCHING_MODELS.md +6 -2
- package/docs/guides/TROUBLESHOOTING.md +25 -0
- package/docs/reference/CLI.md +60 -11
- package/docs/reference/CONFIGURATION.md +34 -6
- package/docs/reference/ERRORS.md +41 -12
- package/docs/reference/PROVIDERS.md +31 -8
- package/docs/reference/SDK.md +72 -26
- package/docs/reference/SOURCES.md +11 -0
- package/examples/extraction.mjs +16 -0
- package/examples/live-decisions.mjs +24 -0
- package/package.json +11 -1
- package/schemas/decision.config.schema.json +102 -11
- package/src/bridge.mjs +9 -6
- package/src/capabilities.mjs +34 -4
- package/src/cli/config-validation.mjs +13 -5
- package/src/cli/config.mjs +19 -4
- package/src/cli/decisions.mjs +8 -0
- package/src/cli/initialize.mjs +8 -4
- package/src/cli/live.mjs +63 -0
- package/src/cli/main.mjs +50 -16
- package/src/cli/provider-loader.mjs +3 -2
- package/src/cloudflare-decisions.d.mts +12 -5
- package/src/decisions.d.mts +28 -4
- package/src/errors.mjs +7 -1
- package/src/extraction/index.d.mts +66 -0
- package/src/extraction/index.mjs +78 -0
- package/src/extraction/validation.mjs +105 -0
- package/src/index.d.mts +42 -9
- package/src/index.mjs +1 -1
- package/src/input.mjs +21 -3
- package/src/jev.d.mts +16 -0
- package/src/live/index.d.mts +73 -0
- package/src/live/index.mjs +170 -0
- package/src/live/state.mjs +125 -0
- package/src/live/validation.mjs +122 -0
- package/src/probabilities.mjs +6 -3
- package/src/providers/cloudflare-images.mjs +5 -67
- package/src/providers/cloudflare-media.mjs +5 -10
- package/src/providers/cloudflare-preflight.mjs +4 -3
- package/src/providers/cloudflare-profile.mjs +10 -14
- package/src/providers/cloudflare-transport.mjs +12 -5
- package/src/providers/cloudflare-validation.mjs +3 -1
- package/src/providers/decisions-codec.mjs +10 -5
- package/src/providers/decisions-input.mjs +120 -0
- package/src/providers/decisions-validation.mjs +37 -69
- package/src/providers/image-header.mjs +59 -0
- package/src/providers/jev-images.mjs +84 -0
- package/src/providers/jev-preflight.mjs +62 -0
- package/src/providers/jev-profile.mjs +37 -0
- package/src/providers/jev.mjs +32 -13
- package/src/providers/media-binary.mjs +0 -7
- package/src/providers/openai-decisions.mjs +2 -1
- package/src/providers/openai-errors.mjs +23 -0
- package/src/providers/openai-profile.mjs +2 -1
- package/src/questions.mjs +2 -0
- package/src/response-transport.mjs +84 -17
- package/src/validation.mjs +39 -20
- package/src/version.mjs +1 -1
package/docs/reference/ERRORS.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# Errors and recovery
|
|
2
2
|
|
|
3
3
|
`DecisionError` extends `Error` and exposes `code`, optional `status`, `requestId`,
|
|
4
|
-
`gatewayLogId`, `attempts`, and numeric `upstreamCode` for Cloudflare diagnostics.
|
|
4
|
+
`gatewayLogId`, `attempts`, and numeric `upstreamCode` for Cloudflare diagnostics. Optional `source`,
|
|
5
|
+
`upstreamErrorCode`, `upstreamErrorType`, `retryAfterMs` and `retryable`
|
|
6
|
+
distinguish client controls and upstream failures.
|
|
5
7
|
OpenAI Decisions refusal errors can also carry validated `refusedQuestions` and
|
|
6
8
|
`usage`. `toJSON()` and `publicError(error)` return safe structured details.
|
|
7
9
|
Unknown exceptions become a generic message, not a copied stack/body. Custom
|
|
@@ -16,13 +18,13 @@ providers deliberately constructing `DecisionError` must keep its message safe.
|
|
|
16
18
|
| `USAGE_ERROR` | Invalid CLI flags/arguments or stdin usage; consult help |
|
|
17
19
|
| `IO_ERROR` | Input/output path or permissions failure; preserve previous output |
|
|
18
20
|
| `INPUT_TOO_LARGE` | CLI byte limit exceeded; reduce or split input |
|
|
19
|
-
| `REQUEST_TOO_LARGE` |
|
|
21
|
+
| `REQUEST_TOO_LARGE` | Configured client byte budget or upstream size admission rejected the request; inspect `source` and optional status |
|
|
20
22
|
| `RESPONSE_TOO_LARGE` | Provider response exceeds configured limit; inspect budget/model behavior |
|
|
21
23
|
| `HTTP_ERROR` | Non-success HTTP response; use status/request ID, not raw error body |
|
|
22
24
|
| `CAPACITY_EXCEEDED` | Cloudflare capacity unavailable (3040); busy mode does not queue/retry |
|
|
23
|
-
| `ALLOCATION_EXCEEDED` |
|
|
24
|
-
| `RATE_LIMITED` |
|
|
25
|
-
| `AUTHENTICATION_ERROR`, `PERMISSION_DENIED` |
|
|
25
|
+
| `ALLOCATION_EXCEEDED` | Provider allocation, credit or spending limit exceeded; not automatically retried |
|
|
26
|
+
| `RATE_LIMITED` | Temporary provider throttling without a more specific allocation/capacity code |
|
|
27
|
+
| `AUTHENTICATION_ERROR`, `PERMISSION_DENIED` | Provider authentication or authorization failure |
|
|
26
28
|
| `UPSTREAM_TIMEOUT`, `UPSTREAM_ABORTED` | Cloudflare upstream timeout (3007) or abort (3008) |
|
|
27
29
|
| `NETWORK_ERROR` | Transport failed ambiguously; no automatic network retry occurred |
|
|
28
30
|
| `RETRY_BUDGET_EXCEEDED` | Server delay cannot fit remaining deadline; choose a later attempt explicitly |
|
|
@@ -35,6 +37,10 @@ providers deliberately constructing `DecisionError` must keep its message safe.
|
|
|
35
37
|
| `PROVIDER_ERROR` | Sanitized custom-provider exception |
|
|
36
38
|
| `UNSUPPORTED_OPERATION` | Provider does not implement listing or another requested operation |
|
|
37
39
|
| `BATCH_SKIPPED` | SDK stop-on-error prevented a not-yet-started record |
|
|
40
|
+
| `INVALID_REQUEST` | Upstream request rejection; inspect safe machine code/type and correct the request |
|
|
41
|
+
| `CONNECTION_CLOSED`, `DISPOSED` | Live connection ended or controller was disposed; pending work is cancelled |
|
|
42
|
+
| `RESOURCE_LIMIT` | Live client pending-operation budget exceeded; settle existing operations before submitting more |
|
|
43
|
+
| `OBSERVER_ERROR` | Live observer notification failed; no command or application action is repeated |
|
|
38
44
|
| `UNEXPECTED_ERROR` | Unrecognized error sanitized for public output |
|
|
39
45
|
|
|
40
46
|
## Retry policy
|
|
@@ -44,18 +50,27 @@ available HTTP diagnostics. A refusal of any question fails that complete call;
|
|
|
44
50
|
successful siblings are not exposed as a partial result.
|
|
45
51
|
|
|
46
52
|
The shared response transport retries statuses **429, 502, 503, 504, and 529**
|
|
47
|
-
|
|
53
|
+
as a fallback for HTTP and binding responses. Provider decoders refine eligibility; known allocation/billing failures are never retried. `maxRetries`
|
|
48
54
|
means additional attempts; the default 2 allows at most 3 total attempts. Native
|
|
49
|
-
OpenAI Decisions
|
|
55
|
+
OpenAI Decisions, Cloudflare Clef and Clairic default to 0; explicitly enabling retries can repeat a billed
|
|
50
56
|
request. All
|
|
51
57
|
attempts, backoff, and response-body reading share one timeout budget.
|
|
52
58
|
|
|
53
|
-
`Retry-After` seconds or HTTP dates are honored.
|
|
59
|
+
Valid `Retry-After` decimal integer seconds or HTTP dates are honored. All three
|
|
60
|
+
HTTP date forms are interpreted in UTC; an elapsed date means zero delay.
|
|
61
|
+
Malformed values are ignored, including fractional, signed, hexadecimal and
|
|
62
|
+
exponent numbers. Without a valid hint, exponential backoff
|
|
54
63
|
starts at 250 ms with jitter and an 8-second base cap. A delay that cannot fit the
|
|
55
64
|
remaining budget fails instead of violating the server's requested wait.
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
66
|
+
When an HTTP rejection body is malformed, too large, or interrupted, the known
|
|
67
|
+
status, safe request/Gateway IDs and valid `Retry-After` remain available. If the
|
|
68
|
+
body cannot be decoded, classification and retry eligibility use the status
|
|
69
|
+
alone; no missing upstream code is invented. Caller cancellation and the total
|
|
70
|
+
deadline still take precedence over this fallback.
|
|
71
|
+
|
|
72
|
+
Authentication failures, invalid output, model refusal, and
|
|
73
|
+
ambiguous network failures are not retried automatically. OpenAI may classify HTTP 500 as retryable; other transports retain their fallback policy. HTTP retries are not an
|
|
59
74
|
exactly-once billing guarantee. Set `maxRetries: 0` when your workflow requires
|
|
60
75
|
manual retry decisions. The bridge never retries a successful request because an
|
|
61
76
|
observer failed; inspect `meta.observerFailures` separately.
|
|
@@ -64,8 +79,9 @@ observer failed; inspect `meta.observerFailures` separately.
|
|
|
64
79
|
|
|
65
80
|
401/403 usually requires checking key/account/model authorization with the provider;
|
|
66
81
|
the client reports the actual status rather than claiming to diagnose account
|
|
67
|
-
state. 404 can indicate an incorrect API base/model/route. 429
|
|
68
|
-
|
|
82
|
+
state. 404 can indicate an incorrect API base/model/route. A 429 can represent
|
|
83
|
+
temporary throttling or an allocation/billing failure; inspect `code`,
|
|
84
|
+
`upstreamErrorCode`, `upstreamErrorType` and `retryable`. For `INVALID_RESPONSE`, a schema-capable model
|
|
69
85
|
may still emit invalid probabilities or be routed through an incompatible endpoint.
|
|
70
86
|
Change configuration deliberately and retest; do not disable local validation.
|
|
71
87
|
|
|
@@ -83,3 +99,16 @@ For successful OpenAI calls, retain
|
|
|
83
99
|
the requested selection, resolved outgoing ID, and reported model separately;
|
|
84
100
|
see [model identities](../guides/OPENAI_DECISIONS.md#model-selection). Log input or results only under your
|
|
85
101
|
own data-handling policy. No logging or telemetry is enabled by default.
|
|
102
|
+
|
|
103
|
+
## Extraction and Live
|
|
104
|
+
|
|
105
|
+
Clairic preserves native nulls, empty lists and the `truncated` flag in a successful
|
|
106
|
+
extraction envelope; truncation is not converted into a decision-style failure.
|
|
107
|
+
The application decides whether that extraction is sufficient for its task.
|
|
108
|
+
|
|
109
|
+
Live preserves native refusal answers on completed decision events. Malformed
|
|
110
|
+
server events report `INVALID_RESPONSE`; the offline event-file validator reports
|
|
111
|
+
caller input as `VALIDATION_ERROR`. Observer failures produce `observer_error`
|
|
112
|
+
notifications containing a safe `OBSERVER_ERROR`. Command submission receipts do
|
|
113
|
+
not promise a completed decision. No Live command or application action is
|
|
114
|
+
automatically replayed. See [Live lifecycle](../guides/LIVE_DECISIONS.md).
|
|
@@ -44,25 +44,35 @@ contract. The following additional forms are checked before dispatch:
|
|
|
44
44
|
|
|
45
45
|
| Provider | Ordered text / embedded images | Typed string/boolean choices | Labelled score levels | Safety identifier | Model listing |
|
|
46
46
|
| --- | --- | --- | --- | --- | --- |
|
|
47
|
-
| Jev |
|
|
48
|
-
| OpenAI Decisions | Supported;
|
|
49
|
-
| Cloudflare Clef / Clef-flash | Supported;
|
|
50
|
-
| Cloudflare Clef-omni | Supported;
|
|
47
|
+
| Jev | Ordered text; images with explicit opt-in | Unsupported | Unsupported | Unsupported | Supported |
|
|
48
|
+
| OpenAI Decisions | Supported; preserving order | Supported | Supported | Supported | Unsupported |
|
|
49
|
+
| Cloudflare Clef / Clef-flash | Supported; images before text | Supported | Supported; ordered levels | Unsupported | Unsupported |
|
|
50
|
+
| Cloudflare Clef-omni | Supported; images before audio/video/text | Supported | Supported; ordered levels | Unsupported | Unsupported |
|
|
51
51
|
| OpenAI-compatible / OpenRouter / Anthropic | Unsupported | Unsupported | Unsupported | Unsupported | Supported; service-specific catalog |
|
|
52
52
|
|
|
53
53
|
`bridge.getCapabilities(model)` reports the local profile, and
|
|
54
54
|
`bridge.validate(request)` checks that profile and provider preflight without
|
|
55
55
|
inference. These methods do not authenticate an account or query availability.
|
|
56
|
-
Legacy choice maps and score rubrics have
|
|
56
|
+
Legacy choice maps and score rubrics have structural requirements, described in the
|
|
57
57
|
[SDK reference](SDK.md#question-builders). Custom providers declare additional
|
|
58
58
|
capabilities explicitly.
|
|
59
59
|
|
|
60
|
-
Omni additionally accepts
|
|
61
|
-
capability fields `audio`, `videos`, `maxAudioClips`, and
|
|
60
|
+
Omni additionally accepts embedded audio clips and videos; service counts remain
|
|
61
|
+
upstream. The optional capability fields `audio`, `videos`, `maxAudioClips`, and
|
|
62
|
+
`maxVideos` normalize to
|
|
62
63
|
false/zero when omitted, preserving legacy custom profiles. Cloudflare's older
|
|
63
64
|
models and all other shipped providers reject audio/video before inference.
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
Jev additionally supports `box` questions on `jev-preview` and pinned 1.14+ models
|
|
67
|
+
when `dangerZone.images` is enabled. Other built-ins reject box questions.
|
|
68
|
+
See the [Jev guide](../guides/JEV.md) for asset placement and experimental opt-ins.
|
|
69
|
+
|
|
70
|
+
OpenAI additionally supports `conversation`, `toolHistory`, `remoteImages` and
|
|
71
|
+
`promptCaching`. These optional capability flags default to false for existing
|
|
72
|
+
custom providers. Built-in quantitative limits use `null` where admission is
|
|
73
|
+
left to the service; explicit custom-provider limits remain enforced.
|
|
74
|
+
|
|
75
|
+
Dedicated `createDecision()` access is available on Jev, OpenAI Decisions and
|
|
66
76
|
Cloudflare providers. It uses each service's native request/response shape and
|
|
67
77
|
bypasses bridge preparation and observation hooks.
|
|
68
78
|
|
|
@@ -74,6 +84,12 @@ intermediate language model, skill, portal prompt, or chat conversion is used.
|
|
|
74
84
|
`GET /v1/models` lists native models. A listed catalog can differ from valid aliases;
|
|
75
85
|
`jev-latest` is the documented stable alias.
|
|
76
86
|
|
|
87
|
+
`jev-preview` selects the preview release. Images and longer context require
|
|
88
|
+
explicit `dangerZone` settings. Common image input preserves ordering; native
|
|
89
|
+
`createDecision()` additionally accepts JSON assets referenced in state,
|
|
90
|
+
instructions, and criteria. Box outputs preserve normalized edges and confidence.
|
|
91
|
+
See the [Jev guide](../guides/JEV.md) for limits and absence handling.
|
|
92
|
+
|
|
77
93
|
Pin a version after evaluating it for your workload rather than assuming a moving
|
|
78
94
|
alias yields reproducible quality. Store the returned `model` along with the
|
|
79
95
|
requested model and your question-template revision.
|
|
@@ -114,3 +130,10 @@ do not override them. This release has no silent provider failover, model search
|
|
|
114
130
|
credential refresh, provider-side batch API, or universal quality guarantee.
|
|
115
131
|
Unsupported protocols require an explicit custom decision or generative provider; unsupported server
|
|
116
132
|
features require an explicitly supported mode or a different model.
|
|
133
|
+
|
|
134
|
+
## Dedicated operations
|
|
135
|
+
|
|
136
|
+
Clairic is a native extraction model exposed through [extraction](../guides/EXTRACTION.md).
|
|
137
|
+
Its provider is not a DecisionProvider and is not accepted by createBridge.
|
|
138
|
+
[Live Decisions](../guides/LIVE_DECISIONS.md) owns a connection-oriented command
|
|
139
|
+
and event lifecycle through a dedicated export.
|
package/docs/reference/SDK.md
CHANGED
|
@@ -7,6 +7,9 @@ TypeScript setup, and CommonJS dynamic import. The source-tree entry point is
|
|
|
7
7
|
TypeScript declarations are in `src/index.d.mts`; runtime JavaScript is authoritative
|
|
8
8
|
and checked independently of those declarations.
|
|
9
9
|
|
|
10
|
+
This reference covers **0.1.3**. See
|
|
11
|
+
[version availability](../README.md#version-availability) for earlier versions.
|
|
12
|
+
|
|
10
13
|
## Create a bridge
|
|
11
14
|
|
|
12
15
|
```javascript
|
|
@@ -48,7 +51,7 @@ guides. These are SDK options, not per-evaluation bridge options.
|
|
|
48
51
|
| --- | --- |
|
|
49
52
|
| `timeoutMs` | 30,000 ms; positive integer through 2,147,483,647; one transport budget for dispatch, retries, backoff, and response reading |
|
|
50
53
|
| `maxRetries` | Additional eligible attempts, 0–10; Jev and generative presets default to 2, native OpenAI and Cloudflare to 0 |
|
|
51
|
-
| `maxRequestBytes` | Complete serialized request ceiling; normally 8 MiB, configurable from 1 byte through 64 MiB; Cloudflare applies its [model-specific budgets](../guides/CLOUDFLARE_DECISIONS.md#embedded-images-and-limits) |
|
|
54
|
+
| `maxRequestBytes` | Complete serialized request ceiling; normally 8 MiB, configurable from 1 byte through 64 MiB; Jev defaults to 32 MiB, with explicit client budgets through 64 MiB; Cloudflare applies its [model-specific budgets](../guides/CLOUDFLARE_DECISIONS.md#embedded-images-and-limits) |
|
|
52
55
|
| `maxResponseBytes` | 8 MiB; configurable from 1 byte through 64 MiB; applies while reading the response body |
|
|
53
56
|
| `fetchImpl` | Optional `(url: string, init?: RequestInit) => Promise<Response>`; defaults to the runtime's `fetch` |
|
|
54
57
|
|
|
@@ -68,8 +71,9 @@ they interact; [errors](ERRORS.md#retry-policy) lists retryable statuses.
|
|
|
68
71
|
|
|
69
72
|
### `bridge.evaluate(request, options?)`
|
|
70
73
|
|
|
71
|
-
`request` has exactly one of `state
|
|
72
|
-
`
|
|
74
|
+
`request` has exactly one of `state`, ordered `input` or `conversation`, plus
|
|
75
|
+
`questions`. Optional fields are `model`, `safetyIdentifier`, `promptCacheKey`
|
|
76
|
+
and `promptCacheOptions`. New forms require declared provider capabilities;
|
|
73
77
|
see [OpenAI Decisions](../guides/OPENAI_DECISIONS.md) and
|
|
74
78
|
[Cloudflare Clef](../guides/CLOUDFLARE_DECISIONS.md). The request model
|
|
75
79
|
wins over the provider's configured default, which an omitted request model inherits.
|
|
@@ -81,14 +85,20 @@ resolve to upstream IDs within the provider. No default is assumed for a generat
|
|
|
81
85
|
independent transport timeout, including Workers AI binding calls.
|
|
82
86
|
|
|
83
87
|
Ordered parts are `{ type: 'text', text }`, `{ type: 'image', dataUrl, detail? }`,
|
|
84
|
-
`{ type: '
|
|
85
|
-
|
|
88
|
+
`{ type: 'image', url, detail? }`, `{ type: 'audio', dataUrl }`, or
|
|
89
|
+
`{ type: 'video', dataUrl }`. Image `url` and `dataUrl` are exclusive. Text/image
|
|
90
|
+
parts may carry `promptCacheBreakpoint`. Remote HTTP(S) images and cache controls
|
|
91
|
+
require their respective capabilities and are forwarded without URL fetching or
|
|
92
|
+
cache-policy selection. `conversation` uses the native Decisions input-item union;
|
|
93
|
+
see [conversation and prompt caching](../guides/OPENAI_DECISIONS.md#conversation-and-prompt-caching).
|
|
94
|
+
Audio/video are supported by Cloudflare Clef-omni and explicitly capable custom providers; other
|
|
86
95
|
built-ins reject them before dispatch. Cloudflare requires images → audio →
|
|
87
|
-
videos → text.
|
|
88
|
-
in the [Cloudflare guide](../guides/CLOUDFLARE_DECISIONS.md#omni-audio-and-video).
|
|
96
|
+
videos → text. Its media use embedded data URLs, with format and client-budget
|
|
97
|
+
checks described in the [Cloudflare guide](../guides/CLOUDFLARE_DECISIONS.md#omni-audio-and-video).
|
|
89
98
|
|
|
90
|
-
The bridge snapshots and freezes its input, runs
|
|
91
|
-
invokes the provider once, validates the result, then
|
|
99
|
+
The bridge snapshots and freezes its input, runs preparation hooks for the
|
|
100
|
+
selected input form, invokes the provider once, validates the result, then
|
|
101
|
+
observes an immutable result.
|
|
92
102
|
Built-in transports can retry eligible response statuses within that invocation
|
|
93
103
|
when client retries are configured.
|
|
94
104
|
|
|
@@ -146,19 +156,22 @@ const q3 = score('How far did processing progress?', [
|
|
|
146
156
|
]);
|
|
147
157
|
```
|
|
148
158
|
|
|
159
|
+
`box(instructions)` returns a box question with no criteria; supported providers
|
|
160
|
+
must declare `boxes: true`. Jev supports it with experimental image opt-in and
|
|
161
|
+
a supported model; see [Jev images and boxes](../guides/JEV.md).
|
|
162
|
+
|
|
149
163
|
Builders return immutable question objects. `choice(instructions, criteria)` accepts
|
|
150
|
-
a label map
|
|
164
|
+
a nonempty label map. `noul(instructions, criteria?)` accepts an
|
|
151
165
|
optional criteria object,
|
|
152
|
-
with only `true` and `false` keys. `score(instructions, criteria)` accepts
|
|
166
|
+
with only `true` and `false` keys. `score(instructions, criteria)` accepts at least two
|
|
153
167
|
ordered levels; numeric level indices are zero-based. There is no boolean alias:
|
|
154
168
|
`noul` means a probability, not a thresholded truth value.
|
|
155
169
|
|
|
156
170
|
`choice(instructions, options)` accepts ordered objects with unique string or
|
|
157
171
|
boolean `value` fields and optional text or structured JSON descriptions. Boolean `true` and string
|
|
158
172
|
`"true"` remain distinct. `scoreLevels(instructions, levels)` accepts at least two
|
|
159
|
-
ordered label/description objects. Provider preflight
|
|
160
|
-
OpenAI Decisions and Cloudflare require
|
|
161
|
-
to 2–10 levels, while OpenAI labelled scores have no additional client count cap.
|
|
173
|
+
ordered label/description objects. Provider preflight enforces structural requirements:
|
|
174
|
+
OpenAI Decisions and Cloudflare require at least two choices; maximum service counts remain upstream.
|
|
162
175
|
|
|
163
176
|
## Returned data
|
|
164
177
|
|
|
@@ -201,7 +214,8 @@ rubric exactly. Generative providers calculate score and legend locally. Native
|
|
|
201
214
|
values are validated and preserved, not normalized or replaced.
|
|
202
215
|
|
|
203
216
|
**Usage:** `input_tokens` and `output_tokens` are nonnegative integers or null.
|
|
204
|
-
Jev
|
|
217
|
+
Jev accepts explicitly null counts as unknown; OpenAI Decisions and Cloudflare
|
|
218
|
+
require reported integer counts. OpenAI and
|
|
205
219
|
Anthropic cache creation/read counts are preserved separately when provided;
|
|
206
220
|
Cloudflare does not fabricate cache or total-token fields. No total price, inferred cache saving, or
|
|
207
221
|
estimated token count is fabricated.
|
|
@@ -228,20 +242,26 @@ estimated token count is fabricated.
|
|
|
228
242
|
|
|
229
243
|
Metadata can have additional JSON fields. Application logic should not assume
|
|
230
244
|
unavailable metadata exists. Result objects and nested data returned by the bridge
|
|
231
|
-
are immutable. Standalone
|
|
245
|
+
are immutable. Standalone common `validateRequest` and `validateResult` return
|
|
246
|
+
snapshots without freezing them; dedicated extraction and Live validators return
|
|
247
|
+
frozen snapshots.
|
|
232
248
|
|
|
233
|
-
`schemaVersion`
|
|
234
|
-
|
|
235
|
-
|
|
249
|
+
`schemaVersion` is selected by the highest applicable feature: 5 for conversation,
|
|
250
|
+
remote-image URLs or prompt-cache controls; 4 for boxes; 3 for audio/video; 2 for
|
|
251
|
+
ordered images/text, typed choices, labelled scores or a safety identifier; and
|
|
252
|
+
1 for legacy requests. The CLI configuration schema remains 1. Extraction and
|
|
253
|
+
Live use their dedicated native envelopes rather than a common result version.
|
|
236
254
|
|
|
237
255
|
## Extensions
|
|
238
256
|
|
|
239
257
|
An extension has a unique printable `name` (maximum 100 characters), optional
|
|
240
|
-
`prepareState(state, context)`, `prepareInput(input, context)`,
|
|
258
|
+
`prepareState(state, context)`, `prepareInput(input, context)`,
|
|
259
|
+
`prepareConversation(items, context)`, and
|
|
241
260
|
`onResult(result, context)`. Preparation extensions must support the request's
|
|
242
261
|
input form; incompatible hooks fail explicitly before dispatch.
|
|
243
262
|
|
|
244
|
-
Preparation returns replacement state
|
|
263
|
+
Preparation returns replacement state, ordered input or conversation, or
|
|
264
|
+
`undefined` to leave it unchanged.
|
|
245
265
|
Preparation exceptions fail before inference with `EXTENSION_ERROR`; transformed
|
|
246
266
|
content is revalidated, including capabilities and provider preflight. Preparation
|
|
247
267
|
cannot rewrite question definitions or switch the model.
|
|
@@ -304,6 +324,8 @@ automatic model fallback. The CLI has a separate streaming JSONL implementation.
|
|
|
304
324
|
- `createProvider(config)`: factory requiring an explicit `type` equal to `jev`,
|
|
305
325
|
`openai-decisions`, or `cloudflare-decisions`.
|
|
306
326
|
- `JevProvider`, `OpenAIDecisionsProvider`, `CloudflareDecisionsProvider`: native provider classes.
|
|
327
|
+
- `box(instructions)` and `JevProvider.createDecision(request, options?)`:
|
|
328
|
+
bounding boxes and native JSON assets; see the [Jev guide](../guides/JEV.md).
|
|
307
329
|
- `scoreLevels(instructions, levels)` and the array overload of `choice`:
|
|
308
330
|
labelled rubrics and typed string/boolean options, with provider capability checks.
|
|
309
331
|
- `OpenAIDecisionsProvider.createDecision(request, options?)`: dedicated native
|
|
@@ -314,9 +336,9 @@ automatic model fallback. The CLI has a separate streaming JSONL implementation.
|
|
|
314
336
|
an own `input.model` property or an explicitly supplied default; inherited
|
|
315
337
|
models are ignored, and it never selects a Jev model.
|
|
316
338
|
Question builders and schema generation validate without selecting an inference model.
|
|
317
|
-
- `validateResult(input, questions, { native = false, probabilityDecimalPlaces })`: snapshot supplied
|
|
339
|
+
- `validateResult(input, questions, { native = false, nullableUsage = false, probabilityDecimalPlaces })`: snapshot supplied
|
|
318
340
|
questions and validate the canonical result; native mode requires confidence
|
|
319
|
-
and reported counts.
|
|
341
|
+
and reported counts unless the provider explicitly enables nullable usage.
|
|
320
342
|
- `decideChoice(answer, { minProbability, minMargin = 0, abstainOptions = [], probabilityDecimalPlaces })`:
|
|
321
343
|
returns a policy result, never executes an action. `minProbability` is required.
|
|
322
344
|
- `DecisionError`, `publicError(error)`: public structured failure handling.
|
|
@@ -354,14 +376,14 @@ decision providers may preserve custom string labels. Generative prompt and
|
|
|
354
376
|
normalization helpers independently validate the shared-state, legacy-question
|
|
355
377
|
profile and explicitly reject unsupported request capabilities.
|
|
356
378
|
Decision-kind classification alone does not require confidence or known counts;
|
|
357
|
-
`validateResult({ native: true })` is a separate strict validation option used for
|
|
379
|
+
`validateResult(result, questions, { native: true })` is a separate strict validation option used for
|
|
358
380
|
Jev's contract. See [custom decision](../guides/CUSTOM_DECISION.md),
|
|
359
381
|
[custom generative](../guides/CUSTOM_GENERATIVE.md), and the shared
|
|
360
382
|
[custom contract](../guides/CUSTOM_PROVIDERS.md).
|
|
361
383
|
|
|
362
384
|
## Validation guarantees
|
|
363
385
|
|
|
364
|
-
Legacy choice criteria maps
|
|
386
|
+
Legacy choice criteria maps must be nonempty. Noul
|
|
365
387
|
criteria must be omitted or an object; its present true/false descriptions cannot
|
|
366
388
|
be raw null. Score levels likewise cannot be raw null (nested null JSON values are
|
|
367
389
|
still allowed). These invalid forms now fail before provider dispatch.
|
|
@@ -371,7 +393,10 @@ the answer. `evaluateBatch()` validates array holes as invalid requests before a
|
|
|
371
393
|
item is dispatched, rather than spending on adjacent valid entries.
|
|
372
394
|
|
|
373
395
|
The optional third argument to `validateResult()` must be a plain options object
|
|
374
|
-
with optional boolean `native` and integer
|
|
396
|
+
with optional boolean `native`, boolean `nullableUsage`, and integer
|
|
397
|
+
`probabilityDecimalPlaces` (1–15) fields. Both booleans default to false.
|
|
398
|
+
`nullableUsage: true` permits null token counts when native validation is enabled;
|
|
399
|
+
it does not relax the native confidence requirement.
|
|
375
400
|
Providers can declare a pure synchronous `getResultValidationOptions(model)` hook;
|
|
376
401
|
its policy is validated before inference and is not read from response metadata.
|
|
377
402
|
Returning a Promise is a configuration error; its rejection is observed without
|
|
@@ -392,3 +417,24 @@ Native provider cancellation/timeout errors preserve the last observed sanitized
|
|
|
392
417
|
request ID and attempt count when available. The bridge may settle its own
|
|
393
418
|
cancellation race before the provider returns diagnostics; do not require those
|
|
394
419
|
optional fields on every `ABORTED` or `TIMEOUT` error.
|
|
420
|
+
|
|
421
|
+
## Dedicated operations
|
|
422
|
+
|
|
423
|
+
Import these subpaths under `@fayegram-ai/decision-bridge/`. Neither is selected
|
|
424
|
+
by the root `createProvider` factory or implements the bridge's `evaluate` contract.
|
|
425
|
+
|
|
426
|
+
| Export | Runtime API | Result / integration |
|
|
427
|
+
| --- | --- | --- |
|
|
428
|
+
| `extraction` | `CloudflareExtractionProvider`, `validateExtractionRequest`, `extractBatch` | Immutable `{ extraction, meta }`, with native values and model/transport diagnostics; [extraction guide](../guides/EXTRACTION.md) |
|
|
429
|
+
| `live` | `createLiveDecisions`, `validateLiveConfiguration`, `validateLiveCommand`, `validateLiveEvent` | Commands, acknowledgements and event subscriptions over a caller-owned connection; [Live guide](../guides/LIVE_DECISIONS.md) |
|
|
430
|
+
|
|
431
|
+
Both export their request, result, configuration and transport types. Extraction
|
|
432
|
+
supports REST or a Workers AI binding; Live owns no authentication, audio,
|
|
433
|
+
connection establishment or reconnection. See the [CLI reference](CLI.md) for
|
|
434
|
+
their command namespaces.
|
|
435
|
+
|
|
436
|
+
Service quotas, maximum request counts, context/media limits and Gateway
|
|
437
|
+
admission remain authoritative upstream. Offline validation checks adapter
|
|
438
|
+
structure and client resource budgets. SDK and CLI do not estimate tokens or
|
|
439
|
+
enforce RPM/TPM. Explicit transport budgets can select up to 64 MiB, including
|
|
440
|
+
Jev and all Clef models; existing default budgets are retained.
|
|
@@ -11,6 +11,10 @@ reference does not imply that authenticated inference was run against its servic
|
|
|
11
11
|
| TypeSafe request/response API | https://docs.typesafe.ai/api |
|
|
12
12
|
| TypeSafe JavaScript examples | https://docs.typesafe.ai/sdk/javascript |
|
|
13
13
|
| Native model listing and aliases | https://docs.typesafe.ai/models |
|
|
14
|
+
| Jev image assets and experimental opt-in | https://docs.typesafe.ai/images |
|
|
15
|
+
| Jev bounding boxes | https://docs.typesafe.ai/primitives/box |
|
|
16
|
+
| Jev 1.14 release | https://typesafe.ai/blog/jev-1-14 |
|
|
17
|
+
| Jev nullable usage compatibility | https://docs.typesafe.ai/sdk/javascript/changelog |
|
|
14
18
|
| Choice decisions | https://docs.typesafe.ai/primitives/choice |
|
|
15
19
|
| Noul probabilities | https://docs.typesafe.ai/primitives/noul |
|
|
16
20
|
| Score rubric and weighted expectation | https://docs.typesafe.ai/primitives/score |
|
|
@@ -18,6 +22,8 @@ reference does not imply that authenticated inference was run against its servic
|
|
|
18
22
|
| OpenAI structured output modes | https://platform.openai.com/docs/guides/structured-outputs |
|
|
19
23
|
| OpenAI native Decisions guide | https://developers.openai.com/api/docs/guides/decisions |
|
|
20
24
|
| OpenAI Decisions request/response contract | https://developers.openai.com/api/reference/resources/decisions/methods/create |
|
|
25
|
+
| OpenAI Live Decisions guide | https://developers.openai.com/api/docs/guides/decisions-voice |
|
|
26
|
+
| OpenAI Live protocol | https://developers.openai.com/api/reference/resources/live/primary-websocket |
|
|
21
27
|
| OpenRouter structured output and routing | https://openrouter.ai/docs/guides/features/structured-outputs |
|
|
22
28
|
| Anthropic Messages, tools, usage, and stop reasons | https://platform.claude.com/docs/en/api/messages/create |
|
|
23
29
|
| GitHub checkout action | https://github.com/actions/checkout |
|
|
@@ -44,6 +50,11 @@ separate operational check.
|
|
|
44
50
|
- [Cloudflare-owned model implementation](https://huggingface.co/Cloudflare/clef-flash/blob/main/joint_schema_model.py), including output precision
|
|
45
51
|
- [Cloudflare-owned Omni implementation](https://huggingface.co/Cloudflare/clef-omni/blob/main/joint_schema_model.py), including grouped media and output precision
|
|
46
52
|
|
|
53
|
+
## Cloudflare extraction
|
|
54
|
+
|
|
55
|
+
- [Extraction concepts](https://developers.cloudflare.com/workers-ai/concepts/extraction-models/)
|
|
56
|
+
- [Clairic schema snapshot](https://github.com/cloudflare/cloudflare-docs/blob/a5cc2cba1a31b8bd95eda69dad151e6cd307ac7b/src/content/workers-ai-models/clairic.json), the pinned basis for established native fields; underspecified predictive JSON remains preserved
|
|
57
|
+
|
|
47
58
|
## Package and repository release
|
|
48
59
|
|
|
49
60
|
- [Scoped public npm packages](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Explicit execution calls Cloudflare; configure account/token in your environment.
|
|
2
|
+
import { CloudflareExtractionProvider } from '../src/extraction/index.mjs';
|
|
3
|
+
import { publicError } from '../src/index.mjs';
|
|
4
|
+
|
|
5
|
+
try {
|
|
6
|
+
const provider = new CloudflareExtractionProvider();
|
|
7
|
+
const result = await provider.extract({
|
|
8
|
+
state: 'Invoice total: 1080 USD. Due date: 2026-11-01.',
|
|
9
|
+
reference_date: '2026-10-20',
|
|
10
|
+
fields: { amount: { type: 'number', unit: 'USD' }, due_date: { type: 'date' } },
|
|
11
|
+
});
|
|
12
|
+
console.log(JSON.stringify(result, null, 2));
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.error(publicError(error));
|
|
15
|
+
process.exitCode = 1;
|
|
16
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Call with your already authenticated, open WebSocket-like Live connection.
|
|
2
|
+
import { createLiveDecisions } from '../src/live/index.mjs';
|
|
3
|
+
|
|
4
|
+
export function attachLiveDecisions(connection) {
|
|
5
|
+
return createLiveDecisions({ transport: {
|
|
6
|
+
send(command) { connection.send(JSON.stringify(command)); },
|
|
7
|
+
subscribe(listener) {
|
|
8
|
+
const message = event => {
|
|
9
|
+
try { listener({ kind: 'event', event: JSON.parse(event.data) }); }
|
|
10
|
+
catch { listener({ kind: 'error' }); }
|
|
11
|
+
};
|
|
12
|
+
const close = () => listener({ kind: 'close' });
|
|
13
|
+
const error = () => listener({ kind: 'error' });
|
|
14
|
+
connection.addEventListener('message', message);
|
|
15
|
+
connection.addEventListener('close', close);
|
|
16
|
+
connection.addEventListener('error', error);
|
|
17
|
+
return () => {
|
|
18
|
+
connection.removeEventListener('message', message);
|
|
19
|
+
connection.removeEventListener('close', close);
|
|
20
|
+
connection.removeEventListener('error', error);
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
} });
|
|
24
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fayegram-ai/decision-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "JavaScript SDK and CLI for structured decisions across native decision APIs and configurable model providers",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -44,6 +44,16 @@
|
|
|
44
44
|
"browser": "./src/custom/generative/index.mjs",
|
|
45
45
|
"import": "./src/custom/generative/index.mjs"
|
|
46
46
|
},
|
|
47
|
+
"./extraction": {
|
|
48
|
+
"types": "./src/extraction/index.d.mts",
|
|
49
|
+
"browser": "./src/extraction/index.mjs",
|
|
50
|
+
"import": "./src/extraction/index.mjs"
|
|
51
|
+
},
|
|
52
|
+
"./live": {
|
|
53
|
+
"types": "./src/live/index.d.mts",
|
|
54
|
+
"browser": "./src/live/index.mjs",
|
|
55
|
+
"import": "./src/live/index.mjs"
|
|
56
|
+
},
|
|
47
57
|
"./config.schema.json": "./schemas/decision.config.schema.json"
|
|
48
58
|
},
|
|
49
59
|
"bin": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"title": "Decision Bridge configuration",
|
|
4
|
-
"description": "Explicit schemaVersion 1 configuration. Runtime
|
|
4
|
+
"description": "Explicit schemaVersion 1 configuration. Runtime validation checks adapter structure and client resource budgets; service limits remain authoritative upstream.",
|
|
5
5
|
"oneOf": [
|
|
6
6
|
{
|
|
7
7
|
"type": "object",
|
|
@@ -29,13 +29,27 @@
|
|
|
29
29
|
"$ref": "#/$defs/retries"
|
|
30
30
|
},
|
|
31
31
|
"maxRequestBytes": {
|
|
32
|
-
"
|
|
32
|
+
"type": "integer",
|
|
33
|
+
"minimum": 1,
|
|
34
|
+
"maximum": 67108864
|
|
33
35
|
},
|
|
34
36
|
"maxResponseBytes": {
|
|
35
37
|
"$ref": "#/$defs/bytes"
|
|
36
38
|
},
|
|
37
39
|
"provider": {
|
|
38
40
|
"const": "jev"
|
|
41
|
+
},
|
|
42
|
+
"dangerZone": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"properties": {
|
|
46
|
+
"images": {
|
|
47
|
+
"type": "boolean"
|
|
48
|
+
},
|
|
49
|
+
"longContext": {
|
|
50
|
+
"type": "boolean"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
39
53
|
}
|
|
40
54
|
}
|
|
41
55
|
},
|
|
@@ -393,6 +407,89 @@
|
|
|
393
407
|
"provider",
|
|
394
408
|
"module"
|
|
395
409
|
]
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
"type": "object",
|
|
413
|
+
"additionalProperties": false,
|
|
414
|
+
"properties": {
|
|
415
|
+
"$schema": {
|
|
416
|
+
"$ref": "#/$defs/text"
|
|
417
|
+
},
|
|
418
|
+
"schemaVersion": {
|
|
419
|
+
"const": 1
|
|
420
|
+
},
|
|
421
|
+
"model": {
|
|
422
|
+
"enum": [
|
|
423
|
+
"clairic",
|
|
424
|
+
"@cf/cloudflare/clairic"
|
|
425
|
+
]
|
|
426
|
+
},
|
|
427
|
+
"apiKeyEnv": {
|
|
428
|
+
"$ref": "#/$defs/keyEnv"
|
|
429
|
+
},
|
|
430
|
+
"timeoutMs": {
|
|
431
|
+
"$ref": "#/$defs/timeout"
|
|
432
|
+
},
|
|
433
|
+
"baseURL": {
|
|
434
|
+
"$ref": "#/$defs/text"
|
|
435
|
+
},
|
|
436
|
+
"maxRetries": {
|
|
437
|
+
"$ref": "#/$defs/retries"
|
|
438
|
+
},
|
|
439
|
+
"maxRequestBytes": {
|
|
440
|
+
"$ref": "#/$defs/bytes"
|
|
441
|
+
},
|
|
442
|
+
"maxResponseBytes": {
|
|
443
|
+
"$ref": "#/$defs/bytes"
|
|
444
|
+
},
|
|
445
|
+
"provider": {
|
|
446
|
+
"const": "cloudflare-extraction"
|
|
447
|
+
},
|
|
448
|
+
"accountId": {
|
|
449
|
+
"$ref": "#/$defs/text"
|
|
450
|
+
},
|
|
451
|
+
"rejectIfBusy": {
|
|
452
|
+
"$ref": "#/$defs/boolean"
|
|
453
|
+
},
|
|
454
|
+
"gateway": {
|
|
455
|
+
"$ref": "#/$defs/gateway"
|
|
456
|
+
}
|
|
457
|
+
},
|
|
458
|
+
"required": [
|
|
459
|
+
"provider"
|
|
460
|
+
],
|
|
461
|
+
"allOf": [
|
|
462
|
+
{
|
|
463
|
+
"if": {
|
|
464
|
+
"properties": {
|
|
465
|
+
"rejectIfBusy": {
|
|
466
|
+
"const": true
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
"required": [
|
|
470
|
+
"rejectIfBusy"
|
|
471
|
+
]
|
|
472
|
+
},
|
|
473
|
+
"then": {
|
|
474
|
+
"properties": {
|
|
475
|
+
"maxRetries": {
|
|
476
|
+
"const": 0
|
|
477
|
+
},
|
|
478
|
+
"gateway": {
|
|
479
|
+
"properties": {
|
|
480
|
+
"retries": {
|
|
481
|
+
"properties": {
|
|
482
|
+
"maxAttempts": {
|
|
483
|
+
"const": 1
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
]
|
|
396
493
|
}
|
|
397
494
|
],
|
|
398
495
|
"$defs": {
|
|
@@ -482,19 +579,16 @@
|
|
|
482
579
|
"id": {
|
|
483
580
|
"type": "string",
|
|
484
581
|
"minLength": 1,
|
|
485
|
-
"maxLength": 64,
|
|
486
582
|
"pattern": "^[\\x20-\\x7e]*\\S[\\x20-\\x7e]*$"
|
|
487
583
|
},
|
|
488
584
|
"cacheKey": {
|
|
489
585
|
"type": "string",
|
|
490
586
|
"minLength": 1,
|
|
491
|
-
"maxLength": 200,
|
|
492
587
|
"pattern": "^[\\x20-\\x7e]*\\S[\\x20-\\x7e]*$"
|
|
493
588
|
},
|
|
494
589
|
"cacheTtl": {
|
|
495
590
|
"type": "integer",
|
|
496
|
-
"minimum":
|
|
497
|
-
"maximum": 2592000
|
|
591
|
+
"minimum": 0
|
|
498
592
|
},
|
|
499
593
|
"skipCache": {
|
|
500
594
|
"type": "boolean"
|
|
@@ -509,7 +603,6 @@
|
|
|
509
603
|
},
|
|
510
604
|
"metadata": {
|
|
511
605
|
"type": "object",
|
|
512
|
-
"maxProperties": 5,
|
|
513
606
|
"propertyNames": {
|
|
514
607
|
"not": {
|
|
515
608
|
"pattern": "^cf\\."
|
|
@@ -530,13 +623,11 @@
|
|
|
530
623
|
"properties": {
|
|
531
624
|
"maxAttempts": {
|
|
532
625
|
"type": "integer",
|
|
533
|
-
"minimum": 1
|
|
534
|
-
"maximum": 5
|
|
626
|
+
"minimum": 1
|
|
535
627
|
},
|
|
536
628
|
"retryDelayMs": {
|
|
537
629
|
"type": "integer",
|
|
538
|
-
"minimum": 0
|
|
539
|
-
"maximum": 60000
|
|
630
|
+
"minimum": 0
|
|
540
631
|
},
|
|
541
632
|
"backoff": {
|
|
542
633
|
"enum": [
|