theorum 0.1.3 → 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/README.md +30 -9
- package/deno.json +57 -0
- package/deno.lock +469 -0
- package/{esm/mod.d.ts → mod.ts} +57 -15
- package/package.json +35 -44
- package/src/cli/commands/profile.ts +57 -0
- package/src/cli/commands/run.ts +66 -0
- package/src/cli/commands/test.ts +195 -0
- package/src/cli/index.ts +161 -0
- package/src/cli/matrix/fixtures.ts +96 -0
- package/src/cli/matrix/synthesizer.ts +240 -0
- package/src/guardrails/error.ts +142 -0
- package/src/guardrails/injection.ts +254 -0
- package/src/guardrails/mod.ts +40 -0
- package/src/guardrails/quota.ts +87 -0
- package/src/guardrails/sanitize.ts +165 -0
- package/src/guardrails/sensitive.ts +96 -0
- package/src/host/mint-trace.ts +54 -0
- package/{esm/src/host/mod.js → src/host/mod.ts} +11 -3
- package/src/host/reply.ts +32 -0
- package/src/kernel/engine/assert.ts +29 -0
- package/src/kernel/engine/boundary.ts +75 -0
- package/src/kernel/engine/delta.ts +440 -0
- package/src/kernel/engine/hash.ts +11 -0
- package/src/kernel/engine/record.ts +8 -0
- package/src/kernel/engine/repair.ts +56 -0
- package/src/kernel/engine/runner/gates.ts +338 -0
- package/src/kernel/engine/runner/mod.ts +135 -0
- package/src/kernel/engine/runner/state.ts +31 -0
- package/src/kernel/engine/runner/steps.ts +183 -0
- package/src/kernel/engine/runner/stream.ts +83 -0
- package/src/kernel/engine/runner/tokens.ts +47 -0
- package/src/kernel/engine/runner/tools.ts +266 -0
- package/{esm/src/kernel/engine/runner.d.ts → src/kernel/engine/runner.ts} +2 -1
- package/src/kernel/engine/tree.ts +18 -0
- package/src/kernel/mod.ts +39 -0
- package/src/kernel/registry/attachments.ts +195 -0
- package/src/kernel/registry/catalog.ts +181 -0
- package/src/kernel/registry/ingress.ts +223 -0
- package/src/kernel/registry/profiles.ts +165 -0
- package/src/kernel/registry/provider-request.ts +31 -0
- package/src/kernel/registry/resolve.ts +290 -0
- package/src/kernel/registry/schemas.ts +29 -0
- package/src/kernel/registry/tools.ts +45 -0
- package/{esm/src/kernel/registry/vault.d.ts → src/kernel/registry/vault.ts} +17 -2
- package/src/kernel/types.ts +576 -0
- package/{esm/src/observability/mod.js → src/observability/mod.ts} +11 -2
- package/src/observability/spans.ts +70 -0
- package/src/observability/trace-attach.ts +96 -0
- package/src/observability/trace-record.ts +254 -0
- package/src/observability/trace-usage.ts +36 -0
- package/src/observability/trace.ts +143 -0
- package/src/presets/google.ts +147 -0
- package/src/presets/mod.ts +24 -0
- package/src/providers/create-provider.ts +64 -0
- package/src/providers/gemini-tape.ts +59 -0
- package/src/providers/google-tap.ts +57 -0
- package/src/providers/interactions.ts +182 -0
- package/src/providers/keys.ts +182 -0
- package/{esm/src/providers/mod.js → src/providers/mod.ts} +4 -2
- package/{esm/src/providers/openrouter-mod.js → src/providers/openrouter-mod.ts} +7 -3
- package/src/providers/openrouter-payload.ts +232 -0
- package/src/providers/openrouter.ts +758 -0
- package/src/providers/pcm.ts +37 -0
- package/src/providers/provider.ts +206 -0
- package/src/providers/speech.ts +180 -0
- package/src/providers/sse.ts +59 -0
- package/esm/_dnt.polyfills.d.ts +0 -110
- package/esm/_dnt.polyfills.js +0 -144
- package/esm/_dnt.shims.d.ts +0 -5
- package/esm/_dnt.shims.js +0 -61
- package/esm/mod.js +0 -49
- package/esm/package.json +0 -3
- package/esm/src/cli/commands/profile.d.ts +0 -2
- package/esm/src/cli/commands/profile.js +0 -53
- package/esm/src/cli/commands/run.d.ts +0 -10
- package/esm/src/cli/commands/run.js +0 -55
- package/esm/src/cli/commands/test.d.ts +0 -15
- package/esm/src/cli/commands/test.js +0 -140
- package/esm/src/cli/index.d.ts +0 -4
- package/esm/src/cli/index.js +0 -148
- package/esm/src/cli/matrix/fixtures.d.ts +0 -13
- package/esm/src/cli/matrix/fixtures.js +0 -77
- package/esm/src/cli/matrix/synthesizer.d.ts +0 -29
- package/esm/src/cli/matrix/synthesizer.js +0 -187
- package/esm/src/guardrails/error.d.ts +0 -33
- package/esm/src/guardrails/error.js +0 -114
- package/esm/src/guardrails/injection.d.ts +0 -12
- package/esm/src/guardrails/injection.js +0 -220
- package/esm/src/guardrails/mod.d.ts +0 -14
- package/esm/src/guardrails/mod.js +0 -14
- package/esm/src/guardrails/sanitize.d.ts +0 -22
- package/esm/src/guardrails/sanitize.js +0 -133
- package/esm/src/guardrails/sensitive.d.ts +0 -12
- package/esm/src/guardrails/sensitive.js +0 -88
- package/esm/src/host/mint-trace.d.ts +0 -27
- package/esm/src/host/mint-trace.js +0 -33
- package/esm/src/host/mod.d.ts +0 -13
- package/esm/src/host/reply.d.ts +0 -14
- package/esm/src/host/reply.js +0 -27
- package/esm/src/kernel/engine/boundary.d.ts +0 -10
- package/esm/src/kernel/engine/boundary.js +0 -55
- package/esm/src/kernel/engine/delta.d.ts +0 -8
- package/esm/src/kernel/engine/delta.js +0 -389
- package/esm/src/kernel/engine/hash.d.ts +0 -1
- package/esm/src/kernel/engine/hash.js +0 -9
- package/esm/src/kernel/engine/record.d.ts +0 -2
- package/esm/src/kernel/engine/record.js +0 -7
- package/esm/src/kernel/engine/repair.d.ts +0 -7
- package/esm/src/kernel/engine/repair.js +0 -38
- package/esm/src/kernel/engine/runner/gates.d.ts +0 -4
- package/esm/src/kernel/engine/runner/gates.js +0 -206
- package/esm/src/kernel/engine/runner/mod.d.ts +0 -14
- package/esm/src/kernel/engine/runner/mod.js +0 -103
- package/esm/src/kernel/engine/runner/state.d.ts +0 -16
- package/esm/src/kernel/engine/runner/state.js +0 -8
- package/esm/src/kernel/engine/runner/steps.d.ts +0 -15
- package/esm/src/kernel/engine/runner/steps.js +0 -119
- package/esm/src/kernel/engine/runner/stream.d.ts +0 -11
- package/esm/src/kernel/engine/runner/stream.js +0 -65
- package/esm/src/kernel/engine/runner/tokens.d.ts +0 -3
- package/esm/src/kernel/engine/runner/tokens.js +0 -38
- package/esm/src/kernel/engine/runner/tools.d.ts +0 -13
- package/esm/src/kernel/engine/runner/tools.js +0 -197
- package/esm/src/kernel/engine/runner.js +0 -6
- package/esm/src/kernel/engine/tree.d.ts +0 -2
- package/esm/src/kernel/engine/tree.js +0 -17
- package/esm/src/kernel/mod.d.ts +0 -18
- package/esm/src/kernel/mod.js +0 -16
- package/esm/src/kernel/registry/attachments.d.ts +0 -16
- package/esm/src/kernel/registry/attachments.js +0 -156
- package/esm/src/kernel/registry/catalog.d.ts +0 -31
- package/esm/src/kernel/registry/catalog.js +0 -135
- package/esm/src/kernel/registry/ingress.d.ts +0 -13
- package/esm/src/kernel/registry/ingress.js +0 -163
- package/esm/src/kernel/registry/profiles.d.ts +0 -34
- package/esm/src/kernel/registry/profiles.js +0 -120
- package/esm/src/kernel/registry/provider-request.d.ts +0 -4
- package/esm/src/kernel/registry/provider-request.js +0 -25
- package/esm/src/kernel/registry/resolve.d.ts +0 -19
- package/esm/src/kernel/registry/resolve.js +0 -217
- package/esm/src/kernel/registry/schemas.d.ts +0 -14
- package/esm/src/kernel/registry/schemas.js +0 -23
- package/esm/src/kernel/registry/tools.d.ts +0 -12
- package/esm/src/kernel/registry/tools.js +0 -36
- package/esm/src/kernel/registry/vault.js +0 -18
- package/esm/src/kernel/types.d.ts +0 -521
- package/esm/src/kernel/types.js +0 -10
- package/esm/src/observability/mod.d.ts +0 -12
- package/esm/src/observability/spans.d.ts +0 -16
- package/esm/src/observability/spans.js +0 -56
- package/esm/src/observability/trace-attach.d.ts +0 -16
- package/esm/src/observability/trace-attach.js +0 -67
- package/esm/src/observability/trace-record.d.ts +0 -112
- package/esm/src/observability/trace-record.js +0 -140
- package/esm/src/observability/trace-usage.d.ts +0 -3
- package/esm/src/observability/trace-usage.js +0 -32
- package/esm/src/observability/trace.d.ts +0 -23
- package/esm/src/observability/trace.js +0 -121
- package/esm/src/presets/google.d.ts +0 -50
- package/esm/src/presets/google.js +0 -96
- package/esm/src/presets/mod.d.ts +0 -11
- package/esm/src/presets/mod.js +0 -10
- package/esm/src/providers/create-provider.d.ts +0 -29
- package/esm/src/providers/create-provider.js +0 -38
- package/esm/src/providers/gemini-tape.d.ts +0 -2
- package/esm/src/providers/gemini-tape.js +0 -46
- package/esm/src/providers/google-tap.d.ts +0 -3
- package/esm/src/providers/google-tap.js +0 -48
- package/esm/src/providers/interactions.d.ts +0 -5
- package/esm/src/providers/interactions.js +0 -152
- package/esm/src/providers/keys.d.ts +0 -19
- package/esm/src/providers/keys.js +0 -129
- package/esm/src/providers/mod.d.ts +0 -12
- package/esm/src/providers/openrouter-mod.d.ts +0 -13
- package/esm/src/providers/openrouter-payload.d.ts +0 -32
- package/esm/src/providers/openrouter-payload.js +0 -179
- package/esm/src/providers/openrouter.d.ts +0 -15
- package/esm/src/providers/openrouter.js +0 -589
- package/esm/src/providers/pcm.d.ts +0 -7
- package/esm/src/providers/pcm.js +0 -35
- package/esm/src/providers/provider.d.ts +0 -15
- package/esm/src/providers/provider.js +0 -166
- package/esm/src/providers/speech.d.ts +0 -23
- package/esm/src/providers/speech.js +0 -125
- package/esm/src/providers/sse.d.ts +0 -7
- package/esm/src/providers/sse.js +0 -53
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Kernel ingress: input parts, image pins, and speech-role checks.
|
|
3
|
-
*
|
|
4
|
-
* Owned by the kernel so `resolveTurn` does not import provider adapters.
|
|
5
|
-
*
|
|
6
|
-
* @module
|
|
7
|
-
*/
|
|
8
|
-
import { TheorumError } from '../../guardrails/error.js';
|
|
9
|
-
import { wrapUserData } from '../engine/boundary.js';
|
|
10
|
-
import { synthesizeRepairPrompt } from '../engine/repair.js';
|
|
11
|
-
import { assertAttachmentLimits, requireMediaLimits } from './attachments.js';
|
|
12
|
-
import { geminiKindForMime, mimeAllowed, mimeEssence } from './catalog.js';
|
|
13
|
-
function listedValue(allowed, value) {
|
|
14
|
-
if (!value) {
|
|
15
|
-
return undefined;
|
|
16
|
-
}
|
|
17
|
-
if (!allowed || allowed.length === 0) {
|
|
18
|
-
return value;
|
|
19
|
-
}
|
|
20
|
-
if (allowed.includes(value)) {
|
|
21
|
-
return value;
|
|
22
|
-
}
|
|
23
|
-
return undefined;
|
|
24
|
-
}
|
|
25
|
-
function resolveSlotOrPin(profileId, label, slotValue, pin, allow) {
|
|
26
|
-
if (slotValue !== undefined) {
|
|
27
|
-
const fromSlot = listedValue(allow, slotValue);
|
|
28
|
-
if (!fromSlot) {
|
|
29
|
-
throw new TheorumError(`Unknown image ${label} for ${profileId}`);
|
|
30
|
-
}
|
|
31
|
-
return fromSlot;
|
|
32
|
-
}
|
|
33
|
-
if (pin === undefined) {
|
|
34
|
-
return undefined;
|
|
35
|
-
}
|
|
36
|
-
const fromPin = listedValue(allow, pin);
|
|
37
|
-
if (!fromPin) {
|
|
38
|
-
throw new TheorumError(`Unknown image ${label} for ${profileId}`);
|
|
39
|
-
}
|
|
40
|
-
return fromPin;
|
|
41
|
-
}
|
|
42
|
-
function assertImageRole(profile) {
|
|
43
|
-
const pins = profile.outputs.image;
|
|
44
|
-
if (!pins) {
|
|
45
|
-
throw new TheorumError(`Profile ${profile.id} requests image output but does not set outputs.image`);
|
|
46
|
-
}
|
|
47
|
-
assertExclusiveNativeOutput(profile, 'image');
|
|
48
|
-
return pins;
|
|
49
|
-
}
|
|
50
|
-
function assertSpeechRole(profile) {
|
|
51
|
-
if (!profile.outputs.speech) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
assertExclusiveNativeOutput(profile, 'speech');
|
|
55
|
-
if (profile.outputs.speech.format === 'mp3' && profile.model.protocol === 'geminiInteractions') {
|
|
56
|
-
throw new TheorumError(`Profile ${profile.id}: outputs.speech.format 'mp3' requires protocol 'openAi' ` +
|
|
57
|
-
`(geminiInteractions speech returns PCM and emits WAV)`);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
function assertExclusiveNativeOutput(profile, kind) {
|
|
61
|
-
const other = kind === 'image' ? 'speech' : 'image';
|
|
62
|
-
if (profile.outputs[other]) {
|
|
63
|
-
throw new TheorumError(`Profile ${profile.id} cannot mix outputs.${kind} with outputs.${other}`);
|
|
64
|
-
}
|
|
65
|
-
if (profile.outputs.structured !== null && profile.outputs.structured !== undefined) {
|
|
66
|
-
throw new TheorumError(`Profile ${profile.id} cannot mix structured JSON with native ${kind} output`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
function resolveImageFormat(profile, _model, slots) {
|
|
70
|
-
if (!profile.outputs.image) {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
const pins = assertImageRole(profile);
|
|
74
|
-
const aspectRatio = resolveSlotOrPin(profile.id, 'aspect', slots?.aspectRatio, pins.aspectRatio, profile.inputs.slots?.aspectRatio);
|
|
75
|
-
const size = resolveSlotOrPin(profile.id, 'size', slots?.size, pins.size, profile.inputs.slots?.size);
|
|
76
|
-
if (!(aspectRatio && size)) {
|
|
77
|
-
throw new TheorumError(`Unknown image aspect or size for ${profile.id}`);
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
type: 'image',
|
|
81
|
-
mimeType: pins.mimeType ?? 'image/jpeg',
|
|
82
|
-
aspectRatio,
|
|
83
|
-
size,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function assertGeminiMime(mime) {
|
|
87
|
-
const kind = geminiKindForMime(mime);
|
|
88
|
-
if (!kind) {
|
|
89
|
-
throw new TheorumError(`MIME '${mime}' is not a Gemini input type`);
|
|
90
|
-
}
|
|
91
|
-
return kind;
|
|
92
|
-
}
|
|
93
|
-
function mediaParts(profile, model, blobs, channel) {
|
|
94
|
-
const accept = channel === 'voice' ? profile.inputs.voice?.accept : profile.inputs.attachments?.accept;
|
|
95
|
-
if (!accept) {
|
|
96
|
-
throw new TheorumError(`Profile ${profile.id} does not accept ${channel}`);
|
|
97
|
-
}
|
|
98
|
-
const maxInputImages = profile.outputs.image?.maxInputImages;
|
|
99
|
-
const imageCount = blobs.filter((blob) => geminiKindForMime(blob.mimeType) === 'image').length;
|
|
100
|
-
if (maxInputImages !== undefined && imageCount > maxInputImages) {
|
|
101
|
-
throw new TheorumError(`At most ${maxInputImages} reference images on ${model}`);
|
|
102
|
-
}
|
|
103
|
-
return blobs.map((blob) => {
|
|
104
|
-
const kind = assertGeminiMime(blob.mimeType);
|
|
105
|
-
if (!mimeAllowed(accept, blob.mimeType)) {
|
|
106
|
-
throw new TheorumError(`MIME '${blob.mimeType}' is not accepted on ${profile.id}`);
|
|
107
|
-
}
|
|
108
|
-
const essence = mimeEssence(blob.mimeType);
|
|
109
|
-
return {
|
|
110
|
-
type: kind,
|
|
111
|
-
mimeType: essence === 'image/jpg' ? 'image/jpeg' : essence,
|
|
112
|
-
data: blob.data,
|
|
113
|
-
};
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
function extractTextPart(profile, req) {
|
|
117
|
-
const { text, repair, history } = req.input ?? {};
|
|
118
|
-
if (profile.inputs.text === false) {
|
|
119
|
-
if (text) {
|
|
120
|
-
throw new TheorumError(`Profile ${profile.id} does not accept text input`);
|
|
121
|
-
}
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
let promptText = text;
|
|
125
|
-
if (repair) {
|
|
126
|
-
promptText = synthesizeRepairPrompt({ profile, repair, history });
|
|
127
|
-
}
|
|
128
|
-
if (!promptText) {
|
|
129
|
-
return null;
|
|
130
|
-
}
|
|
131
|
-
return { type: 'text', text: wrapUserData(promptText) };
|
|
132
|
-
}
|
|
133
|
-
function extractMediaParts(profile, model, req) {
|
|
134
|
-
const { attachments, voice } = req.input ?? {};
|
|
135
|
-
const files = attachments ?? [];
|
|
136
|
-
const clips = voice ?? [];
|
|
137
|
-
if (files.length + clips.length > 0) {
|
|
138
|
-
assertAttachmentLimits([...files, ...clips], requireMediaLimits(profile));
|
|
139
|
-
}
|
|
140
|
-
const parts = [];
|
|
141
|
-
if (files.length > 0) {
|
|
142
|
-
parts.push(...mediaParts(profile, model, files, 'attachments'));
|
|
143
|
-
}
|
|
144
|
-
if (clips.length > 0) {
|
|
145
|
-
parts.push(...mediaParts(profile, model, clips, 'voice'));
|
|
146
|
-
}
|
|
147
|
-
return parts;
|
|
148
|
-
}
|
|
149
|
-
function resolveInputParts(profile, model, req) {
|
|
150
|
-
const parts = [];
|
|
151
|
-
const textPart = extractTextPart(profile, req);
|
|
152
|
-
if (textPart) {
|
|
153
|
-
parts.push(textPart);
|
|
154
|
-
}
|
|
155
|
-
parts.push(...extractMediaParts(profile, model, req));
|
|
156
|
-
return parts;
|
|
157
|
-
}
|
|
158
|
-
function assertImageGrounding(profile, model, builtins) {
|
|
159
|
-
if (profile.outputs.image?.allowsGrounding === false && builtins.length > 0) {
|
|
160
|
-
throw new TheorumError(`Grounding tools are not valid on ${model}`);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
export { assertImageGrounding, assertSpeechRole, resolveImageFormat, resolveInputParts };
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime profile registry for host-owned THEORUM profiles.
|
|
3
|
-
*
|
|
4
|
-
* THEORUM ships profile types and defaults, not application profiles. Host apps
|
|
5
|
-
* register their profiles at process startup or test setup.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import type { Profile } from '../types.js';
|
|
10
|
-
/** Host-authored profile definition, with defaults applied to omitted sections. */
|
|
11
|
-
export type ProfileDefinition = {
|
|
12
|
-
id: Profile['id'];
|
|
13
|
-
identity?: Partial<Profile['identity']>;
|
|
14
|
-
model: Partial<Profile['model']> & Pick<Profile['model'], 'allow' | 'config'>;
|
|
15
|
-
tools?: Partial<Profile['tools']>;
|
|
16
|
-
inputs?: Partial<Profile['inputs']>;
|
|
17
|
-
outputs?: Partial<Profile['outputs']>;
|
|
18
|
-
guardrails?: Partial<Profile['guardrails']>;
|
|
19
|
-
};
|
|
20
|
-
/** Define a typed profile with stable defaults for optional properties. */
|
|
21
|
-
declare function defineProfile(input: ProfileDefinition): Profile;
|
|
22
|
-
/** Register one host-owned profile in the process-local registry. */
|
|
23
|
-
declare function registerProfile(profileInput: Profile | ProfileDefinition): void;
|
|
24
|
-
/** Register several host-owned profiles in order. */
|
|
25
|
-
declare function registerProfiles(profilesList: Array<Profile | ProfileDefinition>): void;
|
|
26
|
-
/** Return whether a profile id is currently registered. */
|
|
27
|
-
declare function hasProfile(id: string): boolean;
|
|
28
|
-
/** List all currently registered profiles. */
|
|
29
|
-
declare function listProfiles(): Profile[];
|
|
30
|
-
/** Clear the process-local registry; intended for tests and host reloads. */
|
|
31
|
-
declare function clearProfiles(): void;
|
|
32
|
-
/** Fetch a registered profile or throw a `TheorumError`. */
|
|
33
|
-
declare function getProfile(id: string): Profile;
|
|
34
|
-
export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, };
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime profile registry for host-owned THEORUM profiles.
|
|
3
|
-
*
|
|
4
|
-
* THEORUM ships profile types and defaults, not application profiles. Host apps
|
|
5
|
-
* register their profiles at process startup or test setup.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { TheorumError } from '../../guardrails/error.js';
|
|
10
|
-
const profiles = new Map();
|
|
11
|
-
function assertModelSpecs(profileId, allow, config) {
|
|
12
|
-
for (const id of allow) {
|
|
13
|
-
if (!config[id]) {
|
|
14
|
-
throw new TheorumError(`Profile ${profileId} allowlists '${id}' without a model spec`);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
function buildDefaultIdentity(id, identity) {
|
|
19
|
-
return {
|
|
20
|
-
handle: identity?.handle ?? id,
|
|
21
|
-
chat: identity?.chat,
|
|
22
|
-
system: identity?.system,
|
|
23
|
-
systemByRole: identity?.systemByRole,
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
function buildDefaultModel(profileId, model) {
|
|
27
|
-
assertModelSpecs(profileId, model.allow, model.config);
|
|
28
|
-
return {
|
|
29
|
-
protocol: model.protocol ?? 'geminiInteractions',
|
|
30
|
-
provider: model.provider ?? 'google',
|
|
31
|
-
allow: model.allow,
|
|
32
|
-
config: model.config,
|
|
33
|
-
thinking: model.thinking ?? 'minimal',
|
|
34
|
-
controls: model.controls ?? [],
|
|
35
|
-
maxSteps: model.maxSteps ?? 1,
|
|
36
|
-
key: model.key ?? 'freeA',
|
|
37
|
-
select: model.select,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
function buildDefaultInputs(inputs) {
|
|
41
|
-
return {
|
|
42
|
-
text: inputs?.text ?? true,
|
|
43
|
-
attachments: inputs?.attachments,
|
|
44
|
-
voice: inputs?.voice,
|
|
45
|
-
maxFiles: inputs?.maxFiles,
|
|
46
|
-
maxBytes: inputs?.maxBytes,
|
|
47
|
-
maxTurnBytes: inputs?.maxTurnBytes,
|
|
48
|
-
limitsByMime: inputs?.limitsByMime,
|
|
49
|
-
slots: inputs?.slots,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
function buildDefaultOutputs(outputs) {
|
|
53
|
-
return {
|
|
54
|
-
structured: outputs?.structured ?? null,
|
|
55
|
-
image: outputs?.image,
|
|
56
|
-
speech: outputs?.speech,
|
|
57
|
-
validation: outputs?.validation,
|
|
58
|
-
streaming: outputs?.streaming,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
function buildDefaultGuardrails(guardrails) {
|
|
62
|
-
return {
|
|
63
|
-
quota: guardrails?.quota,
|
|
64
|
-
canary: guardrails?.canary ?? true,
|
|
65
|
-
sanitizeInput: guardrails?.sanitizeInput ?? true,
|
|
66
|
-
redactSensitive: guardrails?.redactSensitive ?? true,
|
|
67
|
-
egress: guardrails?.egress,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
/** Define a typed profile with stable defaults for optional properties. */
|
|
71
|
-
function defineProfile(input) {
|
|
72
|
-
return {
|
|
73
|
-
id: input.id,
|
|
74
|
-
identity: buildDefaultIdentity(input.id, input.identity),
|
|
75
|
-
model: buildDefaultModel(input.id, input.model),
|
|
76
|
-
tools: { allow: input.tools?.allow ?? [] },
|
|
77
|
-
inputs: buildDefaultInputs(input.inputs),
|
|
78
|
-
outputs: buildDefaultOutputs(input.outputs),
|
|
79
|
-
guardrails: buildDefaultGuardrails(input.guardrails),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
/** Register one host-owned profile in the process-local registry. */
|
|
83
|
-
function registerProfile(profileInput) {
|
|
84
|
-
const profile = defineProfile(profileInput);
|
|
85
|
-
assertModelSpecs(profile.id, profile.model.allow, profile.model.config);
|
|
86
|
-
const { attachments, voice, maxFiles, maxBytes, maxTurnBytes } = profile.inputs;
|
|
87
|
-
if (attachments || voice) {
|
|
88
|
-
if (!(maxFiles && maxBytes && maxTurnBytes)) {
|
|
89
|
-
throw new TheorumError(`Profile ${profile.id} must set maxFiles, maxBytes, and maxTurnBytes`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
profiles.set(profile.id, profile);
|
|
93
|
-
}
|
|
94
|
-
/** Register several host-owned profiles in order. */
|
|
95
|
-
function registerProfiles(profilesList) {
|
|
96
|
-
for (const p of profilesList) {
|
|
97
|
-
registerProfile(p);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
/** Return whether a profile id is currently registered. */
|
|
101
|
-
function hasProfile(id) {
|
|
102
|
-
return profiles.has(id);
|
|
103
|
-
}
|
|
104
|
-
/** List all currently registered profiles. */
|
|
105
|
-
function listProfiles() {
|
|
106
|
-
return Array.from(profiles.values());
|
|
107
|
-
}
|
|
108
|
-
/** Clear the process-local registry; intended for tests and host reloads. */
|
|
109
|
-
function clearProfiles() {
|
|
110
|
-
profiles.clear();
|
|
111
|
-
}
|
|
112
|
-
/** Fetch a registered profile or throw a `TheorumError`. */
|
|
113
|
-
function getProfile(id) {
|
|
114
|
-
const profile = profiles.get(id);
|
|
115
|
-
if (!profile) {
|
|
116
|
-
throw new TheorumError(`Unknown profile '${id}'`);
|
|
117
|
-
}
|
|
118
|
-
return profile;
|
|
119
|
-
}
|
|
120
|
-
export { clearProfiles, defineProfile, getProfile, hasProfile, listProfiles, registerProfile, registerProfiles, };
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import type { ProviderCompleteRequest, ResolvedGeneration } from '../types.js';
|
|
2
|
-
/** Build the provider request projection shared by execution and tracing. */
|
|
3
|
-
declare function providerCompleteRequest(generation: ResolvedGeneration, system: string): ProviderCompleteRequest;
|
|
4
|
-
export { providerCompleteRequest };
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/** Build the provider request projection shared by execution and tracing. */
|
|
2
|
-
function providerCompleteRequest(generation, system) {
|
|
3
|
-
return {
|
|
4
|
-
model: generation.model,
|
|
5
|
-
apiId: generation.apiId,
|
|
6
|
-
openRouterId: generation.openRouterId,
|
|
7
|
-
previousInteractionId: generation.previousInteractionId,
|
|
8
|
-
store: generation.store,
|
|
9
|
-
thinking: generation.thinking,
|
|
10
|
-
summaries: generation.summaries,
|
|
11
|
-
maxOutputTokens: generation.maxOutputTokens,
|
|
12
|
-
temperature: generation.temperature,
|
|
13
|
-
builtins: generation.builtins,
|
|
14
|
-
system,
|
|
15
|
-
input: generation.input,
|
|
16
|
-
history: generation.history,
|
|
17
|
-
dynamicTools: generation.dynamicTools,
|
|
18
|
-
dynamicToolLoader: generation.dynamicToolLoader,
|
|
19
|
-
structured: generation.structured,
|
|
20
|
-
image: generation.image,
|
|
21
|
-
speech: generation.speech,
|
|
22
|
-
geminiBucket: generation.geminiBucket,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
export { providerCompleteRequest };
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profile resolution for THEORUM turns.
|
|
3
|
-
*
|
|
4
|
-
* This module validates caller overrides, selects models and tools, normalizes
|
|
5
|
-
* input parts, and produces the provider request state consumed by `runTurn`.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import type { Profile, ProjectedProfile, ResolvedGeneration, ToolId, TurnRequest } from '../types.js';
|
|
10
|
-
declare function assertToolAllowed(profile: Profile, name: ToolId): void;
|
|
11
|
-
/** Resolve a host `TurnRequest` into provider-ready generation state. */
|
|
12
|
-
declare function resolveTurn(req: TurnRequest): {
|
|
13
|
-
profile: Profile;
|
|
14
|
-
generation: ResolvedGeneration;
|
|
15
|
-
};
|
|
16
|
-
/** Project a registered profile into a safe host/UI inspection object. */
|
|
17
|
-
declare function projectProfile(id: Profile['id']): ProjectedProfile;
|
|
18
|
-
declare function pickSystemRole(profile: Profile, requested?: string): string;
|
|
19
|
-
export { assertToolAllowed, pickSystemRole, projectProfile, resolveTurn };
|
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Profile resolution for THEORUM turns.
|
|
3
|
-
*
|
|
4
|
-
* This module validates caller overrides, selects models and tools, normalizes
|
|
5
|
-
* input parts, and produces the provider request state consumed by `runTurn`.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { TheorumError } from '../../guardrails/error.js';
|
|
10
|
-
import { sanitizeTurnRequest } from '../../guardrails/sanitize.js';
|
|
11
|
-
import { mintCanary } from '../engine/boundary.js';
|
|
12
|
-
import { CATALOG, clampThinkingLevel, getTool, listBuiltinIds, requireModelSpec, } from './catalog.js';
|
|
13
|
-
import { assertImageGrounding, assertSpeechRole, resolveImageFormat, resolveInputParts, } from './ingress.js';
|
|
14
|
-
import { getProfile } from './profiles.js';
|
|
15
|
-
import { resolveGeminiBucket } from './vault.js';
|
|
16
|
-
function applyBuiltinMutualExclusions(requested) {
|
|
17
|
-
return requested.filter((id) => {
|
|
18
|
-
const conflicts = getTool(id)?.conflictsWith ?? [];
|
|
19
|
-
return !conflicts.some((other) => requested.includes(other));
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
function firstSelectKey(selectMap) {
|
|
23
|
-
const [key] = Object.keys(selectMap);
|
|
24
|
-
return key;
|
|
25
|
-
}
|
|
26
|
-
function lookupSelectId(profile, select) {
|
|
27
|
-
const { select: selectMap } = profile.model;
|
|
28
|
-
if (!selectMap) {
|
|
29
|
-
return undefined;
|
|
30
|
-
}
|
|
31
|
-
let key = select;
|
|
32
|
-
if (!key) {
|
|
33
|
-
key = firstSelectKey(selectMap);
|
|
34
|
-
}
|
|
35
|
-
if (!key) {
|
|
36
|
-
return undefined;
|
|
37
|
-
}
|
|
38
|
-
return selectMap[key];
|
|
39
|
-
}
|
|
40
|
-
function pickModel(profile, select) {
|
|
41
|
-
if (profile.model.select) {
|
|
42
|
-
const id = lookupSelectId(profile, select);
|
|
43
|
-
if (!(id && profile.model.allow.includes(id))) {
|
|
44
|
-
let label = '';
|
|
45
|
-
if (select) {
|
|
46
|
-
label = select;
|
|
47
|
-
}
|
|
48
|
-
throw new TheorumError(`Unknown model select '${label}' for ${profile.id}`);
|
|
49
|
-
}
|
|
50
|
-
return id;
|
|
51
|
-
}
|
|
52
|
-
const [only] = profile.model.allow;
|
|
53
|
-
if (!only) {
|
|
54
|
-
throw new TheorumError(`Profile ${profile.id} has no models`);
|
|
55
|
-
}
|
|
56
|
-
return only;
|
|
57
|
-
}
|
|
58
|
-
function thinkingFromControl(spec, thinkingOn) {
|
|
59
|
-
if (thinkingOn) {
|
|
60
|
-
return spec.thinking.on;
|
|
61
|
-
}
|
|
62
|
-
return spec.thinking.off;
|
|
63
|
-
}
|
|
64
|
-
function pinnedLevel(pinned, key) {
|
|
65
|
-
if (!key) {
|
|
66
|
-
return undefined;
|
|
67
|
-
}
|
|
68
|
-
return pinned[key];
|
|
69
|
-
}
|
|
70
|
-
function thinkingFromPin(profile, select) {
|
|
71
|
-
const pinned = profile.model.thinking;
|
|
72
|
-
if (typeof pinned === 'string') {
|
|
73
|
-
return pinned;
|
|
74
|
-
}
|
|
75
|
-
if (!pinned) {
|
|
76
|
-
throw new TheorumError(`Profile ${profile.id} must pin thinking or list it in controls`);
|
|
77
|
-
}
|
|
78
|
-
const fromSelect = pinnedLevel(pinned, select);
|
|
79
|
-
if (fromSelect) {
|
|
80
|
-
return fromSelect;
|
|
81
|
-
}
|
|
82
|
-
const fromFirst = pinnedLevel(pinned, firstSelectKey(profile.model.select ?? {}));
|
|
83
|
-
if (fromFirst) {
|
|
84
|
-
return fromFirst;
|
|
85
|
-
}
|
|
86
|
-
throw new TheorumError(`Profile ${profile.id} must pin thinking or list it in controls`);
|
|
87
|
-
}
|
|
88
|
-
function resolveThinking(profile, spec, thinkingOn, select) {
|
|
89
|
-
const raw = profile.model.controls?.includes('thinking')
|
|
90
|
-
? thinkingFromControl(spec, thinkingOn)
|
|
91
|
-
: thinkingFromPin(profile, select);
|
|
92
|
-
return clampThinkingLevel(spec, raw);
|
|
93
|
-
}
|
|
94
|
-
function resolveSummaries(profile, spec, thinkingOn) {
|
|
95
|
-
if (profile.model.controls?.includes('thinking')) {
|
|
96
|
-
if (thinkingOn) {
|
|
97
|
-
return spec.summaries.on;
|
|
98
|
-
}
|
|
99
|
-
return spec.summaries.off;
|
|
100
|
-
}
|
|
101
|
-
return spec.summaries.on;
|
|
102
|
-
}
|
|
103
|
-
function isGatedOn(requested, id) {
|
|
104
|
-
if (!requested) {
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
return requested[id] === true;
|
|
108
|
-
}
|
|
109
|
-
function resolveBuiltins(profile, requested) {
|
|
110
|
-
const allowed = profile.tools.allow.filter((id) => CATALOG.tools[id]?.kind === 'builtin');
|
|
111
|
-
const picked = listBuiltinIds().filter((id) => allowed.includes(id) && isGatedOn(requested, id));
|
|
112
|
-
return applyBuiltinMutualExclusions(picked);
|
|
113
|
-
}
|
|
114
|
-
function resolveCustom(profile, requested) {
|
|
115
|
-
return profile.tools.allow.filter((id) => CATALOG.tools[id]?.kind === 'custom' && isGatedOn(requested, id));
|
|
116
|
-
}
|
|
117
|
-
function assertToolAllowed(profile, name) {
|
|
118
|
-
if (!profile.tools.allow.includes(name)) {
|
|
119
|
-
throw new TheorumError(`Tool '${name}' is not allowed on ${profile.id}`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
function resolveStructured(profile, slots) {
|
|
123
|
-
const { structured } = profile.outputs;
|
|
124
|
-
if (!structured) {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
if (typeof structured === 'string') {
|
|
128
|
-
return structured;
|
|
129
|
-
}
|
|
130
|
-
const value = slots?.[structured.by];
|
|
131
|
-
if (value) {
|
|
132
|
-
const mapped = structured.map[value];
|
|
133
|
-
if (mapped) {
|
|
134
|
-
return mapped;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return structured.fallback;
|
|
138
|
-
}
|
|
139
|
-
/** Resolve a host `TurnRequest` into provider-ready generation state. */
|
|
140
|
-
function resolveTurn(req) {
|
|
141
|
-
const safe = sanitizeTurnRequest(req);
|
|
142
|
-
const input = safe.input ?? {};
|
|
143
|
-
const profile = getProfile(safe.profile);
|
|
144
|
-
const model = pickModel(profile, safe.select);
|
|
145
|
-
const spec = requireModelSpec(profile, model);
|
|
146
|
-
const thinkingOn = safe.thinking === true;
|
|
147
|
-
const builtins = resolveBuiltins(profile, safe.tools);
|
|
148
|
-
assertImageGrounding(profile, model, builtins);
|
|
149
|
-
assertSpeechRole(profile);
|
|
150
|
-
const geminiBucket = profile.model.provider === 'google'
|
|
151
|
-
? resolveGeminiBucket(profile.model.key ?? 'freeA', spec, builtins)
|
|
152
|
-
: undefined;
|
|
153
|
-
return {
|
|
154
|
-
profile,
|
|
155
|
-
generation: {
|
|
156
|
-
model,
|
|
157
|
-
apiId: spec.apiId,
|
|
158
|
-
openRouterId: spec.openRouterId,
|
|
159
|
-
previousInteractionId: safe.previousInteractionId,
|
|
160
|
-
store: safe.store,
|
|
161
|
-
thinking: resolveThinking(profile, spec, thinkingOn, safe.select),
|
|
162
|
-
summaries: resolveSummaries(profile, spec, thinkingOn),
|
|
163
|
-
maxOutputTokens: spec.maxOutputTokens,
|
|
164
|
-
temperature: spec.temperature,
|
|
165
|
-
builtins,
|
|
166
|
-
custom: resolveCustom(profile, safe.tools),
|
|
167
|
-
dynamicTools: safe.dynamicTools,
|
|
168
|
-
dynamicToolLoader: safe.dynamicToolLoader,
|
|
169
|
-
sessionPermissions: safe.sessionPermissions,
|
|
170
|
-
history: input.history,
|
|
171
|
-
maxSteps: profile.model.maxSteps ?? 1,
|
|
172
|
-
structured: resolveStructured(profile, input.slots),
|
|
173
|
-
image: resolveImageFormat(profile, model, input.slots),
|
|
174
|
-
speech: profile.outputs.speech,
|
|
175
|
-
input: resolveInputParts(profile, model, safe),
|
|
176
|
-
geminiBucket,
|
|
177
|
-
canary: profile.guardrails.canary !== false ? mintCanary() : '',
|
|
178
|
-
},
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
function primaryImageSpec(profile) {
|
|
182
|
-
return profile.outputs.image;
|
|
183
|
-
}
|
|
184
|
-
/** Project a registered profile into a safe host/UI inspection object. */
|
|
185
|
-
function projectProfile(id) {
|
|
186
|
-
const profile = getProfile(id);
|
|
187
|
-
const { model, identity, tools, inputs, outputs } = profile;
|
|
188
|
-
const { select, allow, maxSteps, controls } = model;
|
|
189
|
-
const { handle, chat } = identity;
|
|
190
|
-
const { slots } = inputs;
|
|
191
|
-
return {
|
|
192
|
-
id: profile.id,
|
|
193
|
-
handle,
|
|
194
|
-
chat: chat !== false,
|
|
195
|
-
maxSteps: maxSteps ?? 1,
|
|
196
|
-
models: allow,
|
|
197
|
-
select: select ?? null,
|
|
198
|
-
controls: controls ?? [],
|
|
199
|
-
tools: tools.allow.map((name) => ({
|
|
200
|
-
name,
|
|
201
|
-
...(CATALOG.tools[name] ?? { kind: 'custom', ui: true }),
|
|
202
|
-
})),
|
|
203
|
-
inputs,
|
|
204
|
-
slots: slots ?? {},
|
|
205
|
-
outputs,
|
|
206
|
-
image: primaryImageSpec(profile),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
function pickSystemRole(profile, requested) {
|
|
210
|
-
const { identity } = profile;
|
|
211
|
-
const { handle, systemByRole } = identity;
|
|
212
|
-
if (requested && systemByRole && Object.hasOwn(systemByRole, requested)) {
|
|
213
|
-
return requested;
|
|
214
|
-
}
|
|
215
|
-
return handle;
|
|
216
|
-
}
|
|
217
|
-
export { assertToolAllowed, pickSystemRole, projectProfile, resolveTurn };
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime structured-output schema registry.
|
|
3
|
-
*
|
|
4
|
-
* Host apps register schemas by id, then reference those ids from profile output
|
|
5
|
-
* declarations.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import type { StructuredSpec } from '../types.js';
|
|
10
|
-
/** Register a host-owned structured output schema. */
|
|
11
|
-
declare function registerStructured(id: string, spec: StructuredSpec): void;
|
|
12
|
-
/** Fetch a registered structured output schema or throw a `TheorumError`. */
|
|
13
|
-
declare function getStructured(id: string): StructuredSpec;
|
|
14
|
-
export { getStructured, registerStructured };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Runtime structured-output schema registry.
|
|
3
|
-
*
|
|
4
|
-
* Host apps register schemas by id, then reference those ids from profile output
|
|
5
|
-
* declarations.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { TheorumError } from '../../guardrails/error.js';
|
|
10
|
-
const schemas = new Map();
|
|
11
|
-
/** Register a host-owned structured output schema. */
|
|
12
|
-
function registerStructured(id, spec) {
|
|
13
|
-
schemas.set(id, spec);
|
|
14
|
-
}
|
|
15
|
-
/** Fetch a registered structured output schema or throw a `TheorumError`. */
|
|
16
|
-
function getStructured(id) {
|
|
17
|
-
const spec = schemas.get(id);
|
|
18
|
-
if (!spec) {
|
|
19
|
-
throw new TheorumError(`Unknown structured schema '${id}'`);
|
|
20
|
-
}
|
|
21
|
-
return spec;
|
|
22
|
-
}
|
|
23
|
-
export { getStructured, registerStructured };
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic built-in custom tool executor.
|
|
3
|
-
*
|
|
4
|
-
* Static custom tools are intentionally minimal. Application-specific tools
|
|
5
|
-
* should be supplied as dynamic declarations with host-owned handlers.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import type { CustomToolId, Profile, ToolEnvelope } from '../types.js';
|
|
10
|
-
/** Execute a static tool after enforcing the profile allowlist. */
|
|
11
|
-
declare function executeTool(profile: Profile, name: CustomToolId, args: Record<string, unknown>): ToolEnvelope;
|
|
12
|
-
export { executeTool };
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Generic built-in custom tool executor.
|
|
3
|
-
*
|
|
4
|
-
* Static custom tools are intentionally minimal. Application-specific tools
|
|
5
|
-
* should be supplied as dynamic declarations with host-owned handlers.
|
|
6
|
-
*
|
|
7
|
-
* @module
|
|
8
|
-
*/
|
|
9
|
-
import { getTool } from './catalog.js';
|
|
10
|
-
import { assertToolAllowed } from './resolve.js';
|
|
11
|
-
function executeAskUser(args) {
|
|
12
|
-
const { kind, prompt } = args;
|
|
13
|
-
if (kind !== 'confirm' && kind !== 'choice' && kind !== 'text') {
|
|
14
|
-
return { status: 'error', finding: 'askUser.kind must be confirm, choice, or text' };
|
|
15
|
-
}
|
|
16
|
-
if (typeof prompt !== 'string' || !prompt.trim()) {
|
|
17
|
-
return { status: 'error', finding: 'askUser.prompt is required' };
|
|
18
|
-
}
|
|
19
|
-
return {
|
|
20
|
-
status: 'pause',
|
|
21
|
-
finding: prompt,
|
|
22
|
-
data: { ...args, schema: getTool('askUser')?.schema },
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
/** Execute a static tool after enforcing the profile allowlist. */
|
|
26
|
-
function executeTool(profile, name, args) {
|
|
27
|
-
assertToolAllowed(profile, name);
|
|
28
|
-
if (name === 'askUser') {
|
|
29
|
-
return executeAskUser(args);
|
|
30
|
-
}
|
|
31
|
-
return {
|
|
32
|
-
status: 'error',
|
|
33
|
-
finding: `Tool '${name}' has no kernel executor; pass a dynamic tool handler instead.`,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
export { executeTool };
|