@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.
- package/CHANGELOG.md +19 -0
- package/CONTRIBUTING.md +5 -3
- package/README.md +24 -8
- package/SECURITY.md +18 -11
- package/docs/README.md +17 -4
- package/docs/development/ARCHITECTURE.md +32 -5
- 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 +5 -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 +13 -20
- 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 +48 -10
- package/docs/reference/CONFIGURATION.md +31 -8
- package/docs/reference/ERRORS.md +41 -12
- package/docs/reference/PROVIDERS.md +19 -6
- package/docs/reference/SDK.md +62 -24
- package/docs/reference/SOURCES.md +7 -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 +88 -11
- package/src/bridge.mjs +9 -6
- package/src/capabilities.mjs +28 -4
- package/src/cli/config-validation.mjs +4 -4
- package/src/cli/config.mjs +4 -2
- package/src/cli/initialize.mjs +8 -4
- package/src/cli/live.mjs +63 -0
- package/src/cli/main.mjs +35 -12
- 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 +18 -4
- package/src/input.mjs +21 -3
- 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/providers/cloudflare-images.mjs +3 -9
- 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/jev-images.mjs +2 -8
- package/src/providers/jev-preflight.mjs +1 -0
- package/src/providers/jev-profile.mjs +2 -2
- 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/response-transport.mjs +84 -17
- package/src/validation.mjs +26 -14
- package/src/version.mjs +1 -1
package/src/validation.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { requireCondition as check } from './errors.mjs';
|
|
2
|
-
import {
|
|
2
|
+
import { validateOrderedInput } from './input.mjs';
|
|
3
|
+
import { validateCacheOptions, validateCacheBreakpoint, validateDecisionInput } from './providers/decisions-input.mjs';
|
|
3
4
|
import { validateProbabilitySum, validateResultOptions } from './probabilities.mjs';
|
|
4
5
|
|
|
5
6
|
const own = (value, key) => Object.hasOwn(value, key);
|
|
@@ -81,14 +82,25 @@ function allowedKeys(value, expected, label, code = 'VALIDATION_ERROR') {
|
|
|
81
82
|
export function validateRequest(input, defaultModel) {
|
|
82
83
|
const request = cloneJson(input, 'request');
|
|
83
84
|
check(isRecord(request), 'request must be an object.');
|
|
84
|
-
allowedKeys(request, ['state', 'input', 'questions', 'model', 'safetyIdentifier'
|
|
85
|
-
|
|
85
|
+
allowedKeys(request, ['state', 'input', 'conversation', 'questions', 'model', 'safetyIdentifier',
|
|
86
|
+
'promptCacheKey', 'promptCacheOptions'], 'request');
|
|
87
|
+
check(['state', 'input', 'conversation'].filter(key => own(request, key)).length === 1,
|
|
88
|
+
'Provide exactly one of state, input or conversation.');
|
|
86
89
|
if (own(request, 'state')) check(request.state !== null && isEntry(request.state),
|
|
87
90
|
'state must be text, a JSON object, or an array.');
|
|
88
|
-
else
|
|
91
|
+
else if (own(request, 'conversation')) {
|
|
92
|
+
check(Array.isArray(request.conversation), 'conversation must be an ordered item array.');
|
|
93
|
+
validateDecisionInput(request.conversation);
|
|
94
|
+
} else {
|
|
95
|
+
validateOrderedInput(request.input);
|
|
96
|
+
for (const part of request.input) validateCacheBreakpoint(part.promptCacheBreakpoint);
|
|
97
|
+
}
|
|
98
|
+
if (own(request, 'promptCacheKey')) check(request.promptCacheKey === null || typeof request.promptCacheKey === 'string',
|
|
99
|
+
'promptCacheKey must be text or null.');
|
|
100
|
+
validateCacheOptions(request.promptCacheOptions);
|
|
89
101
|
if (own(request, 'safetyIdentifier')) check(request.safetyIdentifier === null ||
|
|
90
|
-
|
|
91
|
-
'safetyIdentifier must be a string
|
|
102
|
+
typeof request.safetyIdentifier === 'string',
|
|
103
|
+
'safetyIdentifier must be a string or null.');
|
|
92
104
|
if (own(request, 'model')) check(nonempty(request.model), 'model must be a nonempty string when provided.');
|
|
93
105
|
const model = own(request, 'model') ? request.model : defaultModel;
|
|
94
106
|
check(nonempty(model), 'model must be a nonempty string.');
|
|
@@ -125,14 +137,14 @@ export function validateRequest(input, defaultModel) {
|
|
|
125
137
|
if (own(level, 'description')) check(level.description !== null && isEntry(level.description), 'Invalid level description.');
|
|
126
138
|
}
|
|
127
139
|
} else if (q.type === 'choice') {
|
|
128
|
-
check(isRecord(q.criteria) && Object.keys(q.criteria).length > 0
|
|
129
|
-
'choice requires a criteria map
|
|
140
|
+
check(isRecord(q.criteria) && Object.keys(q.criteria).length > 0,
|
|
141
|
+
'choice requires a nonempty criteria map.');
|
|
130
142
|
for (const [label, description] of Object.entries(q.criteria)) {
|
|
131
143
|
check(nonempty(label) && isEntry(description), 'choice criteria require labels and text, structured JSON, or null descriptions.');
|
|
132
144
|
}
|
|
133
145
|
} else if (q.type === 'score') {
|
|
134
|
-
check(Array.isArray(q.criteria) && q.criteria.length >= 2
|
|
135
|
-
'score requires
|
|
146
|
+
check(Array.isArray(q.criteria) && q.criteria.length >= 2,
|
|
147
|
+
'score requires at least two ordered criteria.');
|
|
136
148
|
check(q.criteria.every(value => value !== null && isEntry(value)),
|
|
137
149
|
'score descriptions must be text or structured JSON, not null.');
|
|
138
150
|
} else if (own(q, 'criteria')) {
|
|
@@ -173,9 +185,9 @@ export function validateResult(input, questions, options = {}) {
|
|
|
173
185
|
q.options.every(option => isRecord(option)), 'Typed choice requires nonempty option objects.');
|
|
174
186
|
if (q.type === 'score' && own(q, 'levels')) check(Array.isArray(q.levels) && q.levels.length >= 2 &&
|
|
175
187
|
q.levels.every(level => isRecord(level) && typeof level.label === 'string'), 'Labelled score requires valid levels.');
|
|
176
|
-
if (q.type === 'choice' && !own(q, 'options')) check(isRecord(q.criteria) && Object.keys(q.criteria).length > 0
|
|
177
|
-
|
|
178
|
-
if (q.type === 'score' && !own(q, 'levels')) check(Array.isArray(q.criteria) && q.criteria.length >= 2
|
|
188
|
+
if (q.type === 'choice' && !own(q, 'options')) check(isRecord(q.criteria) && Object.keys(q.criteria).length > 0,
|
|
189
|
+
'choice requires nonempty criteria.');
|
|
190
|
+
if (q.type === 'score' && !own(q, 'levels')) check(Array.isArray(q.criteria) && q.criteria.length >= 2, 'score requires at least two levels.');
|
|
179
191
|
const answer = result.answers[id];
|
|
180
192
|
check(isRecord(answer) && answer.type === q.type, 'Answer type must match its question.', 'INVALID_RESPONSE');
|
|
181
193
|
allowedKeys(answer, q.type === 'box' ? ['type', 'box', 'confidence'] : q.type === 'noul' ? ['type', 'noul'] : q.type === 'choice'
|
|
@@ -202,7 +214,7 @@ export function validateResult(input, questions, options = {}) {
|
|
|
202
214
|
if (q.type === 'choice') {
|
|
203
215
|
check(typeof answer.choice === 'string' && labels.includes(answer.choice), 'choice must be a supplied option.', 'INVALID_RESPONSE');
|
|
204
216
|
const selected = answer.probabilities[answer.choice];
|
|
205
|
-
check(selected + 1e-6 >=
|
|
217
|
+
check(selected + 1e-6 >= Object.values(answer.probabilities).reduce((max, value) => Math.max(max, value), 0),
|
|
206
218
|
'choice must select a highest-probability option.', 'INVALID_RESPONSE');
|
|
207
219
|
} else {
|
|
208
220
|
exactKeys(answer.legend, labels, 'legend', 'INVALID_RESPONSE');
|
package/src/version.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Keep in sync with package.json; scripts/check.mjs verifies the release version. */
|
|
2
|
-
export const VERSION = '0.1.
|
|
2
|
+
export const VERSION = '0.1.3';
|