theorum 0.1.15 → 1.0.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 +177 -90
- package/esm/mod.d.ts +21 -11
- package/esm/mod.js +15 -8
- package/esm/src/cli/commands/bench.js +6 -3
- package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
- package/esm/src/cli/commands/fuzz-canary.js +195 -0
- package/esm/src/cli/commands/fuzz-guardrails.d.ts +3 -5
- package/esm/src/cli/commands/fuzz-guardrails.js +4 -581
- package/esm/src/cli/commands/profile.js +25 -14
- package/esm/src/cli/commands/run.d.ts +3 -0
- package/esm/src/cli/commands/run.js +22 -30
- package/esm/src/cli/commands/test.d.ts +10 -1
- package/esm/src/cli/commands/test.js +31 -31
- package/esm/src/cli/event-log.d.ts +19 -0
- package/esm/src/cli/event-log.js +147 -0
- package/esm/src/cli/index.js +45 -11
- package/esm/src/cli/matrix/synthesizer.d.ts +7 -9
- package/esm/src/cli/matrix/synthesizer.js +32 -106
- package/esm/src/guardrails/canary-gate.d.ts +20 -0
- package/esm/src/guardrails/canary-gate.js +31 -0
- package/esm/src/guardrails/canary.d.ts +26 -0
- package/esm/src/guardrails/canary.js +139 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +16 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.js +151 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.d.ts +11 -0
- package/esm/src/guardrails/corpus/fuzz-inbound.js +216 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +124 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
- package/esm/src/guardrails/corpus/live-attacks.js +232 -0
- package/esm/src/guardrails/corpus/mod.d.ts +13 -0
- package/esm/src/guardrails/corpus/mod.js +11 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +16 -0
- package/esm/src/guardrails/corpus/secrets.js +16 -0
- package/esm/src/guardrails/corpus/strings.d.ts +27 -0
- package/esm/src/guardrails/corpus/strings.js +33 -0
- package/esm/src/guardrails/corpus/types.d.ts +37 -0
- package/esm/src/guardrails/corpus/types.js +6 -0
- package/esm/src/guardrails/egress.d.ts +9 -0
- package/esm/src/guardrails/egress.js +36 -0
- package/esm/src/guardrails/error.js +6 -4
- package/esm/src/guardrails/injection.js +28 -5
- package/esm/src/guardrails/live-outbound-gate.d.ts +39 -0
- package/esm/src/guardrails/live-outbound-gate.js +180 -0
- package/esm/src/guardrails/mod.d.ts +13 -4
- package/esm/src/guardrails/mod.js +10 -4
- package/esm/src/guardrails/quota.js +1 -1
- package/esm/src/guardrails/sanitize.d.ts +11 -15
- package/esm/src/guardrails/sanitize.js +40 -49
- package/esm/src/guardrails/sensitive.js +2 -1
- package/esm/src/guardrails/testing.d.ts +10 -0
- package/esm/src/guardrails/testing.js +9 -0
- package/esm/src/host/client-turn.d.ts +19 -0
- package/esm/src/host/client-turn.js +32 -0
- package/esm/src/host/mod.d.ts +5 -3
- package/esm/src/host/mod.js +4 -3
- package/esm/src/interface/blocks.d.ts +20 -0
- package/esm/src/interface/blocks.js +180 -0
- package/esm/src/interface/from-profile.d.ts +14 -0
- package/esm/src/interface/from-profile.js +104 -0
- package/esm/src/interface/inputs.d.ts +8 -0
- package/esm/src/interface/inputs.js +127 -0
- package/esm/src/interface/mod.d.ts +10 -0
- package/esm/src/interface/mod.js +9 -0
- package/esm/src/interface/types.d.ts +153 -0
- package/esm/src/interface/types.js +13 -0
- package/esm/src/kernel/engine/delta.d.ts +24 -2
- package/esm/src/kernel/engine/delta.js +437 -39
- package/esm/src/kernel/engine/live-inbound.d.ts +9 -0
- package/esm/src/kernel/engine/live-inbound.js +17 -0
- package/esm/src/kernel/engine/repair.js +1 -1
- package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
- package/esm/src/kernel/engine/runner/gates.js +7 -7
- package/esm/src/kernel/engine/runner/mod.js +13 -13
- package/esm/src/kernel/engine/runner/state.d.ts +7 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
- package/esm/src/kernel/engine/runner/steps.js +171 -37
- package/esm/src/kernel/engine/runner/stream.d.ts +1 -2
- package/esm/src/kernel/engine/runner/stream.js +66 -29
- package/esm/src/kernel/engine/session/mod.d.ts +23 -0
- package/esm/src/kernel/engine/session/mod.js +205 -0
- package/esm/src/kernel/mod.d.ts +9 -10
- package/esm/src/kernel/mod.js +6 -8
- package/esm/src/kernel/registry/attachments.d.ts +4 -2
- package/esm/src/kernel/registry/attachments.js +6 -3
- package/esm/src/kernel/registry/catalog.d.ts +3 -16
- package/esm/src/kernel/registry/catalog.js +5 -81
- package/esm/src/kernel/registry/ingress.d.ts +9 -4
- package/esm/src/kernel/registry/ingress.js +73 -63
- package/esm/src/kernel/registry/profiles.d.ts +35 -12
- package/esm/src/kernel/registry/profiles.js +159 -66
- package/esm/src/kernel/registry/provider-request.js +11 -7
- package/esm/src/kernel/registry/resolve.d.ts +5 -6
- package/esm/src/kernel/registry/resolve.js +100 -70
- package/esm/src/kernel/registry/vault.d.ts +12 -7
- package/esm/src/kernel/registry/vault.js +30 -8
- package/esm/src/kernel/schema.d.ts +145 -0
- package/esm/src/kernel/schema.js +462 -0
- package/esm/src/kernel/stop.d.ts +15 -10
- package/esm/src/kernel/stop.js +5 -5
- package/esm/src/kernel/tools/execute.d.ts +45 -0
- package/esm/src/kernel/tools/execute.js +363 -0
- package/esm/src/kernel/tools/harness.d.ts +8 -0
- package/esm/src/kernel/tools/harness.js +44 -0
- package/esm/src/kernel/tools/invoke.d.ts +10 -0
- package/esm/src/kernel/tools/invoke.js +83 -0
- package/esm/src/kernel/tools/mod.d.ts +11 -0
- package/esm/src/kernel/tools/mod.js +10 -0
- package/esm/src/kernel/tools/project.d.ts +12 -0
- package/esm/src/kernel/tools/project.js +34 -0
- package/esm/src/kernel/tools/registry.d.ts +23 -0
- package/esm/src/kernel/tools/registry.js +71 -0
- package/esm/src/kernel/tools/resolve.d.ts +29 -0
- package/esm/src/kernel/tools/resolve.js +262 -0
- package/esm/src/kernel/tools/schema.d.ts +13 -0
- package/esm/src/kernel/tools/schema.js +159 -0
- package/esm/src/kernel/tools/types.d.ts +216 -0
- package/esm/src/kernel/tools/types.js +9 -0
- package/esm/src/kernel/types.d.ts +338 -193
- package/esm/src/observability/trace-attach.d.ts +6 -4
- package/esm/src/observability/trace-attach.js +39 -25
- package/esm/src/observability/trace-record.d.ts +11 -9
- package/esm/src/observability/trace-record.js +36 -23
- package/esm/src/observability/trace-usage.d.ts +10 -3
- package/esm/src/observability/trace-usage.js +70 -17
- package/esm/src/observability/trace.d.ts +9 -1
- package/esm/src/observability/trace.js +11 -3
- package/esm/src/presets/google/speech-voices.d.ts +11 -0
- package/esm/src/presets/google/speech-voices.js +41 -0
- package/esm/src/presets/google.d.ts +36 -24
- package/esm/src/presets/google.js +50 -63
- package/esm/src/presets/mod.d.ts +2 -2
- package/esm/src/presets/mod.js +1 -1
- package/esm/src/providers/create-provider.d.ts +14 -14
- package/esm/src/providers/create-provider.js +55 -23
- package/esm/src/providers/google/interactions/framing.d.ts +15 -0
- package/esm/src/providers/google/interactions/framing.js +208 -0
- package/esm/src/providers/google/interactions/mod.d.ts +7 -0
- package/esm/src/providers/google/interactions/mod.js +7 -0
- package/esm/src/providers/google/interactions/stream.d.ts +83 -0
- package/esm/src/providers/google/interactions/stream.js +588 -0
- package/esm/src/providers/google/keys.d.ts +26 -0
- package/esm/src/providers/{keys.js → google/keys.js} +19 -31
- package/esm/src/providers/google/live/framing.d.ts +46 -0
- package/esm/src/providers/google/live/framing.js +515 -0
- package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
- package/esm/src/providers/google/live/openapi-schema.js +45 -0
- package/esm/src/providers/google/live/session.d.ts +25 -0
- package/esm/src/providers/google/live/session.js +134 -0
- package/esm/src/providers/google/live/stream.d.ts +36 -0
- package/esm/src/providers/google/live/stream.js +201 -0
- package/esm/src/providers/google/urls.d.ts +6 -0
- package/esm/src/providers/google/urls.js +6 -0
- package/esm/src/providers/local/local.d.ts +30 -0
- package/esm/src/providers/{local.js → local/local.js} +66 -126
- package/esm/src/providers/local/mod.d.ts +9 -0
- package/esm/src/providers/local/mod.js +9 -0
- package/esm/src/providers/mod.d.ts +6 -3
- package/esm/src/providers/mod.js +3 -1
- package/esm/src/providers/openrouter/chat.d.ts +87 -0
- package/esm/src/providers/{openrouter.js → openrouter/chat.js} +70 -229
- package/esm/src/providers/openrouter/image.d.ts +34 -0
- package/esm/src/providers/openrouter/image.js +286 -0
- package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
- package/esm/src/providers/openrouter/openai/chat-payload.js +60 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +47 -0
- package/esm/src/providers/openrouter/openai/compat.js +194 -0
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
- package/esm/src/providers/openrouter/openai/image-payload.js +84 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.js +95 -0
- package/esm/src/providers/openrouter/resolve-api-key.d.ts +9 -0
- package/esm/src/providers/openrouter/resolve-api-key.js +24 -0
- package/esm/src/providers/openrouter/speech.d.ts +23 -0
- package/esm/src/providers/{speech.js → openrouter/speech.js} +32 -55
- package/esm/src/providers/probe.d.ts +1 -0
- package/esm/src/providers/probe.js +22 -0
- package/esm/src/providers/shared/pcm.d.ts +12 -0
- package/esm/src/providers/{pcm.js → shared/pcm.js} +16 -3
- package/esm/src/providers/shared/sse.d.ts +18 -0
- package/esm/src/providers/shared/sse.js +87 -0
- package/esm/src/providers/shared/tool-args.d.ts +17 -0
- package/esm/src/providers/shared/tool-args.js +45 -0
- package/esm/src/providers/shared/upstream-tap.d.ts +5 -0
- package/esm/src/providers/{google-tap.js → shared/upstream-tap.js} +4 -7
- package/esm/src/providers/shared/upstream-tape.d.ts +6 -0
- package/esm/src/providers/{gemini-tape.js → shared/upstream-tape.js} +12 -22
- package/esm/src/providers/types.d.ts +27 -0
- package/esm/src/providers/types.js +1 -0
- package/package.json +11 -7
- package/docs/cli.md +0 -97
- package/docs/guardrails.md +0 -178
- package/docs/host.md +0 -97
- package/docs/kernel.md +0 -404
- package/docs/observability.md +0 -105
- package/docs/openrouter.md +0 -125
- package/docs/presets-google.md +0 -91
- package/docs/presets.md +0 -88
- package/docs/providers.md +0 -202
- package/docs/streaming.md +0 -96
- package/esm/src/kernel/engine/boundary.d.ts +0 -10
- package/esm/src/kernel/engine/boundary.js +0 -55
- package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
- package/esm/src/kernel/engine/runner/tools.js +0 -198
- package/esm/src/kernel/registry/tools.d.ts +0 -12
- package/esm/src/kernel/registry/tools.js +0 -36
- package/esm/src/providers/expose-for-tests.d.ts +0 -1
- package/esm/src/providers/expose-for-tests.js +0 -25
- package/esm/src/providers/gemini-tape.d.ts +0 -2
- package/esm/src/providers/google-tap.d.ts +0 -3
- package/esm/src/providers/interactions.d.ts +0 -5
- package/esm/src/providers/interactions.js +0 -169
- package/esm/src/providers/keys.d.ts +0 -19
- package/esm/src/providers/local.d.ts +0 -29
- package/esm/src/providers/openrouter-mod.d.ts +0 -13
- package/esm/src/providers/openrouter-mod.js +0 -12
- package/esm/src/providers/openrouter-payload.d.ts +0 -39
- package/esm/src/providers/openrouter-payload.js +0 -195
- package/esm/src/providers/openrouter.d.ts +0 -15
- package/esm/src/providers/pcm.d.ts +0 -7
- package/esm/src/providers/provider.d.ts +0 -15
- package/esm/src/providers/provider.js +0 -202
- package/esm/src/providers/speech.d.ts +0 -23
- package/esm/src/providers/sse.d.ts +0 -7
- package/esm/src/providers/sse.js +0 -55
- package/esm/src/streaming/mod.d.ts +0 -9
- package/esm/src/streaming/mod.js +0 -8
- /package/esm/src/{streaming → host}/readStreamingJsonStringField.d.ts +0 -0
- /package/esm/src/{streaming → host}/readStreamingJsonStringField.js +0 -0
|
@@ -1,27 +1,6 @@
|
|
|
1
|
-
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
1
|
import { runTurn } from '../../kernel/engine/runner.js';
|
|
3
2
|
import { getProfile } from '../../kernel/registry/profiles.js';
|
|
4
|
-
|
|
5
|
-
if (event.type === 'thought' && event.text) {
|
|
6
|
-
dntShim.Deno.stdout.write(new TextEncoder().encode(`\x1b[2m${event.text}\x1b[0m`));
|
|
7
|
-
}
|
|
8
|
-
else if (event.type === 'text' && event.text) {
|
|
9
|
-
dntShim.Deno.stdout.write(new TextEncoder().encode(event.text));
|
|
10
|
-
}
|
|
11
|
-
else if (event.type === 'tool' && event.tool) {
|
|
12
|
-
console.log(`\n\x1b[33m⚡ [Tool Call] ${event.tool.name}\x1b[0m:`, event.tool.arguments);
|
|
13
|
-
}
|
|
14
|
-
else if (event.type === 'structured' && event.structured) {
|
|
15
|
-
console.log('\n\x1b[32m✓ [Structured Output]\x1b[0m:');
|
|
16
|
-
console.log(JSON.stringify(event.structured, null, 2));
|
|
17
|
-
}
|
|
18
|
-
else if (event.type === 'media' && event.media) {
|
|
19
|
-
console.log(`\n\x1b[34m🖼 [Media Output]\x1b[0m (${event.media.mimeType})`);
|
|
20
|
-
}
|
|
21
|
-
else if (event.type === 'error' && event.error) {
|
|
22
|
-
console.error(`\n\x1b[31m✗ Error\x1b[0m: ${event.error}`);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
3
|
+
import { createCliTraceCapture, printRunEvent, printTraceRecord } from '../event-log.js';
|
|
25
4
|
export async function runCommand(options) {
|
|
26
5
|
getProfile(options.profile);
|
|
27
6
|
const provider = options.provider;
|
|
@@ -30,24 +9,37 @@ export async function runCommand(options) {
|
|
|
30
9
|
return;
|
|
31
10
|
}
|
|
32
11
|
const prompt = options.prompt || 'Hello! Please introduce your capabilities.';
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
12
|
+
if (options.search || options.map) {
|
|
13
|
+
const profile = getProfile(options.profile);
|
|
14
|
+
const selected = options.mode
|
|
15
|
+
? (profile.model.select?.[options.mode] ?? profile.model.allow[0])
|
|
16
|
+
: profile.model.allow[0];
|
|
17
|
+
const builtins = new Set(profile.model.config[selected]?.builtInTools ?? []);
|
|
18
|
+
if (options.search && !builtins.has('googleSearch')) {
|
|
19
|
+
console.error('\n\x1b[31mExecution Failed\x1b[0m: --search requires googleSearch on model.config.*.builtInTools for the selected model.\n');
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (options.map && !builtins.has('googleMaps')) {
|
|
23
|
+
console.error('\n\x1b[31mExecution Failed\x1b[0m: --map requires googleMaps on model.config.*.builtInTools for the selected model.\n');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
38
27
|
const req = {
|
|
39
28
|
profile: options.profile,
|
|
40
29
|
select: options.mode,
|
|
41
|
-
tools: Object.keys(tools).length > 0 ? tools : undefined,
|
|
42
30
|
input: { text: prompt },
|
|
43
31
|
};
|
|
44
32
|
console.log(`\n▶ [RUNNING TURN] Profile: ${options.profile} (${options.mode ?? 'default'})`);
|
|
45
33
|
console.log(`Prompt: "${prompt}"\n`);
|
|
34
|
+
const traceCapture = options.trace ? createCliTraceCapture(options.traceDir) : undefined;
|
|
46
35
|
try {
|
|
47
|
-
for await (const event of runTurn(req, provider)) {
|
|
48
|
-
|
|
36
|
+
for await (const event of runTurn(req, provider, traceCapture?.sink)) {
|
|
37
|
+
printRunEvent(event, { verbose: options.verbose });
|
|
49
38
|
}
|
|
50
39
|
console.log('\n');
|
|
40
|
+
if (options.trace) {
|
|
41
|
+
printTraceRecord(traceCapture?.records.at(-1), options.verbose === true);
|
|
42
|
+
}
|
|
51
43
|
}
|
|
52
44
|
catch (err) {
|
|
53
45
|
console.error(`\n\x1b[31mExecution Failed\x1b[0m: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
@@ -7,9 +7,18 @@ export interface TestRunResult {
|
|
|
7
7
|
tokensTotal?: number;
|
|
8
8
|
error?: string;
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
interface CliTestOptions {
|
|
11
|
+
verbose?: boolean;
|
|
12
|
+
trace?: boolean;
|
|
13
|
+
traceDir?: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function executeSingleTest(req: TurnRequest, testName: string, provider?: ModelProvider, cliOptions?: CliTestOptions): Promise<TestRunResult>;
|
|
11
16
|
export declare function testProfileCommand(profileId?: string, options?: MatrixOptions & {
|
|
12
17
|
all?: boolean;
|
|
13
18
|
matrix?: boolean;
|
|
14
19
|
provider?: ModelProvider;
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
trace?: boolean;
|
|
22
|
+
traceDir?: string;
|
|
15
23
|
}): Promise<boolean>;
|
|
24
|
+
export {};
|
|
@@ -1,39 +1,30 @@
|
|
|
1
|
-
import * as dntShim from "../../../_dnt.shims.js";
|
|
2
1
|
import { runTurn } from '../../kernel/engine/runner.js';
|
|
3
2
|
import { getProfile, listProfiles } from '../../kernel/registry/profiles.js';
|
|
3
|
+
import { createCliTraceCapture, printTestEvent, printTraceRecord } from '../event-log.js';
|
|
4
4
|
import { buildCustomTurnRequest, synthesizeMatrixCombos, } from '../matrix/synthesizer.js';
|
|
5
5
|
function printTestHeader(req, testName) {
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
.
|
|
9
|
-
.
|
|
6
|
+
const profile = getProfile(req.profile);
|
|
7
|
+
const modelId = req.select && profile.model.select?.[req.select]
|
|
8
|
+
? profile.model.select[req.select]
|
|
9
|
+
: profile.model.allow[0];
|
|
10
|
+
const customs = profile.type === 'speech' ? 'none' : profile.tools.allow.join(', ') || 'none';
|
|
11
|
+
const builtins = (profile.model.config[modelId]?.builtInTools ?? []).join(', ') || 'none';
|
|
10
12
|
console.log(`\n▶ [THEORUM TEST] ${testName}`);
|
|
11
13
|
console.log(` Profile: ${req.profile} (Mode: ${req.select ?? 'default'})`);
|
|
12
|
-
console.log(`
|
|
14
|
+
console.log(` Custom: ${customs}`);
|
|
15
|
+
console.log(` Builtins: ${builtins}`);
|
|
13
16
|
console.log(` Attachments: ${req.input?.attachments?.length ?? 0} file(s) | Voice: ${req.input?.voice?.length ? 'yes' : 'no'}`);
|
|
14
17
|
console.log(` ${'-'.repeat(60)}`);
|
|
15
18
|
}
|
|
16
|
-
function processTestEvent(event, acc) {
|
|
17
|
-
if (event.type === '
|
|
18
|
-
dntShim.Deno.stdout.write(new TextEncoder().encode('.'));
|
|
19
|
-
}
|
|
20
|
-
else if (event.type === 'tool' && event.tool) {
|
|
21
|
-
console.log(`\n ⚡ [Tool Dispatched] ${event.tool.name}(${JSON.stringify(event.tool.arguments ?? {})})`);
|
|
22
|
-
}
|
|
23
|
-
else if (event.type === 'structured') {
|
|
24
|
-
console.log(`\n ✓ [Structured Schema Validated]`);
|
|
25
|
-
}
|
|
26
|
-
else if (event.type === 'media') {
|
|
27
|
-
console.log(`\n ✓ [Media Generated] (${event.media?.mimeType})`);
|
|
28
|
-
}
|
|
29
|
-
else if (event.type === 'tokens' && event.tokens) {
|
|
19
|
+
function processTestEvent(event, acc, options) {
|
|
20
|
+
if (event.type === 'tokens' && event.tokens) {
|
|
30
21
|
acc.totalTokens = event.tokens.total;
|
|
31
22
|
}
|
|
32
|
-
|
|
23
|
+
if (event.type === 'error' && event.error) {
|
|
33
24
|
acc.hasError = true;
|
|
34
25
|
acc.errorMessage = event.error;
|
|
35
|
-
console.error(`\n [Test Error Detail]: ${event.error}`);
|
|
36
26
|
}
|
|
27
|
+
printTestEvent(event, { verbose: options.verbose });
|
|
37
28
|
}
|
|
38
29
|
function printTestResult(passed, durationSec, acc) {
|
|
39
30
|
if (passed) {
|
|
@@ -43,7 +34,7 @@ function printTestResult(passed, durationSec, acc) {
|
|
|
43
34
|
console.log(`\n ✗ STATUS: FAILED: ${acc.errorMessage} (${durationSec.toFixed(2)}s)`);
|
|
44
35
|
}
|
|
45
36
|
}
|
|
46
|
-
export async function executeSingleTest(req, testName, provider) {
|
|
37
|
+
export async function executeSingleTest(req, testName, provider, cliOptions = {}) {
|
|
47
38
|
const start = Date.now();
|
|
48
39
|
getProfile(req.profile);
|
|
49
40
|
printTestHeader(req, testName);
|
|
@@ -56,8 +47,12 @@ export async function executeSingleTest(req, testName, provider) {
|
|
|
56
47
|
if (!provider) {
|
|
57
48
|
throw new Error('Theorum CLI does not create providers or read keys. Pass an explicit ModelProvider from the host app.');
|
|
58
49
|
}
|
|
59
|
-
|
|
60
|
-
|
|
50
|
+
const traceCapture = cliOptions.trace ? createCliTraceCapture(cliOptions.traceDir) : undefined;
|
|
51
|
+
for await (const event of runTurn(req, provider, traceCapture?.sink)) {
|
|
52
|
+
processTestEvent(event, acc, cliOptions);
|
|
53
|
+
}
|
|
54
|
+
if (cliOptions.trace) {
|
|
55
|
+
printTraceRecord(traceCapture?.records.at(-1), cliOptions.verbose === true);
|
|
61
56
|
}
|
|
62
57
|
}
|
|
63
58
|
catch (err) {
|
|
@@ -91,19 +86,19 @@ function resolveTargetProfiles(profileId, all) {
|
|
|
91
86
|
console.error('Error: Please specify a profile ID (e.g. `theorum test --profile your-profile`) or `--all`.');
|
|
92
87
|
return null;
|
|
93
88
|
}
|
|
94
|
-
async function runProfileMatrix(profile, provider) {
|
|
89
|
+
async function runProfileMatrix(profile, provider, cliOptions = {}) {
|
|
95
90
|
const results = [];
|
|
96
91
|
const combos = synthesizeMatrixCombos(profile);
|
|
97
92
|
for (const combo of combos) {
|
|
98
|
-
const res = await executeSingleTest(combo.req, `${profile.id} [${combo.name}]`, provider);
|
|
93
|
+
const res = await executeSingleTest(combo.req, `${profile.id} [${combo.name}]`, provider, cliOptions);
|
|
99
94
|
results.push(res);
|
|
100
95
|
}
|
|
101
96
|
return results;
|
|
102
97
|
}
|
|
103
|
-
async function runProfileSingle(profile, options, provider) {
|
|
98
|
+
async function runProfileSingle(profile, options, provider, cliOptions = {}) {
|
|
104
99
|
const req = buildCustomTurnRequest(profile, options);
|
|
105
100
|
const testName = options.lite ? `${profile.id} [Lite]` : `${profile.id} [Stress Combo]`;
|
|
106
|
-
return await executeSingleTest(req, testName, provider);
|
|
101
|
+
return await executeSingleTest(req, testName, provider, cliOptions);
|
|
107
102
|
}
|
|
108
103
|
function printSummaryReport(results) {
|
|
109
104
|
console.log(`\n${'='.repeat(70)}`);
|
|
@@ -127,13 +122,18 @@ export async function testProfileCommand(profileId, options = {}) {
|
|
|
127
122
|
if (!targetProfiles || targetProfiles.length === 0) {
|
|
128
123
|
return false;
|
|
129
124
|
}
|
|
125
|
+
const cliOptions = {
|
|
126
|
+
verbose: options.verbose,
|
|
127
|
+
trace: options.trace,
|
|
128
|
+
traceDir: options.traceDir,
|
|
129
|
+
};
|
|
130
130
|
const results = [];
|
|
131
131
|
for (const profile of targetProfiles) {
|
|
132
132
|
if (options.matrix) {
|
|
133
|
-
results.push(...(await runProfileMatrix(profile, options.provider)));
|
|
133
|
+
results.push(...(await runProfileMatrix(profile, options.provider, cliOptions)));
|
|
134
134
|
}
|
|
135
135
|
else {
|
|
136
|
-
results.push(await runProfileSingle(profile, options, options.provider));
|
|
136
|
+
results.push(await runProfileSingle(profile, options, options.provider, cliOptions));
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
return printSummaryReport(results);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { TurnEvent } from '../kernel/types.js';
|
|
2
|
+
import { type TraceSink } from '../observability/trace.js';
|
|
3
|
+
import type { TraceRecord } from '../observability/trace-record.js';
|
|
4
|
+
export interface CliEventLogOptions {
|
|
5
|
+
verbose?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface CliTraceCapture {
|
|
8
|
+
sink: TraceSink;
|
|
9
|
+
records: TraceRecord[];
|
|
10
|
+
}
|
|
11
|
+
/** Attach an in-memory trace sink; optionally mirror to a JSONL directory. */
|
|
12
|
+
declare function createCliTraceCapture(traceDir?: string): CliTraceCapture;
|
|
13
|
+
/** Print one turn event for `theorum run`. */
|
|
14
|
+
declare function printRunEvent(event: TurnEvent, options?: CliEventLogOptions): void;
|
|
15
|
+
/** Print one turn event for `theorum test`. */
|
|
16
|
+
declare function printTestEvent(event: TurnEvent, options?: CliEventLogOptions): void;
|
|
17
|
+
/** Dump the last captured trace record after a CLI turn. */
|
|
18
|
+
declare function printTraceRecord(record: TraceRecord | undefined, verbose: boolean): void;
|
|
19
|
+
export { createCliTraceCapture, printRunEvent, printTestEvent, printTraceRecord };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI turn-event printing and trace capture for `run` and `test`.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import * as dntShim from "../../_dnt.shims.js";
|
|
7
|
+
import { jsonlSink, memorySink } from '../observability/trace.js';
|
|
8
|
+
/** Attach an in-memory trace sink; optionally mirror to a JSONL directory. */
|
|
9
|
+
function createCliTraceCapture(traceDir) {
|
|
10
|
+
const records = [];
|
|
11
|
+
const sinks = [memorySink(records)];
|
|
12
|
+
if (traceDir?.trim()) {
|
|
13
|
+
sinks.push(jsonlSink(traceDir.trim()));
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
records,
|
|
17
|
+
sink: {
|
|
18
|
+
write: async (record) => {
|
|
19
|
+
for (const sink of sinks) {
|
|
20
|
+
await sink.write(record);
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function printVerboseEvidence(event) {
|
|
27
|
+
if (event.type !== 'evidence' || !event.evidence) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const e = event.evidence;
|
|
31
|
+
if (e.raw) {
|
|
32
|
+
console.log('\n\x1b[2m[verbose evidence.raw]\x1b[0m');
|
|
33
|
+
console.log(JSON.stringify(e.raw, null, 2));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function printVerboseError(event) {
|
|
37
|
+
if (event.type !== 'error' || !event.errorInternal) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
console.error(`\n\x1b[2m[verbose errorInternal]\x1b[0m ${event.errorInternal}`);
|
|
41
|
+
}
|
|
42
|
+
function printRunEvidence(event, verbose) {
|
|
43
|
+
const e = event.evidence;
|
|
44
|
+
if (!e) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (e.kind === 'code_execution_call') {
|
|
48
|
+
console.log(`\n\x1b[36m🐍 [code_execution_call]\x1b[0m\n${e.code ?? ''}`);
|
|
49
|
+
}
|
|
50
|
+
else if (e.kind === 'code_execution_result') {
|
|
51
|
+
console.log(`\n\x1b[36m🐍 [code_execution_result]\x1b[0m isError=${String(e.isError)}\n${e.result ?? ''}`);
|
|
52
|
+
}
|
|
53
|
+
else if (e.kind) {
|
|
54
|
+
console.log(`\n\x1b[36m📎 [evidence]\x1b[0m ${e.kind}`);
|
|
55
|
+
}
|
|
56
|
+
if (verbose) {
|
|
57
|
+
printVerboseEvidence(event);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Print one turn event for `theorum run`. */
|
|
61
|
+
function printRunEvent(event, options = {}) {
|
|
62
|
+
const verbose = options.verbose === true;
|
|
63
|
+
if (event.type === 'thought' && event.text) {
|
|
64
|
+
dntShim.Deno.stdout.write(new TextEncoder().encode(`\x1b[2m${event.text}\x1b[0m`));
|
|
65
|
+
}
|
|
66
|
+
else if (event.type === 'text' && event.text) {
|
|
67
|
+
dntShim.Deno.stdout.write(new TextEncoder().encode(event.text));
|
|
68
|
+
}
|
|
69
|
+
else if (event.type === 'tool' && event.tool) {
|
|
70
|
+
console.log(`\n\x1b[33m⚡ [Tool Call] ${event.tool.name}\x1b[0m:`, event.tool.arguments);
|
|
71
|
+
}
|
|
72
|
+
else if (event.type === 'evidence') {
|
|
73
|
+
printRunEvidence(event, verbose);
|
|
74
|
+
}
|
|
75
|
+
else if (event.type === 'structured' && event.structured) {
|
|
76
|
+
console.log('\n\x1b[32m✓ [Structured Output]\x1b[0m:');
|
|
77
|
+
console.log(JSON.stringify(event.structured, null, 2));
|
|
78
|
+
}
|
|
79
|
+
else if (event.type === 'media' && event.media) {
|
|
80
|
+
console.log(`\n\x1b[34m🖼 [Media Output]\x1b[0m (${event.media.mimeType})`);
|
|
81
|
+
}
|
|
82
|
+
else if (event.type === 'error' && event.error) {
|
|
83
|
+
console.error(`\n\x1b[31m✗ Error\x1b[0m: ${event.error}`);
|
|
84
|
+
if (verbose) {
|
|
85
|
+
printVerboseError(event);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function printTestEvidence(event, verbose) {
|
|
90
|
+
const e = event.evidence;
|
|
91
|
+
if (!e) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (e.kind === 'code_execution_call') {
|
|
95
|
+
const preview = (e.code ?? '').replaceAll('\n', ' ').slice(0, 80);
|
|
96
|
+
console.log(`\n 🐍 [code_execution_call] ${preview || e.id || ''}`);
|
|
97
|
+
}
|
|
98
|
+
else if (e.kind === 'code_execution_result') {
|
|
99
|
+
const preview = (e.result ?? '').replaceAll('\n', ' ').slice(0, 80);
|
|
100
|
+
console.log(`\n 🐍 [code_execution_result] isError=${String(e.isError)} ${preview}`);
|
|
101
|
+
}
|
|
102
|
+
else if (e.kind) {
|
|
103
|
+
console.log(`\n 📎 [evidence] ${e.kind}`);
|
|
104
|
+
}
|
|
105
|
+
if (verbose) {
|
|
106
|
+
printVerboseEvidence(event);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** Print one turn event for `theorum test`. */
|
|
110
|
+
function printTestEvent(event, options = {}) {
|
|
111
|
+
const verbose = options.verbose === true;
|
|
112
|
+
if (event.type === 'thought' && event.text) {
|
|
113
|
+
dntShim.Deno.stdout.write(new TextEncoder().encode('.'));
|
|
114
|
+
}
|
|
115
|
+
else if (event.type === 'tool' && event.tool) {
|
|
116
|
+
console.log(`\n ⚡ [Tool Dispatched] ${event.tool.name}(${JSON.stringify(event.tool.arguments ?? {})})`);
|
|
117
|
+
}
|
|
118
|
+
else if (event.type === 'evidence') {
|
|
119
|
+
printTestEvidence(event, verbose);
|
|
120
|
+
}
|
|
121
|
+
else if (event.type === 'structured') {
|
|
122
|
+
console.log('\n ✓ [Structured Schema Validated]');
|
|
123
|
+
}
|
|
124
|
+
else if (event.type === 'media') {
|
|
125
|
+
console.log(`\n ✓ [Media Generated] (${event.media?.mimeType})`);
|
|
126
|
+
}
|
|
127
|
+
else if (event.type === 'error' && event.error) {
|
|
128
|
+
console.error(`\n [Test Error Detail]: ${event.error}`);
|
|
129
|
+
if (verbose) {
|
|
130
|
+
printVerboseError(event);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
/** Dump the last captured trace record after a CLI turn. */
|
|
135
|
+
function printTraceRecord(record, verbose) {
|
|
136
|
+
if (!record) {
|
|
137
|
+
console.error('\n\x1b[33m[trace]\x1b[0m No trace record captured for this turn.');
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
console.log('\n\x1b[35m════ TRACE RECORD ════\x1b[0m');
|
|
141
|
+
console.log(JSON.stringify(record, null, 2));
|
|
142
|
+
if (verbose && record.upstreamLog) {
|
|
143
|
+
console.log('\n\x1b[35m════ UPSTREAM LOG ════\x1b[0m');
|
|
144
|
+
console.log(JSON.stringify(record.upstreamLog, null, 2));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
export { createCliTraceCapture, printRunEvent, printTestEvent, printTraceRecord };
|
package/esm/src/cli/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import "../../_dnt.polyfills.js";
|
|
|
3
3
|
import "../../_dnt.polyfills.js";
|
|
4
4
|
import * as dntShim from "../../_dnt.shims.js";
|
|
5
5
|
import { benchCommand } from './commands/bench.js';
|
|
6
|
+
import { fuzzCanaryCommand } from './commands/fuzz-canary.js';
|
|
6
7
|
import { fuzzGuardrailsCommand } from './commands/fuzz-guardrails.js';
|
|
7
8
|
import { listProfilesCommand, showProfileCommand } from './commands/profile.js';
|
|
8
9
|
import { runCommand } from './commands/run.js';
|
|
@@ -20,7 +21,18 @@ COMMANDS:
|
|
|
20
21
|
--iterations <n> Measurement iterations (default: 50)
|
|
21
22
|
--warmup <n> Warmup iterations (default: 5)
|
|
22
23
|
|
|
23
|
-
fuzz Adversarial
|
|
24
|
+
fuzz Adversarial inbound sanitization fuzzer
|
|
25
|
+
fuzz-canary Adversarial canary egress fuzzer (stream + Live gates)
|
|
26
|
+
|
|
27
|
+
run Execute a turn with real-time streaming output
|
|
28
|
+
--profile, -p <id> Target profile ID
|
|
29
|
+
--prompt <text> User prompt string
|
|
30
|
+
--mode <fast|smart> Reasoning mode
|
|
31
|
+
--search Requires googleSearch on the selected model's builtInTools
|
|
32
|
+
--map Requires googleMaps on the selected model's builtInTools
|
|
33
|
+
--verbose, -v Print errorInternal and evidence.raw while running
|
|
34
|
+
--trace Capture a TraceRecord and print it after the turn
|
|
35
|
+
--trace-dir <path> Also append trace JSONL under this directory
|
|
24
36
|
|
|
25
37
|
test Run stress matrix or custom profile tests
|
|
26
38
|
--profile, -p <id> Target profile ID registered by your host app
|
|
@@ -28,15 +40,11 @@ COMMANDS:
|
|
|
28
40
|
--lite Minimal fast-path connectivity ping
|
|
29
41
|
--matrix Run all valid permutations for the profile
|
|
30
42
|
--mode <fast|smart> Reasoning mode override
|
|
31
|
-
--search
|
|
32
|
-
--map
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
--
|
|
36
|
-
--prompt <text> User prompt string
|
|
37
|
-
--mode <fast|smart> Reasoning mode
|
|
38
|
-
--search Optional: set tool id googleSearch when allowlisted
|
|
39
|
-
--map Optional: set tool id googleMaps when allowlisted
|
|
43
|
+
--search Requires googleSearch on the selected model's builtInTools
|
|
44
|
+
--map Requires googleMaps on the selected model's builtInTools
|
|
45
|
+
--verbose, -v Print errorInternal and evidence.raw while running
|
|
46
|
+
--trace Capture a TraceRecord and print it after each turn
|
|
47
|
+
--trace-dir <path> Also append trace JSONL under this directory
|
|
40
48
|
|
|
41
49
|
profile Inspect registered profile blueprints
|
|
42
50
|
list List all registered profiles
|
|
@@ -45,6 +53,13 @@ COMMANDS:
|
|
|
45
53
|
help, --help, -h Show this help message
|
|
46
54
|
`);
|
|
47
55
|
}
|
|
56
|
+
function cliDiagnostics(flags) {
|
|
57
|
+
return {
|
|
58
|
+
verbose: Boolean(flags.verbose || flags.v),
|
|
59
|
+
trace: Boolean(flags.trace),
|
|
60
|
+
traceDir: typeof flags['trace-dir'] === 'string' ? flags['trace-dir'] : undefined,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
48
63
|
function parseLongFlag(arg, nextArg, flags) {
|
|
49
64
|
const key = arg.slice(2);
|
|
50
65
|
if (nextArg && !nextArg.startsWith('-')) {
|
|
@@ -64,6 +79,8 @@ function parseShortFlag(arg, nextArg, flags) {
|
|
|
64
79
|
flags.all = true;
|
|
65
80
|
else if (key === 'h')
|
|
66
81
|
flags.help = true;
|
|
82
|
+
else if (key === 'v')
|
|
83
|
+
flags.verbose = true;
|
|
67
84
|
else
|
|
68
85
|
flags[key] = true;
|
|
69
86
|
return 0;
|
|
@@ -96,6 +113,7 @@ function extractProfileId(flags) {
|
|
|
96
113
|
}
|
|
97
114
|
async function handleTest(flags) {
|
|
98
115
|
const profile = extractProfileId(flags);
|
|
116
|
+
const diagnostics = cliDiagnostics(flags);
|
|
99
117
|
const success = await testProfileCommand(profile, {
|
|
100
118
|
all: Boolean(flags.all || flags.a),
|
|
101
119
|
lite: Boolean(flags.lite),
|
|
@@ -103,6 +121,9 @@ async function handleTest(flags) {
|
|
|
103
121
|
mode: typeof flags.mode === 'string' ? flags.mode : undefined,
|
|
104
122
|
search: flags.search ? true : undefined,
|
|
105
123
|
map: flags.map ? true : undefined,
|
|
124
|
+
verbose: diagnostics.verbose,
|
|
125
|
+
trace: diagnostics.trace,
|
|
126
|
+
traceDir: diagnostics.traceDir,
|
|
106
127
|
});
|
|
107
128
|
if (!success) {
|
|
108
129
|
dntShim.Deno.exit(1);
|
|
@@ -115,12 +136,16 @@ async function handleRun(flags) {
|
|
|
115
136
|
dntShim.Deno.exit(1);
|
|
116
137
|
}
|
|
117
138
|
const prompt = typeof flags.prompt === 'string' ? flags.prompt : flags._.slice(1).join(' ');
|
|
139
|
+
const diagnostics = cliDiagnostics(flags);
|
|
118
140
|
await runCommand({
|
|
119
141
|
profile,
|
|
120
142
|
prompt,
|
|
121
143
|
mode: typeof flags.mode === 'string' ? flags.mode : undefined,
|
|
122
144
|
search: Boolean(flags.search),
|
|
123
145
|
map: Boolean(flags.map),
|
|
146
|
+
verbose: diagnostics.verbose,
|
|
147
|
+
trace: diagnostics.trace,
|
|
148
|
+
traceDir: diagnostics.traceDir,
|
|
124
149
|
});
|
|
125
150
|
}
|
|
126
151
|
function handleProfile(flags) {
|
|
@@ -140,7 +165,16 @@ export async function main(cliArgs = dntShim.Deno.args) {
|
|
|
140
165
|
const flags = parseFlags(cliArgs);
|
|
141
166
|
const command = flags._[0] || (flags.help ? 'help' : 'help');
|
|
142
167
|
if (command === 'fuzz') {
|
|
143
|
-
fuzzGuardrailsCommand();
|
|
168
|
+
const ok = fuzzGuardrailsCommand();
|
|
169
|
+
if (!ok) {
|
|
170
|
+
dntShim.Deno.exit(1);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else if (command === 'fuzz-canary') {
|
|
174
|
+
const ok = await fuzzCanaryCommand();
|
|
175
|
+
if (!ok) {
|
|
176
|
+
dntShim.Deno.exit(1);
|
|
177
|
+
}
|
|
144
178
|
}
|
|
145
179
|
else if (command === 'bench') {
|
|
146
180
|
await benchCommand({
|
|
@@ -1,27 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Stress / matrix turn synthesis for the THEORUM CLI.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Custom tools come from `profile.tools.allow` (visibility via loadTier).
|
|
5
|
+
* Provider builtins come from `model.config.*.builtInTools`. `--search` /
|
|
6
|
+
* `--map` only verify those ids are listed on the selected model.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
-
import type { Profile,
|
|
10
|
+
import type { Profile, TurnRequest } from '../../kernel/types.js';
|
|
11
11
|
export interface MatrixOptions {
|
|
12
12
|
lite?: boolean;
|
|
13
|
-
/**
|
|
13
|
+
/** Requires googleSearch on the selected model's builtInTools. */
|
|
14
14
|
search?: boolean;
|
|
15
|
-
/**
|
|
15
|
+
/** Requires googleMaps on the selected model's builtInTools. */
|
|
16
16
|
map?: boolean;
|
|
17
17
|
mode?: string;
|
|
18
18
|
attachmentPaths?: string[];
|
|
19
19
|
voicePath?: string;
|
|
20
20
|
}
|
|
21
21
|
export declare function synthesizeLiteCombo(profile: Profile): TurnRequest;
|
|
22
|
-
export declare function synthesizeStressCombo(profile: Profile
|
|
23
|
-
preferTool?: ToolId;
|
|
24
|
-
}): TurnRequest;
|
|
22
|
+
export declare function synthesizeStressCombo(profile: Profile): TurnRequest;
|
|
25
23
|
export declare function synthesizeMatrixCombos(profile: Profile): Array<{
|
|
26
24
|
name: string;
|
|
27
25
|
req: TurnRequest;
|