@fayegram-ai/decision-bridge 0.1.2 → 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.
Files changed (72) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/CONTRIBUTING.md +5 -3
  3. package/README.md +24 -8
  4. package/SECURITY.md +18 -11
  5. package/docs/README.md +17 -4
  6. package/docs/development/ARCHITECTURE.md +32 -5
  7. package/docs/development/DESIGN.md +21 -3
  8. package/docs/development/RELEASING.md +7 -3
  9. package/docs/development/REPOSITORY_LAYOUT.md +2 -0
  10. package/docs/development/TESTING.md +31 -3
  11. package/docs/guides/BROWSER.md +5 -0
  12. package/docs/guides/CLOUDFLARE_DECISIONS.md +24 -46
  13. package/docs/guides/CUSTOMIZATION.md +8 -2
  14. package/docs/guides/CUSTOM_GENERATIVE.md +5 -3
  15. package/docs/guides/CUSTOM_PROVIDERS.md +5 -3
  16. package/docs/guides/EXTRACTION.md +125 -0
  17. package/docs/guides/GETTING_STARTED.md +8 -4
  18. package/docs/guides/JEV.md +13 -20
  19. package/docs/guides/LIVE_DECISIONS.md +163 -0
  20. package/docs/guides/OPENAI_DECISIONS.md +52 -24
  21. package/docs/guides/PLATFORMS.md +3 -3
  22. package/docs/guides/SWITCHING_MODELS.md +6 -2
  23. package/docs/guides/TROUBLESHOOTING.md +25 -0
  24. package/docs/reference/CLI.md +48 -10
  25. package/docs/reference/CONFIGURATION.md +31 -8
  26. package/docs/reference/ERRORS.md +41 -12
  27. package/docs/reference/PROVIDERS.md +19 -6
  28. package/docs/reference/SDK.md +62 -24
  29. package/docs/reference/SOURCES.md +7 -0
  30. package/examples/extraction.mjs +16 -0
  31. package/examples/live-decisions.mjs +24 -0
  32. package/package.json +11 -1
  33. package/schemas/decision.config.schema.json +88 -11
  34. package/src/bridge.mjs +9 -6
  35. package/src/capabilities.mjs +28 -4
  36. package/src/cli/config-validation.mjs +4 -4
  37. package/src/cli/config.mjs +4 -2
  38. package/src/cli/initialize.mjs +8 -4
  39. package/src/cli/live.mjs +63 -0
  40. package/src/cli/main.mjs +35 -12
  41. package/src/cli/provider-loader.mjs +3 -2
  42. package/src/cloudflare-decisions.d.mts +12 -5
  43. package/src/decisions.d.mts +28 -4
  44. package/src/errors.mjs +7 -1
  45. package/src/extraction/index.d.mts +66 -0
  46. package/src/extraction/index.mjs +78 -0
  47. package/src/extraction/validation.mjs +105 -0
  48. package/src/index.d.mts +18 -4
  49. package/src/input.mjs +21 -3
  50. package/src/live/index.d.mts +73 -0
  51. package/src/live/index.mjs +170 -0
  52. package/src/live/state.mjs +125 -0
  53. package/src/live/validation.mjs +122 -0
  54. package/src/providers/cloudflare-images.mjs +3 -9
  55. package/src/providers/cloudflare-media.mjs +5 -10
  56. package/src/providers/cloudflare-preflight.mjs +4 -3
  57. package/src/providers/cloudflare-profile.mjs +10 -14
  58. package/src/providers/cloudflare-transport.mjs +12 -5
  59. package/src/providers/cloudflare-validation.mjs +3 -1
  60. package/src/providers/decisions-codec.mjs +10 -5
  61. package/src/providers/decisions-input.mjs +120 -0
  62. package/src/providers/decisions-validation.mjs +37 -69
  63. package/src/providers/jev-images.mjs +2 -8
  64. package/src/providers/jev-preflight.mjs +1 -0
  65. package/src/providers/jev-profile.mjs +2 -2
  66. package/src/providers/media-binary.mjs +0 -7
  67. package/src/providers/openai-decisions.mjs +2 -1
  68. package/src/providers/openai-errors.mjs +23 -0
  69. package/src/providers/openai-profile.mjs +2 -1
  70. package/src/response-transport.mjs +84 -17
  71. package/src/validation.mjs +26 -14
  72. package/src/version.mjs +1 -1
@@ -1,7 +1,11 @@
1
1
  # Command runner reference
2
2
 
3
- The optional command runner evaluates files using the same bridge available in
4
- the SDK. For application integration, start with the [SDK guide](../guides/GETTING_STARTED.md).
3
+ The optional command runner evaluates decision files, runs Clairic extraction,
4
+ and validates or replays Live protocol records offline. For application
5
+ integration, start with the [SDK guide](../guides/GETTING_STARTED.md).
6
+
7
+ The extraction and Live commands require **0.1.3 or later**; see
8
+ [version availability](../README.md#version-availability).
5
9
 
6
10
  After [installing the package](../guides/GETTING_STARTED.md#install-into-your-application)
7
11
  in your project, run:
@@ -17,8 +21,10 @@ it with `node bin/decision.mjs` from a source checkout. `decision` and
17
21
  `faye-decision` are equivalent aliases with the same commands and options.
18
22
  `--help` and `--version` do not access credentials or services.
19
23
 
20
- The CLI defaults to Jev. Flags override `DECISION_*` environment settings, which
21
- override an explicit config file and then built-in defaults. It constructs an
24
+ Decision commands default to Jev. The extraction namespace defaults to
25
+ `cloudflare-extraction` only when no provider was selected. Flags override
26
+ `DECISION_*` environment settings, which override an explicit config file and
27
+ then built-in defaults. It constructs an
22
28
  explicit provider for the SDK; `createBridge` itself has no implicit selection.
23
29
  Choose a supported native model from the
24
30
  [model selector inventory](../../README.md#model-selectors).
@@ -50,6 +56,12 @@ there is no CLI binding selector. Gateway settings route the selected REST reque
50
56
  | `schema [FILE\|-]` | Print the generative response schema for these questions; local only |
51
57
  | `models` | List the configured provider's models; may be paginated |
52
58
  | `batch FILE\|-` | Stream JSONL inputs and ordered JSONL result/error records |
59
+ | `extraction run FILE\|-` | One native extraction; returns `{ extraction, meta }` |
60
+ | `extraction validate FILE\|-` | Offline structural and client-budget validation |
61
+ | `extraction batch FILE\|-` | Ordered extraction JSONL results and per-row errors |
62
+ | `extraction init [DIRECTORY]` | Create an extraction profile, request, schema and credential template |
63
+ | `live validate FILE\|- --kind config\|command\|event` | Offline Live structure validation |
64
+ | `live replay FILE\|-` | Offline JSONL protocol replay; no connection is opened |
53
65
 
54
66
  Jev supports both common and `--native` requests for evaluation, validation,
55
67
  initialization, and ordered batches. Experimental images/boxes require
@@ -57,9 +69,11 @@ initialization, and ordered batches. Experimental images/boxes require
57
69
  JSON configuration). Use `--no-jev-images` and `--no-jev-long-context` to
58
70
  override enabled settings. See the [Jev guide](../guides/JEV.md).
59
71
 
60
- No input filename on `evaluate`, `validate`, or `schema` selects the bundled sample,
72
+ No input filename on decision `evaluate`, `validate`, or `schema` selects the bundled sample,
61
73
  not stdin. Use `-` explicitly for stdin. Empty invocation prints help. Configuration
62
74
  and credential errors do not cause fallback to another backend.
75
+ Extraction and Live file operations require an explicit filename or `-`.
76
+ Extraction rejects `--native` because its request already uses native fields.
63
77
 
64
78
  ```bash
65
79
  cat request.json | decision-bridge evaluate - --env-file .env --compact
@@ -94,7 +108,7 @@ later configuration changes to control selection.
94
108
  | --- | --- |
95
109
  | `--config FILE` | Explicit JSON configuration; never autodiscovered |
96
110
  | `--env-file FILE` | Load an explicit environment file without changing the parent shell |
97
- | `--provider NAME` | `jev`, `openai-decisions`, `cloudflare-decisions`, `custom-decision`, `custom-generative` |
111
+ | `--provider NAME` | `jev`, `openai-decisions`, `cloudflare-decisions`, `cloudflare-extraction` (extraction namespace), `custom-decision`, `custom-generative` |
98
112
  | `--preset NAME` | custom-generative preset: `openai-compatible`, `openrouter`, or `anthropic`; exclusive with module |
99
113
  | `--native` | Explicit native Decisions input/output; init/evaluate/validate/batch only |
100
114
  | `--jev-images`, `--no-jev-images` | Enable/disable experimental Jev images and boxes |
@@ -103,7 +117,7 @@ later configuration changes to control selection.
103
117
  | `--base-url URL` | Custom endpoint; requires explicit credential selection |
104
118
  | `--api-key-env NAME` | Environment variable name, never the key itself |
105
119
  | `--account-id ID` | Cloudflare REST account ID |
106
- | `--reject-if-busy`, `--no-reject-if-busy` | Explicit Cloudflare native-request override. Enabling fails local REST preflight with `UNSUPPORTED_CAPABILITY`; disabling permits ordinary inference. See the [REST limitation](../guides/CLOUDFLARE_DECISIONS.md#capacity-rejection-and-ai-gateway) |
120
+ | `--reject-if-busy`, `--no-reject-if-busy` | Override Cloudflare request/provider busy settings. Enabling fails Clef REST preflight; Clairic forwards the setting. See the [Clef REST limitation](../guides/CLOUDFLARE_DECISIONS.md#capacity-rejection-and-ai-gateway) |
107
121
  | `--gateway-id ID` | Existing Cloudflare Gateway; richer settings in config |
108
122
  | `--no-auth` | Only for a loopback OpenAI-compatible endpoint |
109
123
  | `--timeout-ms N` | HTTP and bridge deadline for each evaluation/listing |
@@ -117,6 +131,7 @@ later configuration changes to control selection.
117
131
  | `--force` | Replace existing output; valid only with `--output` |
118
132
  | `--concurrency N` | Batch in-flight limit 1–64; default 4 |
119
133
  | `--pretty`, `--compact` | JSON formatting; pretty by default; batches always JSONL |
134
+ | `--kind config\|command\|event` | Required by `live validate`; rejected by other commands |
120
135
  | `--help`, `-h`, `--version`, `-v` | Informational commands |
121
136
 
122
137
  Unknown or duplicate flags fail. Provider-inapplicable flags fail instead of being
@@ -138,6 +153,10 @@ includes `validationScope: 'provider'` for known native/preset profiles or
138
153
  `'structure'` for a custom module. Structure validation cannot verify an unknown
139
154
  module's capabilities or protocol. `schema` is an offline generative-output tool;
140
155
  it does not add generative support to a native provider.
156
+ Decision validation reports `operation: 'decision'` and `questionCount`;
157
+ extraction reports `operation: 'extraction'` and `fieldCount`. Neither authenticates
158
+ an account or claims server admission. Live validation reports its `kind` and
159
+ `validationScope: 'structure'`.
141
160
 
142
161
  A batch emits one compact record per nonblank input line:
143
162
 
@@ -181,14 +200,16 @@ delivery needs separate validation.
181
200
  ## I/O and resource limits
182
201
 
183
202
  Single JSON input normally uses **8 MiB**. JSONL normally uses **8 MiB per line,
184
- 64 MiB total**. Jev permits **32 MiB** for a single JSON input or JSONL record,
203
+ 64 MiB total**. Jev defaults to **32 MiB** for a single JSON input or JSONL record,
185
204
  then checks serialized requests against its configured ceiling (32 MiB by default).
205
+ An explicit larger client request budget raises the input reader budget through 64 MiB.
186
206
  Config:
187
207
  **1 MiB**. Environment file: **64 KiB**. Provider request and response default to
188
208
  8 MiB each, configurable to at most 64 MiB. Cloudflare reads single JSON inputs
189
209
  and individual JSONL records within 64 MiB, then applies model-specific serialized
190
- request validation: Clef/Clef-flash default/cap 13 MiB; Omni default 36 MiB,
191
- configurable through 64 MiB. Explicit smaller ceilings remain in force. Request
210
+ request validation: Clef/Clef-flash default 13 MiB, configurable through 64 MiB; Omni default 36 MiB,
211
+ configurable through 64 MiB; Clairic defaults to 8 MiB, configurable through 64 MiB.
212
+ Explicit smaller ceilings remain in force. Request
192
213
  model overrides and mixed-model JSONL batches use each effective model's budget.
193
214
  The 64 MiB JSONL total remains. These are client limits, not a promise
194
215
  that every remote model has an equivalent context window.
@@ -222,3 +243,20 @@ Already-cancelled CLI work does not initialize a project or create an output fil
222
243
  File writers check cancellation before writes and before submitting the atomic
223
244
  commit. A commit already submitted to the operating system cannot be undone;
224
245
  cancellation does not roll back a completed write or remote inference billing.
246
+
247
+ ## Offline Live tools
248
+
249
+ Live tools load no provider configuration, environment files or credentials and
250
+ open no connection. They accept input/output and formatting flags; `--kind` is
251
+ required only for validation. Replay always emits compact JSONL.
252
+
253
+ Replay input records are `{ direction: 'client' | 'server', event }`. Each row
254
+ produces `{ line, ok, event }` or `{ line, ok: false, error }` using the same
255
+ correlation state as the SDK controller. Malformed rows remain explicit errors
256
+ and later rows are processed. A closed session ends that replay lifecycle;
257
+ subsequent protocol rows fail with `CONNECTION_CLOSED`.
258
+
259
+ Malformed event-file validation reports `VALIDATION_ERROR` and exits 2. Malformed
260
+ server replay rows retain `INVALID_RESPONSE`; any failed row makes replay exit 1.
261
+ See the [Live guide](../guides/LIVE_DECISIONS.md) for correlation guarantees and
262
+ the [extraction guide](../guides/EXTRACTION.md) for native extraction requests.
@@ -29,16 +29,17 @@ is native-only. Generative presets use `createGenerativeProvider` from the
29
29
  `@fayegram-ai/decision-bridge/config.schema.json` and in
30
30
  [schemas/decision.config.schema.json](../../schemas/decision.config.schema.json).
31
31
  It checks profile structure; runtime preflight additionally checks endpoint,
32
- credential, capability, and model-specific limits.
32
+ credential, capability, and serialized client-byte budgets.
33
33
  Cloudflare CLI configuration always selects REST. Inject a Workers AI binding
34
- through the SDK's `CloudflareDecisionsProvider` constructor instead of a JSON
35
- profile. Gateway configuration is optional for either SDK transport and for CLI REST.
34
+ through the SDK's `CloudflareDecisionsProvider` or `CloudflareExtractionProvider`
35
+ constructor instead of a JSON profile. Gateway configuration is optional for
36
+ either SDK transport and for CLI REST.
36
37
 
37
38
  | Field | Values / scope |
38
39
  | --- | --- |
39
40
  | `$schema` | Optional nonempty schema reference for editors |
40
41
  | `schemaVersion` | 1; optional, but generated profiles include it |
41
- | `provider` | `jev` default, `openai-decisions`, `cloudflare-decisions`, `custom-decision`, `custom-generative` |
42
+ | `provider` | `jev` default for decision commands, `openai-decisions`, `cloudflare-decisions`, `cloudflare-extraction` for extraction commands, `custom-decision`, `custom-generative` |
42
43
  | `preset` | `custom-generative` only: `openai-compatible`, `openrouter`, `anthropic`; mutually exclusive with module |
43
44
  | `model` | Nonempty model selector or supported upstream ID; built-in native providers have defaults; required for generative evaluation unless the request supplies it |
44
45
  | `baseURL` | HTTPS API base; loopback may use HTTP |
@@ -46,9 +47,9 @@ profile. Gateway configuration is optional for either SDK transport and for CLI
46
47
  | `noAuth` | Boolean; true only for loopback OpenAI-compatible endpoints |
47
48
  | `timeoutMs` | Positive integer up to 2,147,483,647 milliseconds |
48
49
  | `maxRetries` | Integer 0–10; OpenAI/Cloudflare default 0; Jev and generative presets default 2 |
49
- | `maxRequestBytes`, `maxResponseBytes` | Positive integer through 64 MiB; default 8 MiB. Jev requests default/cap 32 MiB. Cloudflare requests: Clef/Clef-flash default/cap 13 MiB; Omni default 36 MiB, configurable through 64 MiB |
50
+ | `maxRequestBytes`, `maxResponseBytes` | Positive integer through 64 MiB; default 8 MiB, including Clairic. Jev requests default 32 MiB. Clef/Clef-flash requests default 13 MiB; Omni 36 MiB. Explicit request budgets can select through 64 MiB for every built-in provider |
50
51
  | `accountId` | Cloudflare REST account ID; otherwise `CLOUDFLARE_ACCOUNT_ID` |
51
- | `rejectIfBusy` | Cloudflare boolean; default false, incompatible with retries. Effective true fails REST preflight with `UNSUPPORTED_CAPABILITY`; see the [binding support and REST limitation](../guides/CLOUDFLARE_DECISIONS.md#capacity-rejection-and-ai-gateway) |
52
+ | `rejectIfBusy` | Cloudflare boolean; default false, incompatible with retries. Effective true fails Clef REST preflight with `UNSUPPORTED_CAPABILITY`; Clairic forwards the setting for server acceptance/rejection. See the [Clef limitation](../guides/CLOUDFLARE_DECISIONS.md#capacity-rejection-and-ai-gateway) and [extraction options](../guides/EXTRACTION.md#images-binding-and-gateway) |
52
53
  | `gateway` | Cloudflare Gateway object; see the [Cloudflare guide](../guides/CLOUDFLARE_DECISIONS.md) |
53
54
  | `dangerZone` | Jev-only `{ images?: boolean, longContext?: boolean }`; both default false; see the [Jev guide](../guides/JEV.md) |
54
55
  | `maxTokens` | Generative output budget, 1–1,048,576; default 4096 |
@@ -59,8 +60,8 @@ profile. Gateway configuration is optional for either SDK transport and for CLI
59
60
  | `options` | Custom factory's JSON options, e.g. its own baseURL |
60
61
 
61
62
  Upper numeric limits validate client configuration, not vendor model capabilities.
62
- Jev requests default to and are capped at 32 MiB; a smaller `maxRequestBytes`
63
- lowers that ceiling. `DECISION_JEV_IMAGES` and `DECISION_JEV_LONG_CONTEXT`
63
+ Jev requests default to a 32 MiB client budget; an explicit `maxRequestBytes`
64
+ can select a budget through 64 MiB. `DECISION_JEV_IMAGES` and `DECISION_JEV_LONG_CONTEXT`
64
65
  accept `true` or `false`; their CLI overrides are `--jev-images`,
65
66
  `--no-jev-images`, `--jev-long-context`, and `--no-jev-long-context`.
66
67
  Cloudflare selects its byte budget from the effective request model, including
@@ -173,3 +174,25 @@ presets, and separate custom decision/generative modules. Use
173
174
  with `--provider-module FILE`. The module flag does not infer classification. Replace placeholder model identifiers
174
175
  with IDs returned by the intended account/server. Profiles intentionally contain
175
176
  no real key or claim that one model is available to every user.
177
+
178
+ ## Extraction and Live configuration
179
+
180
+ The `extraction` namespace supplies provider `cloudflare-extraction` only when
181
+ flags, environment and an explicit file have selected no provider. Its default
182
+ model is `clairic`; `@cf/cloudflare/clairic` is also accepted. An explicit
183
+ incompatible provider is rejected. Provider switching follows the same isolation
184
+ rules above, including transitions between Clef and Clairic. The configuration
185
+ schema stays at version 1.
186
+
187
+ OpenAI prompt-cache controls and Clairic inference settings (`include_quantiles`,
188
+ `return_state_text`) belong in request JSON. Extraction busy-mode flags override
189
+ the request's `options.rejectIfBusy`; otherwise that request value overrides the
190
+ provider setting. See [extraction](../guides/EXTRACTION.md).
191
+
192
+ Live SDK configuration is passed directly to `createLiveDecisions` with a supplied
193
+ transport. Offline `live validate` and `live replay` do not load provider profiles,
194
+ credentials or environment files. See [Live Decisions](../guides/LIVE_DECISIONS.md).
195
+
196
+ Offline validation checks structure and client resource budgets. Service quotas,
197
+ context/media admission and Gateway limits remain upstream; the SDK and CLI do
198
+ not estimate tokens or enforce RPM/TPM.
@@ -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` | Encoded provider request exceeds configured limit; reduce input/schema |
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` | Cloudflare allocation limit exceeded (3036) |
24
- | `RATE_LIMITED` | Cloudflare HTTP 429 without a more specific code |
25
- | `AUTHENTICATION_ERROR`, `PERMISSION_DENIED` | Cloudflare authentication or authorization failure |
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
- only, for both HTTP requests and Workers AI binding responses. `maxRetries`
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 and Cloudflare Clef default to 0; explicitly enabling retries can repeat a billed
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. Without it, exponential backoff
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
- Authentication failures, generic HTTP 500, invalid output, model refusal, and
58
- ambiguous network failures are not retried automatically. HTTP retries are not an
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 exposes throttling;
68
- repeated retries can increase load. For `INVALID_RESPONSE`, a schema-capable model
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).
@@ -45,20 +45,21 @@ contract. The following additional forms are checked before dispatch:
45
45
  | Provider | Ordered text / embedded images | Typed string/boolean choices | Labelled score levels | Safety identifier | Model listing |
46
46
  | --- | --- | --- | --- | --- | --- |
47
47
  | Jev | Ordered text; images with explicit opt-in | Unsupported | Unsupported | Unsupported | Supported |
48
- | OpenAI Decisions | Supported; up to 128 images, preserving order | Supported | Supported | Supported | Unsupported |
49
- | Cloudflare Clef / Clef-flash | Supported; up to four images before text | Supported | Supported; 2–10 levels | Unsupported | Unsupported |
50
- | Cloudflare Clef-omni | Supported; up to four images before audio/video/text | Supported | Supported; 2–10 levels | Unsupported | Unsupported |
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 their own limits, described in the
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 up to four audio clips and two videos. The optional
61
- capability fields `audio`, `videos`, `maxAudioClips`, and `maxVideos` normalize to
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
 
@@ -66,6 +67,11 @@ Jev additionally supports `box` questions on `jev-preview` and pinned 1.14+ mode
66
67
  when `dangerZone.images` is enabled. Other built-ins reject box questions.
67
68
  See the [Jev guide](../guides/JEV.md) for asset placement and experimental opt-ins.
68
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
+
69
75
  Dedicated `createDecision()` access is available on Jev, OpenAI Decisions and
70
76
  Cloudflare providers. It uses each service's native request/response shape and
71
77
  bypasses bridge preparation and observation hooks.
@@ -124,3 +130,10 @@ do not override them. This release has no silent provider failover, model search
124
130
  credential refresh, provider-side batch API, or universal quality guarantee.
125
131
  Unsupported protocols require an explicit custom decision or generative provider; unsupported server
126
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.
@@ -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; Jev defaults to and caps at 32 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` or ordered `input`, `questions`, and optional
72
- `model` and `safetyIdentifier`. New forms require declared provider capabilities;
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: 'audio', dataUrl }`, or `{ type: 'video', dataUrl }`. Audio/video are
85
- supported by Cloudflare Clef-omni and explicitly capable custom providers; other
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. Media use embedded data URLs, with format and size checks described
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 sequential state or input preparation,
91
- invokes the provider once, validates the result, then observes an immutable result.
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
 
@@ -151,18 +161,17 @@ must declare `boxes: true`. Jev supports it with experimental image opt-in and
151
161
  a supported model; see [Jev images and boxes](../guides/JEV.md).
152
162
 
153
163
  Builders return immutable question objects. `choice(instructions, criteria)` accepts
154
- a label map containing 1 to 255 options. `noul(instructions, criteria?)` accepts an
164
+ a nonempty label map. `noul(instructions, criteria?)` accepts an
155
165
  optional criteria object,
156
- with only `true` and `false` keys. `score(instructions, criteria)` accepts **2–10**
166
+ with only `true` and `false` keys. `score(instructions, criteria)` accepts at least two
157
167
  ordered levels; numeric level indices are zero-based. There is no boolean alias:
158
168
  `noul` means a probability, not a thresholded truth value.
159
169
 
160
170
  `choice(instructions, options)` accepts ordered objects with unique string or
161
171
  boolean `value` fields and optional text or structured JSON descriptions. Boolean `true` and string
162
172
  `"true"` remain distinct. `scoreLevels(instructions, levels)` accepts at least two
163
- ordered label/description objects. Provider preflight applies service limits:
164
- OpenAI Decisions and Cloudflare require 2–255 choices; Cloudflare limits scores
165
- 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.
166
175
 
167
176
  ## Returned data
168
177
 
@@ -233,21 +242,26 @@ estimated token count is fabricated.
233
242
 
234
243
  Metadata can have additional JSON fields. Application logic should not assume
235
244
  unavailable metadata exists. Result objects and nested data returned by the bridge
236
- are immutable. Standalone validation functions return snapshots, not frozen values.
245
+ are immutable. Standalone common `validateRequest` and `validateResult` return
246
+ snapshots without freezing them; dedicated extraction and Live validators return
247
+ frozen snapshots.
237
248
 
238
- `schemaVersion` remains 1 for legacy requests and 2 for ordered images/text or
239
- richer question forms. Audio/video requests use 3; requests with boxes use 4.
240
- This result version is separate
241
- from the CLI configuration schema, which remains 1.
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.
242
254
 
243
255
  ## Extensions
244
256
 
245
257
  An extension has a unique printable `name` (maximum 100 characters), optional
246
- `prepareState(state, context)`, `prepareInput(input, context)`, and
258
+ `prepareState(state, context)`, `prepareInput(input, context)`,
259
+ `prepareConversation(items, context)`, and
247
260
  `onResult(result, context)`. Preparation extensions must support the request's
248
261
  input form; incompatible hooks fail explicitly before dispatch.
249
262
 
250
- Preparation returns replacement state or input, or `undefined` to leave it unchanged.
263
+ Preparation returns replacement state, ordered input or conversation, or
264
+ `undefined` to leave it unchanged.
251
265
  Preparation exceptions fail before inference with `EXTENSION_ERROR`; transformed
252
266
  content is revalidated, including capabilities and provider preflight. Preparation
253
267
  cannot rewrite question definitions or switch the model.
@@ -362,14 +376,14 @@ decision providers may preserve custom string labels. Generative prompt and
362
376
  normalization helpers independently validate the shared-state, legacy-question
363
377
  profile and explicitly reject unsupported request capabilities.
364
378
  Decision-kind classification alone does not require confidence or known counts;
365
- `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
366
380
  Jev's contract. See [custom decision](../guides/CUSTOM_DECISION.md),
367
381
  [custom generative](../guides/CUSTOM_GENERATIVE.md), and the shared
368
382
  [custom contract](../guides/CUSTOM_PROVIDERS.md).
369
383
 
370
384
  ## Validation guarantees
371
385
 
372
- Legacy choice criteria maps allow at most 255 options, matching Jev's contract. Noul
386
+ Legacy choice criteria maps must be nonempty. Noul
373
387
  criteria must be omitted or an object; its present true/false descriptions cannot
374
388
  be raw null. Score levels likewise cannot be raw null (nested null JSON values are
375
389
  still allowed). These invalid forms now fail before provider dispatch.
@@ -379,7 +393,10 @@ the answer. `evaluateBatch()` validates array holes as invalid requests before a
379
393
  item is dispatched, rather than spending on adjacent valid entries.
380
394
 
381
395
  The optional third argument to `validateResult()` must be a plain options object
382
- with optional boolean `native` and integer `probabilityDecimalPlaces` (1–15) fields.
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.
383
400
  Providers can declare a pure synchronous `getResultValidationOptions(model)` hook;
384
401
  its policy is validated before inference and is not read from response metadata.
385
402
  Returning a Promise is a configuration error; its rejection is observed without
@@ -400,3 +417,24 @@ Native provider cancellation/timeout errors preserve the last observed sanitized
400
417
  request ID and attempt count when available. The bridge may settle its own
401
418
  cancellation race before the provider returns diagnostics; do not require those
402
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.
@@ -22,6 +22,8 @@ reference does not imply that authenticated inference was run against its servic
22
22
  | OpenAI structured output modes | https://platform.openai.com/docs/guides/structured-outputs |
23
23
  | OpenAI native Decisions guide | https://developers.openai.com/api/docs/guides/decisions |
24
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 |
25
27
  | OpenRouter structured output and routing | https://openrouter.ai/docs/guides/features/structured-outputs |
26
28
  | Anthropic Messages, tools, usage, and stop reasons | https://platform.claude.com/docs/en/api/messages/create |
27
29
  | GitHub checkout action | https://github.com/actions/checkout |
@@ -48,6 +50,11 @@ separate operational check.
48
50
  - [Cloudflare-owned model implementation](https://huggingface.co/Cloudflare/clef-flash/blob/main/joint_schema_model.py), including output precision
49
51
  - [Cloudflare-owned Omni implementation](https://huggingface.co/Cloudflare/clef-omni/blob/main/joint_schema_model.py), including grouped media and output precision
50
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
+
51
58
  ## Package and repository release
52
59
 
53
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.2",
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": {