@niscorp/signal 0.1.1 → 0.1.4
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 +53 -0
- package/DOCS.md +58 -7
- package/dist/index.cjs +11 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -58
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -50,17 +50,11 @@ var providerRegistry = {
|
|
|
50
50
|
endpoint: {
|
|
51
51
|
nativeTools: true,
|
|
52
52
|
nativeJsonMode: true,
|
|
53
|
-
// Groq validates tool args server-side (tool_use_failed 400s).
|
|
54
53
|
validatesToolArgs: true,
|
|
55
54
|
supportsEmbedding: false
|
|
56
55
|
},
|
|
57
56
|
adapter: "openai-compatible",
|
|
58
|
-
// tool_use_failed / json_validate_failed 400s carry the model's
|
|
59
|
-
// attempt in failed_generation — recover and route it.
|
|
60
57
|
wire: ["failed-generation"],
|
|
61
|
-
// Reasoning models stream their trace only when asked to parse it out;
|
|
62
|
-
// `reasoning_format` is rejected on the non-reasoning ones, which is why
|
|
63
|
-
// this is opt-in (see reasoningRequest above).
|
|
64
58
|
reasoningRequest: { reasoning_format: "parsed" }
|
|
65
59
|
},
|
|
66
60
|
openai: {
|
|
@@ -75,8 +69,6 @@ var providerRegistry = {
|
|
|
75
69
|
supportsEmbedding: true
|
|
76
70
|
},
|
|
77
71
|
adapter: "openai-compatible",
|
|
78
|
-
// 4o-era models occasionally emit JSONL where one value was asked
|
|
79
|
-
// for; the acceptance gate decides, so this can never misfire.
|
|
80
72
|
wire: ["jsonl-lines"]
|
|
81
73
|
},
|
|
82
74
|
openrouter: {
|
|
@@ -91,8 +83,6 @@ var providerRegistry = {
|
|
|
91
83
|
supportsEmbedding: false
|
|
92
84
|
},
|
|
93
85
|
adapter: "openai-compatible",
|
|
94
|
-
// OpenRouter unifies reasoning across the models it routes; `enabled` turns
|
|
95
|
-
// the trace on for those that have one and is ignored by those that don't.
|
|
96
86
|
reasoningRequest: { reasoning: { enabled: true } }
|
|
97
87
|
},
|
|
98
88
|
anthropic: {
|
|
@@ -125,97 +115,78 @@ var providerRegistry = {
|
|
|
125
115
|
id: "typesafe",
|
|
126
116
|
baseUrl: "https://api.typesafe.ai/v1",
|
|
127
117
|
envKey: "TYPESAFE_API_KEY",
|
|
128
|
-
// The moving alias. A caller that records calibration against a model pins
|
|
129
|
-
// a version (`jev-1.13.0`) with `.model()`.
|
|
130
118
|
defaultModel: "jev-latest",
|
|
131
119
|
adapter: "systemone"
|
|
132
120
|
}
|
|
133
121
|
};
|
|
134
122
|
var modelRegistry = {
|
|
135
|
-
// ── groq ──
|
|
136
123
|
"groq/qwen/qwen3.8-27b": {
|
|
137
124
|
capabilities: { nativeJsonSchema: false, toolsWithStructuredOutput: false, manglesNestedToolArgs: true, multimodal: true },
|
|
138
|
-
// nested: 3 of 20 trials failed
|
|
139
125
|
reasoningEfforts: ["none", "default", "low", "medium", "high"],
|
|
140
126
|
verified: "2026-09-24"
|
|
141
127
|
},
|
|
142
128
|
"groq/openai/gpt-oss-120b": {
|
|
143
129
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: false, manglesNestedToolArgs: true, multimodal: false },
|
|
144
|
-
// nested: 1 of 20 trials failed
|
|
145
130
|
reasoningEfforts: ["low", "medium", "high"],
|
|
146
131
|
verified: "2026-09-24"
|
|
147
132
|
},
|
|
148
133
|
"groq/openai/gpt-oss-20b": {
|
|
149
134
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: false, manglesNestedToolArgs: true, multimodal: false },
|
|
150
|
-
// nested: 6 of 20 trials failed
|
|
151
135
|
reasoningEfforts: ["low", "medium", "high"],
|
|
152
136
|
verified: "2026-09-24"
|
|
153
137
|
},
|
|
154
|
-
// ── openai ──
|
|
155
138
|
"openai/gpt-4o": {
|
|
156
139
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
157
|
-
// nested: 0 of 20 trials failed
|
|
158
140
|
reasoningEfforts: [],
|
|
159
141
|
verified: "2026-09-24"
|
|
160
142
|
},
|
|
161
143
|
"openai/gpt-4o-mini": {
|
|
162
144
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
163
|
-
// nested: 0 of 20 trials failed
|
|
164
145
|
reasoningEfforts: [],
|
|
165
146
|
verified: "2026-09-24"
|
|
166
147
|
},
|
|
167
148
|
"openai/gpt-4.1-mini": {
|
|
168
149
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
169
|
-
// nested: 0 of 20 trials failed
|
|
170
150
|
reasoningEfforts: [],
|
|
171
151
|
verified: "2026-09-24"
|
|
172
152
|
},
|
|
173
|
-
// ── openrouter ──
|
|
174
153
|
"openrouter/qwen/qwen3.8-27b": {
|
|
175
154
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
176
|
-
// nested: 0 of 20 trials failed
|
|
177
155
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
178
156
|
verified: "2026-09-24"
|
|
179
157
|
},
|
|
180
158
|
"openrouter/openai/gpt-4o": {
|
|
181
159
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
182
|
-
// nested: 0 of 20 trials failed
|
|
183
160
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
184
161
|
verified: "2026-09-24"
|
|
185
162
|
},
|
|
186
163
|
"openrouter/openai/gpt-4o-mini": {
|
|
187
164
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
188
|
-
// nested: 0 of 20 trials failed
|
|
189
165
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
190
166
|
verified: "2026-09-24"
|
|
191
167
|
},
|
|
192
168
|
"openrouter/openai/gpt-oss-120b": {
|
|
193
169
|
capabilities: { nativeJsonSchema: false, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: false },
|
|
194
|
-
// nested: 0 of 20 trials failed
|
|
195
170
|
reasoningEfforts: ["minimal", "low", "medium", "high", "xhigh", "max"],
|
|
196
171
|
verified: "2026-09-24"
|
|
197
172
|
},
|
|
198
173
|
"openrouter/z-ai/glm-5.2": {
|
|
199
174
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: true, multimodal: false },
|
|
200
|
-
// nested: 1 of 20 trials failed
|
|
201
175
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
202
176
|
verified: "2026-09-24"
|
|
203
177
|
},
|
|
204
178
|
"openrouter/openai/gpt-5.6-luna": {
|
|
205
179
|
capabilities: { nativeJsonSchema: true, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: true },
|
|
206
|
-
// nested: 0 of 20 trials failed
|
|
207
180
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
208
181
|
verified: "2026-09-24"
|
|
209
182
|
},
|
|
210
183
|
"openrouter/openai/gpt-oss-20b": {
|
|
211
184
|
capabilities: { nativeJsonSchema: false, toolsWithStructuredOutput: true, manglesNestedToolArgs: false, multimodal: false },
|
|
212
|
-
// nested: 0 of 20 trials failed
|
|
213
185
|
reasoningEfforts: ["minimal", "low", "medium", "high", "xhigh", "max"],
|
|
214
186
|
verified: "2026-09-24"
|
|
215
187
|
},
|
|
216
188
|
"openrouter/meta-llama/llama-3.3-70b-instruct": {
|
|
217
189
|
capabilities: { nativeJsonSchema: false, toolsWithStructuredOutput: true, manglesNestedToolArgs: true, multimodal: false },
|
|
218
|
-
// nested: 9 of 20 trials failed
|
|
219
190
|
reasoningEfforts: ["none", "minimal", "low", "medium", "high", "xhigh", "max"],
|
|
220
191
|
verified: "2026-09-24"
|
|
221
192
|
}
|
|
@@ -379,9 +350,8 @@ var createOpenAICompatibleAdapter = async (config) => {
|
|
|
379
350
|
async function* chatStream(request, options) {
|
|
380
351
|
const streamParams = {
|
|
381
352
|
...buildParams(request),
|
|
382
|
-
//
|
|
383
|
-
//
|
|
384
|
-
// the non-stream `chat` path never sees these, so its content is unmoved.
|
|
353
|
+
// Only when the caller set reasoningEffort: Groq answers `reasoning_format` with a 400
|
|
354
|
+
// on its non-reasoning models.
|
|
385
355
|
...request.options?.reasoningEffort !== void 0 && config.reasoningRequest !== void 0 ? config.reasoningRequest : {},
|
|
386
356
|
stream: true,
|
|
387
357
|
stream_options: { include_usage: true }
|
|
@@ -707,8 +677,6 @@ async function* executeStepStream(config) {
|
|
|
707
677
|
contentBuffer += delta.text;
|
|
708
678
|
yield { type: "text", text: delta.text };
|
|
709
679
|
break;
|
|
710
|
-
// Reasoning is passed straight through and deliberately NOT added to
|
|
711
|
-
// contentBuffer: it is the model thinking, not its answer.
|
|
712
680
|
case "reasoning":
|
|
713
681
|
yield { type: "reasoning", text: delta.text };
|
|
714
682
|
break;
|
|
@@ -1387,10 +1355,7 @@ var buildMessages = (config, input) => {
|
|
|
1387
1355
|
var recoveredStepResult = (recovered, routed, raw, sent) => ({
|
|
1388
1356
|
content: "",
|
|
1389
1357
|
toolCalls: routed.outcome.kind === "tool_calls" ? routed.outcome.calls : [],
|
|
1390
|
-
//
|
|
1391
|
-
// billed for it — and the 400 body carries none. The prompt is known exactly
|
|
1392
|
-
// and the model's attempt is in the rejection, so this is countable rather
|
|
1393
|
-
// than lost. Marked unreported, because it is a reckoning.
|
|
1358
|
+
// The provider bills a rejected generation and its 400 carries no usage.
|
|
1394
1359
|
usage: estimateUsage(sent, recovered.rejection.argsText, routed.outcome.kind === "tool_calls" ? routed.outcome.calls : []),
|
|
1395
1360
|
finishReason: "error_recovered",
|
|
1396
1361
|
raw,
|
|
@@ -1445,10 +1410,6 @@ var createSignalFromConfig = (config) => {
|
|
|
1445
1410
|
...providerTools && { tools: providerTools },
|
|
1446
1411
|
...request.toolChoice !== void 0 && { toolChoice: request.toolChoice },
|
|
1447
1412
|
...request.responseFormat !== void 0 && { responseFormat: request.responseFormat },
|
|
1448
|
-
// The client's own options are the floor; a request may override them
|
|
1449
|
-
// field by field. `complete`/`stream` already run on config.options —
|
|
1450
|
-
// step used to drop them, so a configured client behaved differently
|
|
1451
|
-
// depending on which door the caller came through.
|
|
1452
1413
|
...(config.options !== void 0 || request.options !== void 0) && {
|
|
1453
1414
|
options: { ...config.options, ...request.options }
|
|
1454
1415
|
}
|
|
@@ -1483,8 +1444,7 @@ var createSignalFromConfig = (config) => {
|
|
|
1483
1444
|
const result = {
|
|
1484
1445
|
content: response.content,
|
|
1485
1446
|
toolCalls,
|
|
1486
|
-
//
|
|
1487
|
-
// zero rather than a missing frame.
|
|
1447
|
+
// A non-streaming body always carries usage, so a zero here is a reported zero.
|
|
1488
1448
|
usage: { ...response.usage, reported: true },
|
|
1489
1449
|
finishReason: response.finishReason,
|
|
1490
1450
|
raw: response.raw
|
|
@@ -1500,9 +1460,9 @@ var createSignalFromConfig = (config) => {
|
|
|
1500
1460
|
});
|
|
1501
1461
|
return { ...result, outcome: routed.outcome, wire: routed.wire };
|
|
1502
1462
|
};
|
|
1503
|
-
const
|
|
1463
|
+
const stepStreamAs = (verb) => (request, streamOptions) => {
|
|
1504
1464
|
const run = async function* () {
|
|
1505
|
-
const adapter = await getChatAdapter(
|
|
1465
|
+
const adapter = await getChatAdapter(verb);
|
|
1506
1466
|
const resolved = resolveProvider(config);
|
|
1507
1467
|
const declared = new Set((request.tools ?? []).map((tool) => tool.name));
|
|
1508
1468
|
const merged = config.options !== void 0 || request.options !== void 0 ? { ...request, options: { ...config.options, ...request.options } } : request;
|
|
@@ -1542,6 +1502,7 @@ var createSignalFromConfig = (config) => {
|
|
|
1542
1502
|
};
|
|
1543
1503
|
return run();
|
|
1544
1504
|
};
|
|
1505
|
+
const stepStream = stepStreamAs("stepStream");
|
|
1545
1506
|
const decideCalibrated = async (adapter, model, request, started) => {
|
|
1546
1507
|
const response = await adapter.decide(
|
|
1547
1508
|
{ model, state: request.state, questions: request.questions },
|
|
@@ -1579,8 +1540,7 @@ var createSignalFromConfig = (config) => {
|
|
|
1579
1540
|
decisions: acceptUncalibrated(request.questions, result.response, result.meta.provider.raw),
|
|
1580
1541
|
meta: {
|
|
1581
1542
|
model: result.meta.model,
|
|
1582
|
-
// complete()
|
|
1583
|
-
// and does not say which, so this total cannot be vouched for as measured.
|
|
1543
|
+
// complete() adds reported usage to estimated usage and does not say which.
|
|
1584
1544
|
usage: { ...result.meta.usage, reported: false },
|
|
1585
1545
|
durationMs: Date.now() - started,
|
|
1586
1546
|
provider: { raw: result.meta.provider.raw }
|
|
@@ -1588,7 +1548,6 @@ var createSignalFromConfig = (config) => {
|
|
|
1588
1548
|
};
|
|
1589
1549
|
};
|
|
1590
1550
|
return {
|
|
1591
|
-
// Builder methods
|
|
1592
1551
|
apiKey: (key) => fork({ apiKey: key }),
|
|
1593
1552
|
model: (m) => fork({ model: m }),
|
|
1594
1553
|
systemPrompt: (prompt) => fork({ systemPrompt: prompt }),
|
|
@@ -1618,7 +1577,6 @@ var createSignalFromConfig = (config) => {
|
|
|
1618
1577
|
modelKnown: false
|
|
1619
1578
|
};
|
|
1620
1579
|
},
|
|
1621
|
-
// Execution — thin wrappers over the step core (src/complete.ts).
|
|
1622
1580
|
complete: async (input) => runComplete(
|
|
1623
1581
|
{
|
|
1624
1582
|
messages: buildMessages(config, input),
|
|
@@ -1629,7 +1587,7 @@ var createSignalFromConfig = (config) => {
|
|
|
1629
1587
|
onRetry: config.onRetry,
|
|
1630
1588
|
onToolCall: config.onToolCall
|
|
1631
1589
|
},
|
|
1632
|
-
{ stepStream, model: resolveProvider(config).model, capabilities: resolveCapabilities(config) }
|
|
1590
|
+
{ stepStream: stepStreamAs("complete"), model: resolveProvider(config).model, capabilities: resolveCapabilities(config) }
|
|
1633
1591
|
),
|
|
1634
1592
|
stream: (input, streamOptions) => runStream(
|
|
1635
1593
|
{
|
|
@@ -1642,12 +1600,10 @@ var createSignalFromConfig = (config) => {
|
|
|
1642
1600
|
onRetry: config.onRetry,
|
|
1643
1601
|
onToolCall: config.onToolCall
|
|
1644
1602
|
},
|
|
1645
|
-
{ stepStream, model: resolveProvider(config).model, capabilities: resolveCapabilities(config) }
|
|
1603
|
+
{ stepStream: stepStreamAs("stream"), model: resolveProvider(config).model, capabilities: resolveCapabilities(config) }
|
|
1646
1604
|
),
|
|
1647
|
-
// ─── Low-level primitives — the execution core itself ────
|
|
1648
1605
|
step,
|
|
1649
1606
|
stepStream,
|
|
1650
|
-
// ─── Embedding ────────────────────────────────────────────
|
|
1651
1607
|
embed: (async (input, options) => {
|
|
1652
1608
|
const adapter = await getChatAdapter("embed");
|
|
1653
1609
|
if (!adapter.embed) {
|
|
@@ -1667,7 +1623,6 @@ var createSignalFromConfig = (config) => {
|
|
|
1667
1623
|
}
|
|
1668
1624
|
return response.embeddings;
|
|
1669
1625
|
}),
|
|
1670
|
-
// ─── Decisions ────────────────────────────────────────────
|
|
1671
1626
|
decide: async (request) => {
|
|
1672
1627
|
assertQuestions(request.questions);
|
|
1673
1628
|
const started = Date.now();
|
|
@@ -1675,7 +1630,6 @@ var createSignalFromConfig = (config) => {
|
|
|
1675
1630
|
const model = resolveProvider(config).model;
|
|
1676
1631
|
return adapter.kind === "decisions" ? decideCalibrated(adapter, model, request, started) : decideEmulated(model, request, started);
|
|
1677
1632
|
},
|
|
1678
|
-
// ─── Low-level: token counting (heuristic) ───────────────
|
|
1679
1633
|
count: async (input) => {
|
|
1680
1634
|
const CHARS_PER_TOKEN2 = 4;
|
|
1681
1635
|
if (typeof input === "string") {
|
|
@@ -1783,8 +1737,7 @@ var resolveTransport = (spec, caps) => {
|
|
|
1783
1737
|
responseMode: spec.responseMode,
|
|
1784
1738
|
responseFormat: {
|
|
1785
1739
|
type: "json_schema",
|
|
1786
|
-
//
|
|
1787
|
-
// keywords; non-strict still constrains and never hard-fails.
|
|
1740
|
+
// Strict mode rejects open records and several keywords; non-strict still constrains.
|
|
1788
1741
|
jsonSchema: { name: "envelope", strict: false, schema: serialized }
|
|
1789
1742
|
},
|
|
1790
1743
|
injectSchemaDoc: injectSchemaDoc2,
|