@crossworks/voice-client 0.232.205 → 0.232.210
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/package.json +1 -1
- package/src/adapters/registry.ts +22 -5
- package/src/adapters/types.ts +62 -0
- package/src/providers.ts +15 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crossworks/voice-client",
|
|
3
|
-
"version": "0.232.
|
|
3
|
+
"version": "0.232.210",
|
|
4
4
|
"description": "Browser-safe surface of the voice/model layer — provider catalogue, model catalogs, audio tags, and the adapter type/metadata contract. Zero deps by design: nothing here may reach the network adapters or node builtins (the jackdaw-repo-split P0 boundary).",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./src/index.ts",
|
package/src/adapters/registry.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
import type { Provider, ProviderCapability, ProviderId } from '../providers';
|
|
16
16
|
import type {
|
|
17
17
|
ChatDispatcher,
|
|
18
|
+
DecisionDispatcher,
|
|
18
19
|
EmbeddingDispatcher,
|
|
19
20
|
ImageGenDispatcher,
|
|
20
21
|
SttDispatcher,
|
|
@@ -29,8 +30,10 @@ const STT = new Map<ProviderId, SttDispatcher>();
|
|
|
29
30
|
const VISION = new Map<ProviderId, VisionDispatcher>();
|
|
30
31
|
const IMAGE_GEN = new Map<ProviderId, ImageGenDispatcher>();
|
|
31
32
|
const EMBEDDING = new Map<ProviderId, EmbeddingDispatcher>();
|
|
33
|
+
const DECISION = new Map<ProviderId, DecisionDispatcher>();
|
|
32
34
|
|
|
33
|
-
export type WiredCapability =
|
|
35
|
+
export type WiredCapability =
|
|
36
|
+
'chat' | 'tts' | 'stt' | 'vision' | 'image_gen' | 'embedding' | 'decision';
|
|
34
37
|
|
|
35
38
|
/**
|
|
36
39
|
* STATIC mirror of which providers have a registered adapter, per capability —
|
|
@@ -70,6 +73,8 @@ export const WIRED_PROVIDERS: Record<WiredCapability, ReadonlySet<ProviderId>> =
|
|
|
70
73
|
vision: new Set<ProviderId>(['openai', 'anthropic', 'google', 'xai', 'openrouter']),
|
|
71
74
|
image_gen: new Set<ProviderId>(['openrouter', 'openai', 'xai', 'google', 'huggingface']),
|
|
72
75
|
embedding: new Set<ProviderId>(['openrouter', 'openai', 'google', 'mistral', 'cohere', 'local']),
|
|
76
|
+
// Typed decisions: only OpenRouter's alpha decisions endpoint today.
|
|
77
|
+
decision: new Set<ProviderId>(['openrouter']),
|
|
73
78
|
};
|
|
74
79
|
|
|
75
80
|
function mapFor(capability: WiredCapability): ReadonlyMap<ProviderId, unknown> {
|
|
@@ -80,6 +85,7 @@ function mapFor(capability: WiredCapability): ReadonlyMap<ProviderId, unknown> {
|
|
|
80
85
|
vision: VISION,
|
|
81
86
|
image_gen: IMAGE_GEN,
|
|
82
87
|
embedding: EMBEDDING,
|
|
88
|
+
decision: DECISION,
|
|
83
89
|
}[capability];
|
|
84
90
|
}
|
|
85
91
|
|
|
@@ -189,6 +195,19 @@ export function listEmbeddingAdapters(): EmbeddingDispatcher[] {
|
|
|
189
195
|
return Array.from(EMBEDDING.values());
|
|
190
196
|
}
|
|
191
197
|
|
|
198
|
+
// ─── Decision (typed answers, no prose) ──────────────────────────────
|
|
199
|
+
|
|
200
|
+
export function registerDecisionAdapter(adapter: DecisionDispatcher): void {
|
|
201
|
+
DECISION.set(adapter.providerId, adapter);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** No retry wrapper on purpose: a decision sits IN FRONT of a call the caller
|
|
205
|
+
* will make anyway, so a failed decision is simply "no decision" — retrying
|
|
206
|
+
* would spend the latency budget the caller was trying to save. */
|
|
207
|
+
export function getDecisionAdapter(providerId: string): DecisionDispatcher | null {
|
|
208
|
+
return DECISION.get(providerId as ProviderId) ?? null;
|
|
209
|
+
}
|
|
210
|
+
|
|
192
211
|
// ─── Capability check (used by UI to derive `wired` flag) ────────────
|
|
193
212
|
|
|
194
213
|
/**
|
|
@@ -220,10 +239,7 @@ export function findAdapterCatalogDrift(
|
|
|
220
239
|
const problems: string[] = [];
|
|
221
240
|
const catalogById = new Map(providers.map((p) => [p.id as string, p.capabilities]));
|
|
222
241
|
|
|
223
|
-
function check(
|
|
224
|
-
label: 'chat' | 'tts' | 'stt' | 'vision' | 'image_gen' | 'embedding',
|
|
225
|
-
registry: Map<ProviderId, { adapterName: string }>,
|
|
226
|
-
): void {
|
|
242
|
+
function check(label: WiredCapability, registry: Map<ProviderId, { adapterName: string }>): void {
|
|
227
243
|
for (const [providerId, adapter] of registry) {
|
|
228
244
|
const caps = catalogById.get(providerId);
|
|
229
245
|
if (!caps) {
|
|
@@ -247,6 +263,7 @@ export function findAdapterCatalogDrift(
|
|
|
247
263
|
check('vision', VISION);
|
|
248
264
|
check('image_gen', IMAGE_GEN);
|
|
249
265
|
check('embedding', EMBEDDING);
|
|
266
|
+
check('decision', DECISION);
|
|
250
267
|
|
|
251
268
|
return problems;
|
|
252
269
|
}
|
package/src/adapters/types.ts
CHANGED
|
@@ -864,3 +864,65 @@ export interface EmbeddingDispatcher extends AdapterMeta {
|
|
|
864
864
|
* AND as a last-resort if discovery errors. */
|
|
865
865
|
staticCatalog?(): readonly EmbeddingModelInfo[];
|
|
866
866
|
}
|
|
867
|
+
|
|
868
|
+
// ─── Decision (typed answers, no prose) ─────────────────────────────
|
|
869
|
+
|
|
870
|
+
/** One question for a decision model. Three shapes, mirroring TypeSafe's
|
|
871
|
+
* primitives: `choice` picks one key from `criteria`; `score` places the
|
|
872
|
+
* state on an ORDERED rubric (index 0 = lowest); `noul` is a yes/no whose
|
|
873
|
+
* answer is the probability of "yes". Write `instructions` as one direct
|
|
874
|
+
* question and name the state fields it refers to in backticks — the model
|
|
875
|
+
* reads literally, so contrastive criteria ("not for …") pay off. */
|
|
876
|
+
export type DecisionQuestion =
|
|
877
|
+
| { type: 'choice'; instructions: string; criteria: Record<string, string> }
|
|
878
|
+
| { type: 'score'; instructions: string; criteria: readonly string[] }
|
|
879
|
+
| { type: 'noul'; instructions: string; criteria?: { true?: string; false?: string } };
|
|
880
|
+
|
|
881
|
+
/** One answer. `confidence` (0-1) is the SHAPE of the distribution — 1 when
|
|
882
|
+
* all mass sits on one option, 0 when it is flat — and is the number the
|
|
883
|
+
* caller gates on; `probabilities` say WHICH options were likely. A `noul`
|
|
884
|
+
* has no separate confidence: its probability is the whole answer. */
|
|
885
|
+
export type DecisionAnswer =
|
|
886
|
+
| {
|
|
887
|
+
type: 'choice';
|
|
888
|
+
choice: string;
|
|
889
|
+
confidence: number;
|
|
890
|
+
probabilities: Record<string, number>;
|
|
891
|
+
}
|
|
892
|
+
| {
|
|
893
|
+
type: 'score';
|
|
894
|
+
/** Probability-weighted mean over the rubric indexes (fractional). */
|
|
895
|
+
score: number;
|
|
896
|
+
confidence: number;
|
|
897
|
+
probabilities: Record<string, number>;
|
|
898
|
+
}
|
|
899
|
+
| { type: 'noul'; probability: number };
|
|
900
|
+
|
|
901
|
+
export interface DecisionOptions {
|
|
902
|
+
apiKey: string;
|
|
903
|
+
model: string;
|
|
904
|
+
/** The evidence: a string, a JSON object (preferred — every part has a
|
|
905
|
+
* name the questions can point at) or an array. Text only. */
|
|
906
|
+
state: unknown;
|
|
907
|
+
questions: Record<string, DecisionQuestion>;
|
|
908
|
+
/** Ask the provider for zero-data-retention routing and no data
|
|
909
|
+
* collection. The state can hold the owner's documents. */
|
|
910
|
+
zeroDataRetention?: boolean;
|
|
911
|
+
/** Hard ceiling; the adapter aborts and throws past it. */
|
|
912
|
+
timeoutMs?: number;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
export interface DecisionResult {
|
|
916
|
+
answers: Record<string, DecisionAnswer>;
|
|
917
|
+
/** Echo of the model the provider actually served. */
|
|
918
|
+
model: string;
|
|
919
|
+
tokensIn?: number;
|
|
920
|
+
tokensOut?: number;
|
|
921
|
+
/** Provider-reported USD cost (OpenRouter `usage.cost`). */
|
|
922
|
+
reportedCostUsd?: number;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export interface DecisionDispatcher extends AdapterMeta {
|
|
926
|
+
/** One evaluation: all questions answered in one parallel pass. */
|
|
927
|
+
decide(opts: DecisionOptions): Promise<DecisionResult>;
|
|
928
|
+
}
|
package/src/providers.ts
CHANGED
|
@@ -48,7 +48,17 @@ export type ProviderId =
|
|
|
48
48
|
*
|
|
49
49
|
* When a new ai_workers kind ships, add its capability here too so
|
|
50
50
|
* the provider filter knows which providers to expose for that kind. */
|
|
51
|
-
export type ProviderCapability =
|
|
51
|
+
export type ProviderCapability =
|
|
52
|
+
| 'chat'
|
|
53
|
+
| 'embedding'
|
|
54
|
+
| 'tts'
|
|
55
|
+
| 'stt'
|
|
56
|
+
| 'vision'
|
|
57
|
+
| 'image_gen'
|
|
58
|
+
/** Typed decisions (choice / score / yes-no with probabilities, no prose)
|
|
59
|
+
* — TypeSafe Jev through OpenRouter's decisions endpoint. Not chat-shaped:
|
|
60
|
+
* its own dispatcher, its own endpoint. */
|
|
61
|
+
| 'decision';
|
|
52
62
|
|
|
53
63
|
export type Provider = {
|
|
54
64
|
id: ProviderId;
|
|
@@ -82,7 +92,7 @@ export const SUPPORTED_PROVIDERS: readonly Provider[] = [
|
|
|
82
92
|
label: 'OpenRouter',
|
|
83
93
|
description:
|
|
84
94
|
'Aggregator covering OpenAI, Anthropic, Google, Mistral, DeepSeek, and most open models behind one key — plus audio (TTS/STT) and image generation. One key powers chat, memory, voice, and images.',
|
|
85
|
-
capabilities: ['chat', 'embedding', 'vision', 'tts', 'stt', 'image_gen'],
|
|
95
|
+
capabilities: ['chat', 'embedding', 'vision', 'tts', 'stt', 'image_gen', 'decision'],
|
|
86
96
|
signupUrl: 'https://openrouter.ai/keys',
|
|
87
97
|
docsUrl: 'https://openrouter.ai/docs',
|
|
88
98
|
isAggregator: true,
|
|
@@ -259,4 +269,7 @@ export const CAPABILITY_FOR_KIND: Record<string, ProviderCapability> = {
|
|
|
259
269
|
// The suggester runs a plain chat-completion to propose one follow-up
|
|
260
270
|
// question after a turn; same 'chat' capability as the narrator.
|
|
261
271
|
suggester: 'chat',
|
|
272
|
+
// The decider is the first kind whose output is neither prose nor media: a
|
|
273
|
+
// typed-decision model behind its own endpoint, so its own capability.
|
|
274
|
+
decider: 'decision',
|
|
262
275
|
};
|