toolnexus 0.24.0 → 0.26.0
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/README.md +151 -1
- package/dist/acp.d.ts +37 -6
- package/dist/acp.js +239 -52
- package/dist/classifier.d.ts +189 -31
- package/dist/classifier.js +589 -30
- package/dist/client.d.ts +38 -8
- package/dist/client.js +102 -23
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/judge.d.ts +6 -3
- package/dist/judge.js +13 -1
- package/dist/mcp.d.ts +32 -7
- package/dist/mcp.js +125 -36
- package/dist/mcp2026/auth.d.ts +137 -0
- package/dist/mcp2026/auth.js +446 -0
- package/dist/mcp2026/client.d.ts +48 -0
- package/dist/mcp2026/client.js +160 -0
- package/dist/mcp2026/protocol.d.ts +54 -0
- package/dist/mcp2026/protocol.js +113 -0
- package/dist/mcp2026/skills.d.ts +5 -0
- package/dist/mcp2026/skills.js +25 -0
- package/dist/mcp2026/source.d.ts +86 -0
- package/dist/mcp2026/source.js +372 -0
- package/dist/mcp2026/stdio.d.ts +24 -0
- package/dist/mcp2026/stdio.js +99 -0
- package/dist/mcp2026/toolsearch.d.ts +5 -0
- package/dist/mcp2026/toolsearch.js +58 -0
- package/dist/mcphandler.d.ts +169 -0
- package/dist/mcphandler.js +1145 -0
- package/dist/mcpheader.d.ts +5 -0
- package/dist/mcpheader.js +18 -0
- package/dist/mcpserve.d.ts +24 -15
- package/dist/mcpserve.js +105 -2
- package/dist/mcpserverauth.d.ts +48 -0
- package/dist/mcpserverauth.js +203 -0
- package/dist/serve.js +7 -0
- package/dist/skill.d.ts +21 -0
- package/dist/skill.js +44 -0
- package/dist/toolkit.d.ts +20 -1
- package/dist/toolkit.js +25 -3
- package/dist/types.d.ts +22 -0
- package/package.json +4 -3
- package/src/acp.ts +258 -55
- package/src/classifier.ts +677 -46
- package/src/client.ts +130 -27
- package/src/index.ts +2 -0
- package/src/judge.ts +19 -4
- package/src/mcp.ts +162 -43
- package/src/mcp2026/auth.ts +473 -0
- package/src/mcp2026/client.ts +161 -0
- package/src/mcp2026/protocol.ts +135 -0
- package/src/mcp2026/skills.ts +22 -0
- package/src/mcp2026/source.ts +407 -0
- package/src/mcp2026/stdio.ts +102 -0
- package/src/mcp2026/toolsearch.ts +56 -0
- package/src/mcphandler.ts +1252 -0
- package/src/mcpheader.ts +19 -0
- package/src/mcpserve.ts +115 -2
- package/src/mcpserverauth.ts +216 -0
- package/src/serve.ts +7 -0
- package/src/skill.ts +50 -0
- package/src/toolkit.ts +31 -4
- package/src/types.ts +23 -0
package/dist/client.d.ts
CHANGED
|
@@ -208,6 +208,12 @@ export type MetricEvent = {
|
|
|
208
208
|
promptTokens: number;
|
|
209
209
|
completionTokens: number;
|
|
210
210
|
error?: string;
|
|
211
|
+
/** L1: how many questions were asked. */
|
|
212
|
+
questions: number;
|
|
213
|
+
/** L1: sha256 hex of `canonicalRequest(model, questions)` ("" when unencodable). */
|
|
214
|
+
questionsHash: string;
|
|
215
|
+
/** True when the decision came from the classifier cache and no request was sent. */
|
|
216
|
+
cached: boolean;
|
|
211
217
|
} | {
|
|
212
218
|
event: "classifier.warning";
|
|
213
219
|
question: string;
|
|
@@ -358,12 +364,21 @@ export interface RunResult {
|
|
|
358
364
|
export type StreamEvent = {
|
|
359
365
|
type: "text";
|
|
360
366
|
delta: string;
|
|
361
|
-
}
|
|
367
|
+
}
|
|
368
|
+
/** Model reasoning narration (e.g. an ACP agent's `agent_thought_chunk`). Never part of
|
|
369
|
+
* the answer text or the RunResult. */
|
|
370
|
+
| {
|
|
371
|
+
type: "thought";
|
|
372
|
+
delta: string;
|
|
373
|
+
via?: "acp";
|
|
374
|
+
}
|
|
375
|
+
/** `via: "acp"` marks a tool the ACP agent ran itself: reported, never executed by the loop. */
|
|
376
|
+
| {
|
|
362
377
|
type: "tool_call";
|
|
363
378
|
id: string;
|
|
364
379
|
name: string;
|
|
365
380
|
args: Record<string, unknown>;
|
|
366
|
-
via?: "call_tool";
|
|
381
|
+
via?: "call_tool" | "acp";
|
|
367
382
|
} | {
|
|
368
383
|
type: "tool_result";
|
|
369
384
|
id: string;
|
|
@@ -371,7 +386,7 @@ export type StreamEvent = {
|
|
|
371
386
|
output: string;
|
|
372
387
|
isError: boolean;
|
|
373
388
|
metadata?: Record<string, unknown>;
|
|
374
|
-
via?: "call_tool";
|
|
389
|
+
via?: "call_tool" | "acp";
|
|
375
390
|
} | {
|
|
376
391
|
type: "usage";
|
|
377
392
|
usage: Usage;
|
|
@@ -582,11 +597,22 @@ export interface InProcessResponse {
|
|
|
582
597
|
totalTokens?: number;
|
|
583
598
|
};
|
|
584
599
|
}
|
|
600
|
+
/** A streaming in-process model: `emit` each event as it happens — `text` deltas become
|
|
601
|
+
* the streamed answer as they arrive; any other event (thought, an agent's own tool_call /
|
|
602
|
+
* tool_result) goes straight to the stream consumer and is never executed by the loop.
|
|
603
|
+
* Return the whole message when done (its `toolCalls`, if any, are what the loop runs). */
|
|
604
|
+
export type InProcessGenerateStream = (request: InProcessRequest, emit: (event: StreamEvent) => void) => InProcessResponse | Promise<InProcessResponse>;
|
|
605
|
+
type InProcessGenerate = (request: InProcessRequest) => InProcessResponse | Promise<InProcessResponse>;
|
|
585
606
|
/** Options for {@link createInProcessClient}: every client option EXCEPT the three
|
|
586
|
-
* that describe a wire — `baseUrl`, `apiKey` and `style` — plus `generate
|
|
607
|
+
* that describe a wire — `baseUrl`, `apiKey` and `style` — plus `generate` and/or
|
|
608
|
+
* `generateStream` (at least one). */
|
|
587
609
|
export type InProcessOptions = Omit<ClientOptions, "baseUrl" | "apiKey" | "style" | "fetch"> & {
|
|
588
610
|
/** Your model. Receives the assembled request, returns one assistant message. */
|
|
589
|
-
generate
|
|
611
|
+
generate?: InProcessGenerate;
|
|
612
|
+
/** Your model, streaming for real. With it, `stream()` is incremental; without it a
|
|
613
|
+
* `stream()` on a plain `generate` is refused. When both are set, `generate` serves
|
|
614
|
+
* non-streaming calls; alone, it serves them too (with a no-op `emit`). */
|
|
615
|
+
generateStream?: InProcessGenerateStream;
|
|
590
616
|
};
|
|
591
617
|
/**
|
|
592
618
|
* Build a `fetch`-shaped adapter over a semantic `generate` function (ADR 0030):
|
|
@@ -596,9 +622,11 @@ export type InProcessOptions = Omit<ClientOptions, "baseUrl" | "apiKey" | "style
|
|
|
596
622
|
* or the agent runtime's `inProcess` option) goes through this ONE function, so there
|
|
597
623
|
* is no second copy of the request/response assembly to drift.
|
|
598
624
|
*
|
|
599
|
-
* Streaming is refused rather than faked — see the thrown
|
|
625
|
+
* Streaming with only a plain `generate` is refused rather than faked — see the thrown
|
|
626
|
+
* error. With `generateStream` it streams for real: each text event is written to the
|
|
627
|
+
* SSE body the moment it is emitted.
|
|
600
628
|
*/
|
|
601
|
-
export declare function createInProcessFetch(generate
|
|
629
|
+
export declare function createInProcessFetch(generate?: InProcessGenerate, generateStream?: InProcessGenerateStream): typeof fetch;
|
|
602
630
|
/**
|
|
603
631
|
* A client backed by a model running IN THIS PROCESS — no server, no socket, and no
|
|
604
632
|
* HTTP types to construct.
|
|
@@ -609,7 +637,8 @@ export declare function createInProcessFetch(generate: (request: InProcessReques
|
|
|
609
637
|
* The `fetch`-shaped adapter itself is {@link createInProcessFetch} — this function
|
|
610
638
|
* is just that adapter wired into a `Client`.
|
|
611
639
|
*
|
|
612
|
-
* Streaming is refused rather than faked
|
|
640
|
+
* Streaming is refused rather than faked for a plain `generate`; with `generateStream`
|
|
641
|
+
* it streams for real — see {@link createInProcessFetch}.
|
|
613
642
|
*/
|
|
614
643
|
export declare function createInProcessClient(opts: InProcessOptions): Client;
|
|
615
644
|
/** Stateful multi-turn conversation: each send() continues the same transcript (memory). */
|
|
@@ -625,3 +654,4 @@ export declare class Conversation {
|
|
|
625
654
|
/** Reset the conversation memory. */
|
|
626
655
|
reset(): void;
|
|
627
656
|
}
|
|
657
|
+
export {};
|
package/dist/client.js
CHANGED
|
@@ -1132,6 +1132,13 @@ export class Client {
|
|
|
1132
1132
|
if (payload === "[DONE]")
|
|
1133
1133
|
break;
|
|
1134
1134
|
const j = safeParse(payload);
|
|
1135
|
+
// A non-text event from an in-process streaming generate rides in-band so it keeps
|
|
1136
|
+
// its order and arrives as it happens; it goes straight to the consumer and is never
|
|
1137
|
+
// executed. Honoured only on the in-process sentinel URL, never from a real server.
|
|
1138
|
+
if (j && j[IN_PROCESS_SIDE_KEY] && this.opts.baseUrl === IN_PROCESS_BASE_URL) {
|
|
1139
|
+
yield j[IN_PROCESS_SIDE_KEY];
|
|
1140
|
+
continue;
|
|
1141
|
+
}
|
|
1135
1142
|
if (j?.usage)
|
|
1136
1143
|
addUsage(usage, j.usage, "openai");
|
|
1137
1144
|
const choice = j?.choices?.[0];
|
|
@@ -1336,6 +1343,9 @@ export function createClient(opts) {
|
|
|
1336
1343
|
* it must be syntactically valid. `.invalid` is reserved by RFC 2606 precisely so a
|
|
1337
1344
|
* name can never resolve. */
|
|
1338
1345
|
const IN_PROCESS_BASE_URL = "http://in-process.invalid/v1";
|
|
1346
|
+
/** The in-band SSE key that carries a non-text stream event from an in-process
|
|
1347
|
+
* streaming generate to the consumer (honoured only on {@link IN_PROCESS_BASE_URL}). */
|
|
1348
|
+
const IN_PROCESS_SIDE_KEY = "toolnexus_event";
|
|
1339
1349
|
/**
|
|
1340
1350
|
* Build a `fetch`-shaped adapter over a semantic `generate` function (ADR 0030):
|
|
1341
1351
|
* the reusable piece of {@link createInProcessClient} — assembles the wire request,
|
|
@@ -1344,14 +1354,19 @@ const IN_PROCESS_BASE_URL = "http://in-process.invalid/v1";
|
|
|
1344
1354
|
* or the agent runtime's `inProcess` option) goes through this ONE function, so there
|
|
1345
1355
|
* is no second copy of the request/response assembly to drift.
|
|
1346
1356
|
*
|
|
1347
|
-
* Streaming is refused rather than faked — see the thrown
|
|
1357
|
+
* Streaming with only a plain `generate` is refused rather than faked — see the thrown
|
|
1358
|
+
* error. With `generateStream` it streams for real: each text event is written to the
|
|
1359
|
+
* SSE body the moment it is emitted.
|
|
1348
1360
|
*/
|
|
1349
|
-
export function createInProcessFetch(generate) {
|
|
1350
|
-
if (typeof generate !== "function") {
|
|
1351
|
-
throw new Error("toolnexus: createInProcessFetch requires a `generate` function");
|
|
1361
|
+
export function createInProcessFetch(generate, generateStream) {
|
|
1362
|
+
if (typeof generate !== "function" && typeof generateStream !== "function") {
|
|
1363
|
+
throw new Error("toolnexus: createInProcessFetch requires a `generate` (or `generateStream`) function");
|
|
1352
1364
|
}
|
|
1353
1365
|
const inProcessFetch = async (_url, init) => {
|
|
1354
1366
|
const body = JSON.parse(String(init?.body ?? "{}"));
|
|
1367
|
+
const request = { messages: body.messages ?? [], tools: body.tools, model: body.model, body };
|
|
1368
|
+
if (body.stream && generateStream)
|
|
1369
|
+
return inProcessStream(generateStream, request);
|
|
1355
1370
|
// A generate() returns a whole answer, so a stream would be one chunk pretending
|
|
1356
1371
|
// to be many. Content and delta-count assertions cannot tell that from a real
|
|
1357
1372
|
// stream, so refuse instead of degrading silently.
|
|
@@ -1359,24 +1374,10 @@ export function createInProcessFetch(generate) {
|
|
|
1359
1374
|
throw new Error("toolnexus: createInProcessClient does not support streaming — `generate` returns a " +
|
|
1360
1375
|
"complete answer. Use the non-streaming run, or supply a `fetch`/transport that streams.");
|
|
1361
1376
|
}
|
|
1362
|
-
const answer = await generate({
|
|
1363
|
-
messages: body.messages ?? [],
|
|
1364
|
-
tools: body.tools,
|
|
1365
|
-
model: body.model,
|
|
1366
|
-
body,
|
|
1367
|
-
});
|
|
1377
|
+
const answer = generate ? await generate(request) : await generateStream(request, () => { });
|
|
1368
1378
|
const message = { role: "assistant" };
|
|
1369
1379
|
if (answer.toolCalls && answer.toolCalls.length > 0) {
|
|
1370
|
-
message.tool_calls = answer.toolCalls
|
|
1371
|
-
id: c.id ?? `call_${i}`,
|
|
1372
|
-
type: "function",
|
|
1373
|
-
function: {
|
|
1374
|
-
name: c.name,
|
|
1375
|
-
// A string is already encoded; anything else is encoded here so a model
|
|
1376
|
-
// author never has to think about the wire.
|
|
1377
|
-
arguments: typeof c.arguments === "string" ? c.arguments : JSON.stringify(c.arguments ?? {}),
|
|
1378
|
-
},
|
|
1379
|
-
}));
|
|
1380
|
+
message.tool_calls = wireToolCalls(answer.toolCalls, false);
|
|
1380
1381
|
}
|
|
1381
1382
|
else {
|
|
1382
1383
|
message.content = answer.content ?? "";
|
|
@@ -1395,6 +1396,80 @@ export function createInProcessFetch(generate) {
|
|
|
1395
1396
|
};
|
|
1396
1397
|
return inProcessFetch;
|
|
1397
1398
|
}
|
|
1399
|
+
function wireToolCalls(calls, indexed) {
|
|
1400
|
+
return calls.map((c, i) => ({
|
|
1401
|
+
...(indexed ? { index: i } : {}),
|
|
1402
|
+
id: c.id ?? `call_${i}`,
|
|
1403
|
+
type: "function",
|
|
1404
|
+
function: {
|
|
1405
|
+
name: c.name,
|
|
1406
|
+
// A string is already encoded; anything else is encoded here so a model
|
|
1407
|
+
// author never has to think about the wire.
|
|
1408
|
+
arguments: typeof c.arguments === "string" ? c.arguments : JSON.stringify(c.arguments ?? {}),
|
|
1409
|
+
},
|
|
1410
|
+
}));
|
|
1411
|
+
}
|
|
1412
|
+
/** Runs a streaming generate and answers with an OpenAI SSE body written AS EVENTS ARRIVE:
|
|
1413
|
+
* text → a content delta; any other event → an in-band side chunk for the consumer; then
|
|
1414
|
+
* (tool calls as one delta | the content as one delta when no text was emitted), the
|
|
1415
|
+
* finish_reason chunk, usage, and [DONE]. */
|
|
1416
|
+
function inProcessStream(generateStream, request) {
|
|
1417
|
+
const enc = new TextEncoder();
|
|
1418
|
+
let open = true;
|
|
1419
|
+
const sse = new ReadableStream({
|
|
1420
|
+
start(controller) {
|
|
1421
|
+
const chunk = (v) => {
|
|
1422
|
+
if (open)
|
|
1423
|
+
controller.enqueue(enc.encode(`data: ${JSON.stringify(v)}\n\n`));
|
|
1424
|
+
};
|
|
1425
|
+
let sawText = false;
|
|
1426
|
+
void (async () => {
|
|
1427
|
+
try {
|
|
1428
|
+
const answer = await generateStream(request, (ev) => {
|
|
1429
|
+
if (!ev || typeof ev !== "object")
|
|
1430
|
+
return;
|
|
1431
|
+
if (ev.type === "text") {
|
|
1432
|
+
if (ev.delta) {
|
|
1433
|
+
sawText = true;
|
|
1434
|
+
chunk({ choices: [{ index: 0, delta: { content: ev.delta } }] });
|
|
1435
|
+
}
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
chunk({ [IN_PROCESS_SIDE_KEY]: ev });
|
|
1439
|
+
});
|
|
1440
|
+
let finish = "stop";
|
|
1441
|
+
if (answer.toolCalls && answer.toolCalls.length > 0) {
|
|
1442
|
+
chunk({ choices: [{ index: 0, delta: { tool_calls: wireToolCalls(answer.toolCalls, true) } }] });
|
|
1443
|
+
finish = "tool_calls";
|
|
1444
|
+
}
|
|
1445
|
+
else if (!sawText && answer.content) {
|
|
1446
|
+
chunk({ choices: [{ index: 0, delta: { content: answer.content } }] });
|
|
1447
|
+
}
|
|
1448
|
+
chunk({ choices: [{ index: 0, delta: {}, finish_reason: finish }] });
|
|
1449
|
+
const u = answer.usage;
|
|
1450
|
+
if (u) {
|
|
1451
|
+
const p = u.promptTokens ?? 0, c = u.completionTokens ?? 0;
|
|
1452
|
+
chunk({ choices: [], usage: { prompt_tokens: p, completion_tokens: c, total_tokens: u.totalTokens || p + c } });
|
|
1453
|
+
}
|
|
1454
|
+
if (open)
|
|
1455
|
+
controller.enqueue(enc.encode("data: [DONE]\n\n"));
|
|
1456
|
+
open = false;
|
|
1457
|
+
controller.close();
|
|
1458
|
+
}
|
|
1459
|
+
catch (e) {
|
|
1460
|
+
if (open) {
|
|
1461
|
+
open = false;
|
|
1462
|
+
controller.error(e);
|
|
1463
|
+
}
|
|
1464
|
+
}
|
|
1465
|
+
})();
|
|
1466
|
+
},
|
|
1467
|
+
cancel() {
|
|
1468
|
+
open = false;
|
|
1469
|
+
},
|
|
1470
|
+
});
|
|
1471
|
+
return new Response(sse, { status: 200, headers: { "content-type": "text/event-stream" } });
|
|
1472
|
+
}
|
|
1398
1473
|
/**
|
|
1399
1474
|
* A client backed by a model running IN THIS PROCESS — no server, no socket, and no
|
|
1400
1475
|
* HTTP types to construct.
|
|
@@ -1405,11 +1480,15 @@ export function createInProcessFetch(generate) {
|
|
|
1405
1480
|
* The `fetch`-shaped adapter itself is {@link createInProcessFetch} — this function
|
|
1406
1481
|
* is just that adapter wired into a `Client`.
|
|
1407
1482
|
*
|
|
1408
|
-
* Streaming is refused rather than faked
|
|
1483
|
+
* Streaming is refused rather than faked for a plain `generate`; with `generateStream`
|
|
1484
|
+
* it streams for real — see {@link createInProcessFetch}.
|
|
1409
1485
|
*/
|
|
1410
1486
|
export function createInProcessClient(opts) {
|
|
1411
|
-
const { generate, ...rest } = opts;
|
|
1412
|
-
|
|
1487
|
+
const { generate, generateStream, ...rest } = opts;
|
|
1488
|
+
if (typeof generate !== "function" && typeof generateStream !== "function") {
|
|
1489
|
+
throw new Error("toolnexus: createInProcessClient requires a `generate` (or `generateStream`) function");
|
|
1490
|
+
}
|
|
1491
|
+
const inProcessFetch = createInProcessFetch(generate, generateStream);
|
|
1413
1492
|
return new Client({
|
|
1414
1493
|
// Retries default to ZERO here, unlike a network client. There is no wire, so
|
|
1415
1494
|
// there is no transient failure to ride out: whatever `generate` throws will
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export * from "./a2a.js";
|
|
|
10
10
|
export * from "./acp.js";
|
|
11
11
|
export * from "./serve.js";
|
|
12
12
|
export * from "./mcpserve.js";
|
|
13
|
+
export * from "./mcphandler.js";
|
|
14
|
+
export * from "./mcpserverauth.js";
|
|
13
15
|
export * from "./adapters.js";
|
|
14
16
|
export * from "./translate.js";
|
|
15
17
|
export * from "./toolkit.js";
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export * from "./a2a.js";
|
|
|
10
10
|
export * from "./acp.js";
|
|
11
11
|
export * from "./serve.js";
|
|
12
12
|
export * from "./mcpserve.js";
|
|
13
|
+
export * from "./mcphandler.js";
|
|
14
|
+
export * from "./mcpserverauth.js";
|
|
13
15
|
export * from "./adapters.js";
|
|
14
16
|
export * from "./translate.js";
|
|
15
17
|
export * from "./toolkit.js";
|
package/dist/judge.d.ts
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
*
|
|
8
8
|
* A gate never authorises; it only declines to decide.
|
|
9
9
|
*/
|
|
10
|
-
import { Classifier, Decision, type DecisionAnswer, type NoulCriteria, type
|
|
10
|
+
import { Classifier, Decision, type DecisionAnswer, type NoulCriteria, type AnyQuestion, type RecordedDecision } from "./classifier.js";
|
|
11
11
|
import type { Request } from "./types.js";
|
|
12
12
|
/** One named question of an ordered question list. */
|
|
13
13
|
export interface NamedQuestion {
|
|
14
14
|
name: string;
|
|
15
|
-
question:
|
|
15
|
+
question: AnyQuestion;
|
|
16
16
|
}
|
|
17
17
|
/** `noul` question with a name. Name the state field it judges in `instructions`. */
|
|
18
18
|
export declare function noul(name: string, instructions: string, criteria?: NoulCriteria): NamedQuestion;
|
|
@@ -20,8 +20,11 @@ export declare function noul(name: string, instructions: string, criteria?: Noul
|
|
|
20
20
|
export declare function choice(name: string, instructions: string, options: Record<string, string>): NamedQuestion;
|
|
21
21
|
/** `score` question with a name; `levels` is the ordered rubric. */
|
|
22
22
|
export declare function score(name: string, instructions: string, levels: string[]): NamedQuestion;
|
|
23
|
+
/** A raw question with a name: a System One type the library does not model (e.g. `box`), sent
|
|
24
|
+
* as written. Its answer decodes to a raw answer `{type, value}`. */
|
|
25
|
+
export declare function raw(name: string, type: string, instructions: string, criteria?: unknown): NamedQuestion;
|
|
23
26
|
/** Ordered list -> the §8B questions map. A duplicate name is an error naming it. */
|
|
24
|
-
export declare function questionMap(questions: readonly NamedQuestion[]): Record<string,
|
|
27
|
+
export declare function questionMap(questions: readonly NamedQuestion[]): Record<string, AnyQuestion>;
|
|
25
28
|
/** `role` next to the data's fields; a non-object value goes under `data`. */
|
|
26
29
|
export declare function State(role: string, data: unknown): Record<string, unknown>;
|
|
27
30
|
/** Sugar: `{context, message, ...extra}`. */
|
package/dist/judge.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* A gate never authorises; it only declines to decide.
|
|
9
9
|
*/
|
|
10
|
-
import { Classifier, noul as noulQ, choice as choiceQ, score as scoreQ, } from "./classifier.js";
|
|
10
|
+
import { Classifier, isRawAnswer, raw as rawQ, noul as noulQ, choice as choiceQ, score as scoreQ, } from "./classifier.js";
|
|
11
11
|
/** `noul` question with a name. Name the state field it judges in `instructions`. */
|
|
12
12
|
export function noul(name, instructions, criteria) {
|
|
13
13
|
return { name, question: noulQ(instructions, criteria) };
|
|
@@ -20,6 +20,11 @@ export function choice(name, instructions, options) {
|
|
|
20
20
|
export function score(name, instructions, levels) {
|
|
21
21
|
return { name, question: scoreQ(instructions, levels) };
|
|
22
22
|
}
|
|
23
|
+
/** A raw question with a name: a System One type the library does not model (e.g. `box`), sent
|
|
24
|
+
* as written. Its answer decodes to a raw answer `{type, value}`. */
|
|
25
|
+
export function raw(name, type, instructions, criteria) {
|
|
26
|
+
return { name, question: rawQ(type, instructions, criteria) };
|
|
27
|
+
}
|
|
23
28
|
/** Ordered list -> the §8B questions map. A duplicate name is an error naming it. */
|
|
24
29
|
export function questionMap(questions) {
|
|
25
30
|
const out = {};
|
|
@@ -47,6 +52,13 @@ function noulBand(p, b) {
|
|
|
47
52
|
return p < b.low ? "no" : p > b.high ? "yes" : "uncertain";
|
|
48
53
|
}
|
|
49
54
|
function wrap(a, b) {
|
|
55
|
+
if (isRawAnswer(a)) {
|
|
56
|
+
// An unmodelled answer type is never sure: there is no number to band.
|
|
57
|
+
const out = { ...a, sure: false };
|
|
58
|
+
Object.defineProperty(out, "value", { value: () => 0, enumerable: false });
|
|
59
|
+
Object.defineProperty(out, "pick", { value: () => "", enumerable: false });
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
50
62
|
const extra = a.type === "noul"
|
|
51
63
|
? { band: noulBand(a.noul, b) }
|
|
52
64
|
: { sure: a.confidence > b.high && !(a.type === "choice" && a.nearUniform) };
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { ElicitRequest, ElicitResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import { type JSONSchema, type Tool, type ToolHints, type McpStatus, type Request, type Answer } from "./types.js";
|
|
2
|
+
import { type JSONSchema, type Tool, type ToolHints, type ToolResult, type McpStatus, type Request, type Answer } from "./types.js";
|
|
3
3
|
import { type ContentPart } from "./content.js";
|
|
4
|
+
import type { SkillDef } from "./skill.js";
|
|
5
|
+
import { type AuthConfig } from "./mcp2026/source.js";
|
|
6
|
+
import { type TokenStore } from "./mcp2026/auth.js";
|
|
7
|
+
export { Token, MemoryTokenStore, type TokenStore } from "./mcp2026/auth.js";
|
|
8
|
+
export type { AuthConfig } from "./mcp2026/source.js";
|
|
4
9
|
/** Map an MCP `elicitation/create` request onto a §10 `Request`. */
|
|
5
10
|
export declare function elicitationToRequest(params: ElicitRequest["params"]): Request;
|
|
6
11
|
/** Map a resolved §10 `Answer` back onto an MCP `ElicitResult`. ok→accept; declined→decline; else→cancel. */
|
|
@@ -18,6 +23,10 @@ export interface LocalServer {
|
|
|
18
23
|
* builtins/skills filter (nil/empty ⇒ all; ≥1 true ⇒ allowlist; only-false ⇒ drop-list; unknown
|
|
19
24
|
* ⇒ ignore+warn). Applied to the listed defs before sanitize/prefix. */
|
|
20
25
|
tools?: Record<string, boolean>;
|
|
26
|
+
/** §2.8 lazy tool search: expose `<server>_search_tools` + `<server>_call_tool` instead of every tool. */
|
|
27
|
+
toolSearch?: boolean;
|
|
28
|
+
/** §2.8 what this server is for (shown by search_tools). */
|
|
29
|
+
description?: string;
|
|
21
30
|
}
|
|
22
31
|
export interface RemoteServer {
|
|
23
32
|
type?: "remote";
|
|
@@ -28,6 +37,11 @@ export interface RemoteServer {
|
|
|
28
37
|
timeout?: number;
|
|
29
38
|
/** §2 Gap 7. Per-server tool allowlist (see LocalServer.tools). */
|
|
30
39
|
tools?: Record<string, boolean>;
|
|
40
|
+
/** §2.8 lazy tool search (see LocalServer.toolSearch). */
|
|
41
|
+
toolSearch?: boolean;
|
|
42
|
+
description?: string;
|
|
43
|
+
/** §2A OAuth 2.1 client settings. Absent ⇒ a 401 still triggers the flow (CIMD if the AS supports it). */
|
|
44
|
+
auth?: AuthConfig;
|
|
31
45
|
}
|
|
32
46
|
export type ServerConfig = LocalServer | RemoteServer;
|
|
33
47
|
export type McpConfig = Record<string, ServerConfig>;
|
|
@@ -46,6 +60,8 @@ export declare function expandEnvHeaders(headers?: Record<string, string>): Reco
|
|
|
46
60
|
* takes it there.
|
|
47
61
|
*/
|
|
48
62
|
export declare function mcpContentToParts(content: unknown): ContentPart[] | undefined;
|
|
63
|
+
/** §2 `tools/call` result → ToolResult (shared by the 2026 path and the frozen fallback). */
|
|
64
|
+
export declare function mapCallToolResult(result: any, server: string): ToolResult;
|
|
49
65
|
export interface McpSource {
|
|
50
66
|
tools: Tool[];
|
|
51
67
|
status: Record<string, McpStatus>;
|
|
@@ -56,6 +72,8 @@ export interface McpSource {
|
|
|
56
72
|
* source is closed.
|
|
57
73
|
*/
|
|
58
74
|
resourceTools(): Tool[];
|
|
75
|
+
/** §2.7 skills served by 2026 servers (skills extension); the toolkit adds them to the `skill` tool. */
|
|
76
|
+
skills: SkillDef[];
|
|
59
77
|
}
|
|
60
78
|
/** One server's outcome, reported by `loadMcp`'s `onServer` the moment that server finishes. */
|
|
61
79
|
export interface McpServerResult {
|
|
@@ -75,12 +93,21 @@ export declare function mcpHints(a: {
|
|
|
75
93
|
destructiveHint?: boolean;
|
|
76
94
|
openWorldHint?: boolean;
|
|
77
95
|
} | undefined): ToolHints | undefined;
|
|
96
|
+
/** Options shared by loadMcp / listMcpTools for the 2026 path and OAuth (§2A.1a). */
|
|
97
|
+
export interface McpLoadOptions {
|
|
98
|
+
waitFor?: (request: Request) => Promise<Answer>;
|
|
99
|
+
signal?: AbortSignal;
|
|
100
|
+
/** Where OAuth tokens live (default: in memory, per load). */
|
|
101
|
+
tokenStore?: TokenStore;
|
|
102
|
+
/** How `auto` OAuth mode opens the authorization URL (default: the OS opener). */
|
|
103
|
+
openUrl?: (url: string) => unknown | Promise<unknown>;
|
|
104
|
+
/** Final exposed names to drop; on a tool-search server they are also hidden from search/call. */
|
|
105
|
+
disableTools?: string[];
|
|
106
|
+
}
|
|
78
107
|
/** Connect to every enabled server, list + convert tools. Failures are isolated.
|
|
79
108
|
* §2 Gap 3: an optional `signal` bounds each connect/list by the server timeout and aborts the
|
|
80
109
|
* whole load promptly on parent cancellation. */
|
|
81
|
-
export declare function loadMcp(input: string | object, opts?: {
|
|
82
|
-
waitFor?: (request: Request) => Promise<Answer>;
|
|
83
|
-
signal?: AbortSignal;
|
|
110
|
+
export declare function loadMcp(input: string | object, opts?: McpLoadOptions & {
|
|
84
111
|
/**
|
|
85
112
|
* Called once per server the moment it is connected, failed or found disabled (SPEC §4C),
|
|
86
113
|
* so a host can register a fast server's tools while a slow one is still connecting.
|
|
@@ -105,6 +132,4 @@ export interface McpInventory {
|
|
|
105
132
|
* §2 Gap 6. Connect to every enabled server, list tool definitions, and DISCONNECT before
|
|
106
133
|
* returning — no toolkit, no execute wiring, nothing left running. Failure isolation as in loadMcp.
|
|
107
134
|
*/
|
|
108
|
-
export declare function listMcpTools(input: string | object, opts?:
|
|
109
|
-
signal?: AbortSignal;
|
|
110
|
-
}): Promise<McpInventory>;
|
|
135
|
+
export declare function listMcpTools(input: string | object, opts?: McpLoadOptions): Promise<McpInventory>;
|