@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.
Files changed (79) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/CONTRIBUTING.md +5 -3
  3. package/README.md +26 -10
  4. package/SECURITY.md +18 -11
  5. package/docs/README.md +19 -5
  6. package/docs/development/ARCHITECTURE.md +36 -7
  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 +8 -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 +167 -0
  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 +60 -11
  25. package/docs/reference/CONFIGURATION.md +34 -6
  26. package/docs/reference/ERRORS.md +41 -12
  27. package/docs/reference/PROVIDERS.md +31 -8
  28. package/docs/reference/SDK.md +72 -26
  29. package/docs/reference/SOURCES.md +11 -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 +102 -11
  34. package/src/bridge.mjs +9 -6
  35. package/src/capabilities.mjs +34 -4
  36. package/src/cli/config-validation.mjs +13 -5
  37. package/src/cli/config.mjs +19 -4
  38. package/src/cli/decisions.mjs +8 -0
  39. package/src/cli/initialize.mjs +8 -4
  40. package/src/cli/live.mjs +63 -0
  41. package/src/cli/main.mjs +50 -16
  42. package/src/cli/provider-loader.mjs +3 -2
  43. package/src/cloudflare-decisions.d.mts +12 -5
  44. package/src/decisions.d.mts +28 -4
  45. package/src/errors.mjs +7 -1
  46. package/src/extraction/index.d.mts +66 -0
  47. package/src/extraction/index.mjs +78 -0
  48. package/src/extraction/validation.mjs +105 -0
  49. package/src/index.d.mts +42 -9
  50. package/src/index.mjs +1 -1
  51. package/src/input.mjs +21 -3
  52. package/src/jev.d.mts +16 -0
  53. package/src/live/index.d.mts +73 -0
  54. package/src/live/index.mjs +170 -0
  55. package/src/live/state.mjs +125 -0
  56. package/src/live/validation.mjs +122 -0
  57. package/src/probabilities.mjs +6 -3
  58. package/src/providers/cloudflare-images.mjs +5 -67
  59. package/src/providers/cloudflare-media.mjs +5 -10
  60. package/src/providers/cloudflare-preflight.mjs +4 -3
  61. package/src/providers/cloudflare-profile.mjs +10 -14
  62. package/src/providers/cloudflare-transport.mjs +12 -5
  63. package/src/providers/cloudflare-validation.mjs +3 -1
  64. package/src/providers/decisions-codec.mjs +10 -5
  65. package/src/providers/decisions-input.mjs +120 -0
  66. package/src/providers/decisions-validation.mjs +37 -69
  67. package/src/providers/image-header.mjs +59 -0
  68. package/src/providers/jev-images.mjs +84 -0
  69. package/src/providers/jev-preflight.mjs +62 -0
  70. package/src/providers/jev-profile.mjs +37 -0
  71. package/src/providers/jev.mjs +32 -13
  72. package/src/providers/media-binary.mjs +0 -7
  73. package/src/providers/openai-decisions.mjs +2 -1
  74. package/src/providers/openai-errors.mjs +23 -0
  75. package/src/providers/openai-profile.mjs +2 -1
  76. package/src/questions.mjs +2 -0
  77. package/src/response-transport.mjs +84 -17
  78. package/src/validation.mjs +39 -20
  79. package/src/version.mjs +1 -1
@@ -16,8 +16,7 @@ short selectors and full forms.
16
16
  Questions and media consume context before text state; the service truncates
17
17
  remaining text state to fit. Requests whose questions/media exhaust context can
18
18
  fail. Byte checks cannot guarantee token fit or detect remote truncation.
19
- Clef's serving improvements and Clef-flash's lower pricing apply upstream without
20
- client configuration. Consult the official [model pages](#official-references)
19
+ Consult the official [model pages](#official-references)
21
20
  for current pricing and availability; the bridge does not discover account access.
22
21
 
23
22
  ## Supported inference paths
@@ -108,7 +107,7 @@ extensions and the bridge's separate total deadline.
108
107
 
109
108
  ## Embedded images and limits
110
109
 
111
- Clef accepts up to four embedded PNG, JPEG, or WebP images. Native `images` entries
110
+ Clef accepts embedded PNG, JPEG, or WebP images; the service owns count admission. Native `images` entries
112
111
  can be base64 data URLs or `{ content_type, base64 }` objects. Remote URLs are
113
112
  rejected. Common ordered input places all images before all text:
114
113
 
@@ -130,24 +129,15 @@ Text parts concatenate exactly, without inserted separators. Image detail can be
130
129
  omitted, `null`, or `auto`; explicit `low`, `high`, and `original` are unsupported.
131
130
  Safety identifiers are unsupported by this provider.
132
131
 
133
- | Boundary | Limit |
134
- | --- | --- |
135
- | Questions per request | 1–64 |
136
- | Question IDs | 1–100 ASCII letters, digits, `_`, `.`, or `-` |
137
- | Choice options | 2–255 |
138
- | Score levels | 2–10, ordered lowest first, indexed from zero |
139
- | Images | At most four |
140
- | Decoded image size | 4 MiB each; 8 MiB combined |
141
- | Image dimensions | Positive dimensions; at most 16 million pixels each |
142
- | Serialized request | Clef/Clef-flash: at most 13 MiB; Omni: 36 MiB by default, configurable through 64 MiB |
143
-
144
- Preflight checks supported formats, base64 syntax, headers, dimensions, and size.
145
- Header inspection is not full image decoding; the service can reject corrupt image data.
146
- Limits include execution options and binding envelope overhead. Omni's 36 MiB
147
- default is a bridge policy allowing base64 expansion of the permitted decoded
148
- media; its published schema specifies no whole-request byte ceiling. The effective
149
- request model selects the budget, including per-call overrides. An explicit
150
- `maxRequestBytes` remains a caller ceiling and is never enlarged by selecting Omni.
132
+ Preflight validates supported representations, canonical base64, positive image
133
+ dimensions and container structure. Service question/media counts, decoded sizes,
134
+ dimensions, duration and context ceilings are not enforced locally. Header
135
+ inspection is not full decoding; upstream admission and decoding remain authoritative.
136
+
137
+ Client request budgets default to 13 MiB for Clef/Clef-flash and 36 MiB for Omni.
138
+ An explicit `maxRequestBytes` overrides either default through the shared 64 MiB
139
+ client ceiling. Binding envelope overhead counts toward that budget. Response
140
+ budgets remain separate. No automatic resizing, splitting or truncation occurs.
151
141
 
152
142
  Cloudflare's four-decimal probability precision receives a count-aware sum
153
143
  allowance: the larger of 0.001 and half a decimal unit per option, plus floating-point
@@ -204,19 +194,10 @@ audio/video parts accept only `type` and `dataUrl`; remote URLs, paths, image
204
194
  detail, and caller-provided durations are rejected. Other providers and the older
205
195
  Clef models reject audio/video before dispatch.
206
196
 
207
- | Media | Count | Decoded size per item | Duration per item |
208
- | --- | ---: | ---: | ---: |
209
- | Audio | 4 | 8 MiB | 300 seconds |
210
- | Video | 2 | 16 MiB | 60 seconds |
211
-
212
- Audio and video together are limited to 16 MiB decoded. Image limits above remain
213
- separate. Bounded inspectors validate canonical base64, MIME/header consistency,
214
- and container structure, and reject excessive duration when PCM/float WAV,
215
- ordinary MP3 frames, MP4 metadata, or WebM metadata establishes it reliably.
216
- Full decoding, codec validity, and duration that cannot be established locally
217
- (including compressed WAV, free-format MP3, or missing container duration) remain
218
- service validation. The bridge performs no transcription, transcoding, frame
219
- extraction, or streaming, and adds no runtime media dependency.
197
+ Inspectors validate canonical base64, MIME/header consistency and supported
198
+ container structure. Service count, decoded-size and duration limits are handled
199
+ as upstream errors. The bridge performs no transcription, transcoding, frame
200
+ extraction or streaming, and adds no runtime media dependency.
220
201
 
221
202
  Cloudflare samples video at two frames per second. Video soundtracks are processed
222
203
  only when **every supplied video has a soundtrack**. Common results use
@@ -302,23 +283,20 @@ binding sends Gateway settings in the third `ai.run()` argument.
302
283
 
303
284
  | Setting | Accepted value |
304
285
  | --- | --- |
305
- | `id` | Required nonblank printable ASCII string, 1–64 characters |
306
- | `cacheKey` | Optional nonblank printable ASCII string, 1–200 characters |
307
- | `cacheTtl` | Integer seconds, 60–2,592,000 (30 days) |
286
+ | `id` | Required nonblank printable ASCII string |
287
+ | `cacheKey` | Optional nonblank printable ASCII string |
288
+ | `cacheTtl` | Nonnegative integer seconds; service cache policy applies upstream |
308
289
  | `skipCache`, `collectLog` | Optional booleans |
309
- | `metadata` | At most five entries with JSON primitive values; caller-supplied `cf.*` keys are reserved |
290
+ | `metadata` | JSON primitive values; caller-supplied `cf.*` keys are reserved |
310
291
  | `requestTimeoutMs` | Positive integer milliseconds, up to 2,147,483,647 |
311
- | `retries.maxAttempts` | 1–5; defaults to 1 when Gateway is configured |
312
- | `retries.retryDelayMs` | 0–60,000 milliseconds |
292
+ | `retries.maxAttempts` | Positive integer; defaults to 1 when Gateway is configured |
293
+ | `retries.retryDelayMs` | Nonnegative integer milliseconds |
313
294
  | `retries.backoff` | `constant`, `linear`, or `exponential` |
314
295
 
315
296
  The shared validator rejects invalid Gateway settings with `CONFIGURATION_ERROR`
316
- before dispatch. Metadata is preserved unchanged: the bridge rejects entries
317
- that [Cloudflare would ignore or remove](https://developers.cloudflare.com/ai-gateway/observability/custom-metadata/)
318
- instead of silently dropping them. Cloudflare's [cache TTL documentation](https://developers.cloudflare.com/ai-gateway/features/caching/)
319
- describes the upper limit as one month; its [official numeric reference](https://github.com/cloudflare/skills/blob/0cb6116228ad153126f474dce1dfbd05f7944604/skills/cloudflare/references/ai-gateway/README.md)
320
- specifies 2,592,000 seconds (30 days). Cache TTL and first-response timeout have
321
- separate validation bounds.
297
+ before dispatch. Metadata is preserved unchanged. Reserved `cf.*` keys and
298
+ non-primitive values are rejected; service entry-count and cache admission
299
+ limits remain upstream. The adapter does not infer Gateway acceptance.
322
300
 
323
301
  Gateway timeout covers time to the first response; the bridge's total deadline
324
302
  continues to bound the call. Gateway logging/caching follows the explicit options
@@ -1,6 +1,7 @@
1
1
  # Customizing decisions and extending the bridge
2
2
 
3
- Customization is **per request**. You supply context in `state`, the judgment in
3
+ Customization is **per request**. You supply context in `state`, ordered `input`
4
+ or `conversation` according to provider capabilities, the judgment in
4
5
  `instructions`, and the allowed categories/rubric in `criteria`. The same bridge
5
6
  instance can evaluate unrelated tasks on successive calls. This changes the
6
7
  question sent to the existing model, not its weights or account configuration.
@@ -79,6 +80,10 @@ const bridge = createBridge({
79
80
  Extensions run in registration order. They receive immutable snapshots and must
80
81
  return replacements rather than mutate input. Async retrieval can use the supplied
81
82
  context signal. No content is persisted unless your extension explicitly saves it.
83
+ Use `prepareInput(parts, context)` for ordered input and
84
+ `prepareConversation(items, context)` for conversation history. A preparation
85
+ extension must implement the selected form's hook; transformed content is
86
+ revalidated before dispatch. Observer-only extensions work with every form.
82
87
 
83
88
  ## Observe without changing decisions
84
89
 
@@ -133,7 +138,8 @@ and [SDK validation contract](../reference/SDK.md#additional-exports).
133
138
 
134
139
  ## Develop additions without changing the public call
135
140
 
136
- Add retrieval/redaction through `prepareState` or `prepareInput`, metrics through
141
+ Add retrieval/redaction through `prepareState`, `prepareInput` or
142
+ `prepareConversation`, metrics through
137
143
  `onResult`, and another protocol through the explicit [custom decision](CUSTOM_DECISION.md)
138
144
  or [custom generative](CUSTOM_GENERATIVE.md) contract. Keep routing/threshold policies
139
145
  outside the provider and cover additions with relevant regression tests. Persisted templates,
@@ -72,8 +72,9 @@ or zero-based level indices. It checks probabilities, derives argmax/weighted
72
72
  scores and matching legends, and marks absent usage as unknown. It does not repair
73
73
  JSON, strip Markdown, or create confidence. `buildPrompt` and `normalizeGenerated`
74
74
  independently validate and snapshot the request. They require shared state and
75
- legacy questions, and reject ordered input, typed choices, labelled scores, and
76
- safety identifiers with `UNSUPPORTED_CAPABILITY`. Malformed request JSON raises
75
+ legacy questions, and reject ordered input, conversation/tool history, remote
76
+ images, prompt-cache controls, typed choices, labelled scores and safety
77
+ identifiers with `UNSUPPORTED_CAPABILITY`. Malformed request JSON raises
77
78
  `VALIDATION_ERROR`; unsupported input is never silently discarded. New modules
78
79
  implement their own encoding and normalization for richer capabilities.
79
80
 
@@ -110,7 +111,8 @@ provenance and `confidenceSource: 'unavailable'`, and rejects returned native
110
111
  confidence claims or answer confidence fields. Their output is an estimate elicited
111
112
  from a model, not a native probability, logprob, or calibration guarantee.
112
113
  Presets support shared state and legacy `choice`, `noul`, and `score`; ordered
113
- media, typed choices, labelled scores, and safety identifiers are unsupported.
114
+ media, conversation/tool history, remote images, prompt-cache controls, typed
115
+ choices, labelled scores and safety identifiers are unsupported.
114
116
  A new module may declare capabilities only after implementing and validating them.
115
117
 
116
118
  ## OpenAI-compatible servers
@@ -41,7 +41,9 @@ Internal transport helpers are not stable public exports. Delegate a maintained
41
41
  preset for a protocol already supported, or implement and test your own transport.
42
42
 
43
43
  Capability omissions retain the legacy shared-state and question profile. Audio
44
- and video additions default to false/zero. Declare richer forms only when their
44
+ and video additions default to false/zero; conversation, tool history, remote
45
+ images and prompt caching default to false. Explicit quantitative custom limits
46
+ are enforced; `null` leaves that admission limit to the service. Declare richer forms only when their
45
47
  encoding and validation are implemented. The bridge runs preflight again after
46
48
  preparation hooks. Unknown usage is null; no provider should invent token counts,
47
49
  confidence, or calibration. Generative native-provenance claims are rejected.
@@ -68,8 +70,8 @@ relative to that file; flag paths
68
70
  resolve relative to the working directory. Explicit modules execute trusted code;
69
71
  this extension point is not a sandbox. No module is discovered automatically.
70
72
 
71
- `init` creates an honest service implementation placeholder when no implementation
72
- is selected. When given an existing module, it references that module without
73
+ `init` creates a provider module with an unimplemented service call when no
74
+ implementation is selected. When given an existing module, it references that module without
73
75
  loading or overwriting it. Offline `validate` never imports custom modules or
74
76
  requires credentials; it reports structure-only validation for unknown protocols.
75
77
  `bridge.validate()` on an instantiated provider includes capabilities and preflight.
@@ -0,0 +1,125 @@
1
+ # Clairic extraction
2
+
3
+ Requires **0.1.3 or later**. See [version availability](../README.md#version-availability)
4
+ and [installation](GETTING_STARTED.md#install-into-your-application).
5
+
6
+ Import extraction from `@fayegram-ai/decision-bridge/extraction`. This operation
7
+ returns typed values and predictive statistics, using Cloudflare Clairic through
8
+ REST or an injected Workers AI binding. Its result is independent of the decision
9
+ bridge's question/answer contract.
10
+
11
+ ```javascript
12
+ import { CloudflareExtractionProvider } from '@fayegram-ai/decision-bridge/extraction';
13
+
14
+ const provider = new CloudflareExtractionProvider();
15
+ const { extraction, meta } = await provider.extract({
16
+ state: 'Invoice total: 1080 USD. Due date: 2026-11-01.',
17
+ reference_date: '2026-10-20',
18
+ fields: {
19
+ amount: { type: 'number', unit: 'USD' },
20
+ due_date: { type: 'date' },
21
+ payment_days: { type: 'estimate', min: 0, max: 90, step: 1 },
22
+ },
23
+ options: { include_quantiles: true, return_state_text: true },
24
+ });
25
+ console.log(extraction.answers.amount.value, extraction.truncated, meta.requestId);
26
+ ```
27
+
28
+ REST reads `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` only for the official
29
+ origin, or accepts explicit `apiKey` and `accountId`. Custom origins require
30
+ explicit credentials. The default model is `clairic`; the full selector
31
+ `@cf/cloudflare/clairic` is also accepted. Requested, resolved and reported model
32
+ identities remain separate. There is no model-discovery request.
33
+
34
+ ## Fields and results
35
+
36
+ | Type | Definition | Returned value |
37
+ | --- | --- | --- |
38
+ | `text` | Instructions describing a text value | String or null |
39
+ | `number` | Optional unit, integer and decimal settings | Number or null |
40
+ | `date`, `time`, `datetime` | Instructions describing the temporal value | String or null; no implicit timezone conversion |
41
+ | `duration` | Unit: seconds, minutes, hours, days, weeks, months or years | Number or null |
42
+ | `list` | Required `items`: text, number or date | Ordered list, including an empty list, or null |
43
+ | `estimate` | Required numeric or ISO-date `min` and `max`; optional `step` and `scale` | Number, date string or null, plus available distribution summaries |
44
+ | `forecast` | Prediction bounds plus optional positive `horizon` and `interval` | Native value and ordered predictive `steps`, retained as JSON |
45
+
46
+ `instructions` and `null_threshold` describe individual fields. `null_threshold`
47
+ must be greater than zero and at most one. `number` and `duration` accept boolean
48
+ `integer` and nonnegative integer `decimals`; numeric lists also accept `decimals`.
49
+ Grids support positive numeric steps or `month`/`year`;
50
+ `scale` is `linear` or `log`. Forecast intervals are `step`, `minute`, `hour`,
51
+ `day`, `week`, `month`, `quarter`, or `year`. Server ceilings remain server-owned.
52
+
53
+ The immutable envelope is `{ extraction, meta }`. The native extraction retains
54
+ all returned fields: values, guesses, confidence, `p_null`, spans, means,
55
+ medians, `p10`/`p90`, bounds probabilities, quantiles, forecast steps, `truncated`,
56
+ optional `state_text`, and usage including optional pass counts. Unknown native
57
+ response fields are retained after safe JSON validation.
58
+
59
+ A null value can coexist with a guess and span. Typed output does not establish
60
+ factual accuracy. The adapter does not recalculate predictions or token totals.
61
+ Predictive substructures with an underspecified schema remain JSON values in the
62
+ types; span offsets are preserved without assuming JavaScript slicing units.
63
+
64
+ ## Images, binding and Gateway
65
+
66
+ Provide text `state`, embedded `images`, or both. Images accept PNG/JPEG/WebP data
67
+ URLs or `{ content_type, base64 }` objects. Remote images are not supported by
68
+ this operation. The adapter checks format and container structure, while the
69
+ service owns image-count, decoded-size, dimension and context admission.
70
+
71
+ ```javascript
72
+ const provider = new CloudflareExtractionProvider({
73
+ transport: 'binding',
74
+ ai: env.AI,
75
+ gateway: { id: 'existing-gateway', skipCache: true },
76
+ });
77
+ ```
78
+
79
+ `include_quantiles` and `return_state_text` stay in the model input's `options`.
80
+ `rejectIfBusy` is an execution setting, configurable on the provider or request
81
+ options; binding dispatch places it in the third `ai.run` argument. Gateway
82
+ settings use the same routing and diagnostics as the Clef provider. A service
83
+ rejection of an execution setting is reported without dropping the setting.
84
+
85
+ ## Validation, batching and errors
86
+
87
+ `validateExtractionRequest(request, options?)` is credential-free offline
88
+ validation. `provider.validate(request)` uses the configured provider settings.
89
+ Both check structure and client resource budgets, without promising admission.
90
+
91
+ Request/response budgets default to 8 MiB each and can be configured through
92
+ 64 MiB. Requests are checked before media decoding. `extract(request, { signal })`
93
+ accepts an `AbortSignal`. Set `timeoutMs` on the provider constructor to bound
94
+ validation, dispatch and response handling; extraction call options accept only
95
+ `signal` and have no per-call timeout override.
96
+ Retries default to zero. Billing/allocation errors are not retried even when
97
+ retries are enabled; temporary eligible failures use the shared error policy.
98
+ See [errors and recovery](../reference/ERRORS.md).
99
+
100
+ `extractBatch(provider, requests, { concurrency, signal, stopOnError })` validates
101
+ all array requests before dispatch and returns ordered `{ index, ok, result }`
102
+ or `{ index, ok, error }` records. Concurrency defaults to four and is a client
103
+ execution setting, independent of any service quota.
104
+ Batch results retain each caller's `requestedModel`, including the full
105
+ `@cf/cloudflare/clairic` alias, while `resolvedModel` and dispatched input use
106
+ `clairic`, just as for individual extraction calls.
107
+
108
+ ## CLI
109
+
110
+ ```shell
111
+ decision extraction init my-extraction
112
+ decision extraction validate request.json
113
+ decision extraction run request.json --env-file .env
114
+ decision extraction batch requests.jsonl --concurrency 4 --env-file .env
115
+ ```
116
+
117
+ The namespace defaults to `cloudflare-extraction`; incompatible explicit
118
+ providers are rejected. Configuration schema version remains 1. Use the existing
119
+ Cloudflare account, credential, Gateway, timeout and retry settings. Inference
120
+ options belong in request JSON. Validation is offline and reports `fieldCount`.
121
+ Streaming JSONL batches can complete valid rows before a later row fails.
122
+
123
+ See the [runnable extraction example](../../examples/extraction.mjs), the
124
+ [official model schema](https://developers.cloudflare.com/workers-ai/models/clairic/)
125
+ and [extraction concepts](https://developers.cloudflare.com/workers-ai/concepts/extraction-models/).
@@ -20,18 +20,22 @@ In your application's directory, install the package from npm:
20
20
  npm install @fayegram-ai/decision-bridge
21
21
  ```
22
22
 
23
- You can also install a verified local archive, replacing the path below. See
24
- [packaging and release](../development/RELEASING.md) to build and verify one from
25
- a source checkout:
23
+ You can also install a verified package archive. Replace the example archive
24
+ path with your own; see [packaging and release](../development/RELEASING.md) to
25
+ build and verify one from a source checkout:
26
26
 
27
27
  ```bash
28
- npm install /path/to/fayegram-ai-decision-bridge-0.1.1.tgz
28
+ npm install /path/to/fayegram-ai-decision-bridge-0.1.3.tgz
29
29
  ```
30
30
 
31
31
  The installed package contains the SDK, declarations, command runner, examples,
32
32
  and docs. It runs without compilation; source development scripts and tests are
33
33
  excluded.
34
34
 
35
+ Check the installed version with `npm exec -- decision-bridge --version`.
36
+ Use the documentation bundled with your installed package, or select the
37
+ matching [versioned documentation](../README.md#version-availability).
38
+
35
39
  ## Configure credentials
36
40
 
37
41
  Create `.env` in your application's directory and edit it locally:
@@ -0,0 +1,167 @@
1
+ # Jev images, boxes, and long context
2
+
3
+ Jev uses TypeSafe's native `POST /v1/systemone` endpoint. The SDK defaults to
4
+ `jev-latest`; `jev-preview` and explicit version IDs are also accepted. Model
5
+ listing is account-specific and may list aliases without versioned IDs.
6
+ The returned `model` records the service-reported version independently of
7
+ `meta.requestedModel`.
8
+
9
+ ## Experimental opt-ins
10
+
11
+ Jev images and long context are disabled by default. Enable each independently
12
+ in provider configuration. TypeSafe treats these capabilities as experimental;
13
+ their accuracy, formats, and limits can change.
14
+
15
+ ```javascript
16
+ import { createBridge, JevProvider, box, noul } from '@fayegram-ai/decision-bridge';
17
+
18
+ const provider = new JevProvider({
19
+ model: 'jev-1.14.0',
20
+ dangerZone: { images: true, longContext: true },
21
+ });
22
+ const bridge = createBridge({ provider });
23
+
24
+ // imageBase64 is a caller-prepared PNG or JPEG, without a data URL prefix.
25
+ const result = await bridge.evaluate({
26
+ input: [
27
+ { type: 'text', text: 'A photograph from the kitchen camera.' },
28
+ { type: 'image', dataUrl: 'data:image/png;base64,' + imageBase64 },
29
+ ],
30
+ questions: {
31
+ present: noul('Is there a coffee mug in the image?'),
32
+ mug: box('The coffee mug in the image'),
33
+ },
34
+ });
35
+ console.log(result.answers.present.noul, result.answers.mug.box);
36
+ ```
37
+
38
+ `dangerZone.images` sends `TypeSafe-Danger-Zone-Images: true` and enables common
39
+ image input and boxes. It works with Jev 1.13 and 1.14 for images. Boxes require
40
+ `jev-preview` or a pinned Jev version of 1.14.0 or newer. Local box capability
41
+ lookup remains conservative for moving stable aliases and unknown model names;
42
+ use a supported pinned ID or `jev-preview` for boxes. Account access and hosted
43
+ model availability are still checked by the service.
44
+
45
+ `dangerZone.longContext` sends `TypeSafe-Danger-Zone-Long-Context: true`. TypeSafe
46
+ documents 262k tokens for both the per-request and per-question contexts with
47
+ this header, compared with default limits of 64k and 32k respectively. This
48
+ option works on Jev 1.13 and 1.14. It does not change the byte budget or estimate
49
+ token counts. Longer contexts are slower and less accurate.
50
+
51
+ Ordered common input becomes a state array in the same order. Text stays text;
52
+ each image becomes an asset reference. The SDK chooses references that do not
53
+ collide with the input or question text. Jev does not support image detail
54
+ controls: omit `detail`, or use `null` or `auto`. Audio/video, typed choices,
55
+ labelled scores, and safety identifiers remain unsupported by this provider.
56
+
57
+ ## Native assets in instructions and criteria
58
+
59
+ Use `provider.createDecision()` when images belong inside structured state,
60
+ instructions, or criteria. It accepts the native JSON request shape and returns
61
+ `{ decision, meta }`. Native calls share validation, transport, cancellation,
62
+ and retry policy with common calls, and bypass bridge extensions and observers.
63
+
64
+ ```javascript
65
+ const { decision, meta } = await provider.createDecision({
66
+ state: { photo: 'photo-unique-reference' },
67
+ assets: {
68
+ 'photo-unique-reference': {
69
+ type: 'image', format: 'png', data_base64: imageBase64,
70
+ },
71
+ 'example-unique-reference': {
72
+ type: 'image', format: 'jpg', data_base64: exampleBase64,
73
+ },
74
+ },
75
+ questions: {
76
+ same: noul('Does the object in `photo` match this picture: example-unique-reference?'),
77
+ target: box('The matching object in `photo`'),
78
+ },
79
+ });
80
+ console.log(decision.answers.target.box, meta.requestedModel);
81
+ ```
82
+
83
+ References are substituted in string values, including inside sentences and
84
+ nested JSON. Object keys are not substituted. Every asset must be referenced.
85
+ Whole-value references are resolved first. In longer strings, matches are
86
+ consumed from left to right; when keys overlap at the same position, the current
87
+ API uses asset-map order. A reference hidden by another match does not count as
88
+ used. Preflight rejects unused assets before dispatch. Place references in
89
+ separate values when both images are intended.
90
+ Use long unique references (for example, fresh UUIDs) that cannot accidentally
91
+ match ordinary text. Each reference is at most 1024 UTF-8 bytes; all reference
92
+ keys together are at most 65536 bytes. A file is uploaded once, but repeating
93
+ its reference repeats the image in the model's expanded input.
94
+
95
+ The bridge uses the JSON/base64 transport supported by TypeSafe. It does not
96
+ accept multipart `part` assets, read local image files, fetch URLs, resize,
97
+ rotate, or re-encode images. Base64 overhead counts toward the request limit.
98
+ Native Jev assets are separate from the common request shape; use
99
+ `createDecision` for images embedded in instructions or criteria.
100
+
101
+ ## Boxes and results
102
+
103
+ `box(instructions)` takes no criteria. Its answer has `type: 'box'`, `box`,
104
+ and native `confidence`. Coordinates are fractions measured from the top-left:
105
+ `left` and `right` scale with width; `top` and `bottom` scale with height.
106
+ All four values must be finite numbers in 0–1, with `left < right` and
107
+ `top < bottom`. Validation rejects malformed boxes rather than repairing them.
108
+ Common results containing box questions use result `meta.schemaVersion: 4`;
109
+ the CLI configuration schema version remains 1.
110
+
111
+ Each question returns one box. There is no absent-target result: a box is
112
+ returned even when the target is absent. Pair it with a presence `noul` and
113
+ choose your own presence/confidence thresholds using representative images.
114
+ Jev token usage may be `null`; that means unknown, never zero. Native confidence
115
+ and all other result checks remain enforced.
116
+
117
+ ## Images and client budgets
118
+
119
+ PNG/JPEG formats, canonical base64, positive dimensions, still-image structure
120
+ and asset reference semantics are checked locally. Service image dimensions,
121
+ decoded/processed sizes and context admission remain upstream. The bridge does
122
+ not resize, rotate or re-encode images. Prepare upright pixels in the application.
123
+
124
+ Jev requests default to a 32 MiB client serialized-JSON budget. An explicit
125
+ `maxRequestBytes` can select a budget through 64 MiB. Responses default to 8 MiB.
126
+ General JSON processing retains a 100-level depth and 200,000-node safeguard;
127
+ reference-pattern safeguards bound local regex construction. These are client
128
+ resource controls, independent of service quotas.
129
+
130
+ ## CLI
131
+
132
+ ```json
133
+ {
134
+ "schemaVersion": 1,
135
+ "provider": "jev",
136
+ "model": "jev-1.14.0",
137
+ "apiKeyEnv": "TYPESAFE_API_KEY",
138
+ "dangerZone": { "images": true, "longContext": true }
139
+ }
140
+ ```
141
+
142
+ ```shell
143
+ decision-bridge validate request.json --config decision.config.json
144
+ decision-bridge evaluate request.json --config decision.config.json --env-file .env
145
+ decision-bridge validate native.json --native --model jev-preview --jev-images
146
+ decision-bridge batch native.jsonl --native --config decision.config.json --env-file .env
147
+ ```
148
+
149
+ Common/native validation is offline and uses the same preflight as inference.
150
+ `--native` works with `init`, `validate`, `evaluate`, and `batch`. Jev keeps its
151
+ `models` command. CLI JSON/JSONL input defaults to 32 MiB per record and permits a larger explicit client budget through 64 MiB;
152
+ the actual serialized request must also fit the configured provider ceiling.
153
+
154
+ `--jev-images` / `--no-jev-images` and `--jev-long-context` /
155
+ `--no-jev-long-context` override independent fields in `dangerZone`.
156
+ `DECISION_JEV_IMAGES` and `DECISION_JEV_LONG_CONTEXT` accept exactly `true` or
157
+ `false`. Flags override environment, then JSON configuration, then defaults.
158
+ Switching providers discards Jev-specific settings; using these flags with
159
+ another provider is a configuration error.
160
+
161
+ ## Protocol sources
162
+
163
+ - [TypeSafe release announcement](https://typesafe.ai/blog/jev-1-14)
164
+ - [Images, assets, limits, and experimental header](https://docs.typesafe.ai/images)
165
+ - [Box questions and absence behavior](https://docs.typesafe.ai/primitives/box)
166
+ - [Models, aliases, and context limits](https://docs.typesafe.ai/models)
167
+ - [JavaScript SDK compatibility changes](https://docs.typesafe.ai/sdk/javascript/changelog)