theorum 0.1.2 → 0.1.3
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 +62 -27
- package/docs/AGENT_PROFILE_CONTRACT.md +45 -18
- package/docs/CLI_SPEC.md +2 -2
- package/docs/SECRETS.md +27 -22
- package/esm/_dnt.polyfills.d.ts +99 -0
- package/esm/_dnt.polyfills.js +130 -1
- package/esm/mod.d.ts +19 -3
- package/esm/mod.js +17 -3
- package/esm/src/cli/commands/profile.d.ts +2 -0
- package/esm/src/cli/commands/profile.js +53 -0
- package/esm/src/cli/commands/run.d.ts +10 -0
- package/esm/src/cli/commands/run.js +55 -0
- package/esm/src/cli/commands/test.d.ts +15 -0
- package/esm/src/cli/commands/test.js +140 -0
- package/esm/src/cli/index.d.ts +4 -0
- package/esm/src/cli/index.js +148 -0
- package/esm/src/cli/matrix/fixtures.d.ts +13 -0
- package/esm/src/cli/matrix/fixtures.js +77 -0
- package/esm/src/cli/matrix/synthesizer.d.ts +29 -0
- package/esm/src/cli/matrix/synthesizer.js +187 -0
- package/esm/src/guardrails/error.d.ts +1 -3
- package/esm/src/guardrails/error.js +4 -6
- package/esm/src/guardrails/mod.d.ts +1 -1
- package/esm/src/guardrails/mod.js +1 -1
- package/esm/src/guardrails/sanitize.js +1 -1
- package/esm/src/host/mint-trace.d.ts +27 -0
- package/esm/src/host/mint-trace.js +33 -0
- package/esm/src/host/mod.d.ts +13 -0
- package/esm/src/host/mod.js +12 -0
- package/esm/src/host/reply.d.ts +14 -0
- package/esm/src/host/reply.js +27 -0
- package/esm/src/kernel/engine/delta.js +31 -4
- package/esm/src/kernel/engine/repair.d.ts +1 -3
- package/esm/src/kernel/engine/repair.js +1 -1
- package/esm/src/kernel/engine/runner/gates.d.ts +4 -0
- package/esm/src/kernel/engine/runner/gates.js +206 -0
- package/esm/src/kernel/engine/runner/mod.d.ts +14 -0
- package/esm/src/kernel/engine/runner/mod.js +103 -0
- package/esm/src/kernel/engine/runner/state.d.ts +16 -0
- package/esm/src/kernel/engine/runner/state.js +8 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +15 -0
- package/esm/src/kernel/engine/runner/steps.js +119 -0
- package/esm/src/kernel/engine/runner/stream.d.ts +11 -0
- package/esm/src/kernel/engine/runner/stream.js +65 -0
- package/esm/src/kernel/engine/runner/tokens.d.ts +3 -0
- package/esm/src/kernel/engine/runner/tokens.js +38 -0
- package/esm/src/kernel/engine/runner/tools.d.ts +13 -0
- package/esm/src/kernel/engine/runner/tools.js +197 -0
- package/esm/src/kernel/engine/runner.d.ts +1 -9
- package/esm/src/kernel/engine/runner.js +1 -726
- package/esm/src/kernel/mod.d.ts +3 -1
- package/esm/src/kernel/mod.js +2 -1
- package/esm/src/{providers → kernel/registry}/attachments.d.ts +2 -3
- package/esm/src/{providers → kernel/registry}/attachments.js +6 -6
- package/esm/src/kernel/registry/catalog.d.ts +28 -21
- package/esm/src/kernel/registry/catalog.js +55 -133
- package/esm/src/kernel/registry/ingress.d.ts +13 -0
- package/esm/src/kernel/registry/ingress.js +163 -0
- package/esm/src/kernel/registry/profiles.d.ts +2 -4
- package/esm/src/kernel/registry/profiles.js +14 -5
- package/esm/src/kernel/registry/provider-request.d.ts +4 -0
- package/esm/src/kernel/registry/provider-request.js +25 -0
- package/esm/src/kernel/registry/resolve.d.ts +0 -1
- package/esm/src/kernel/registry/resolve.js +35 -53
- package/esm/src/kernel/registry/tools.js +2 -2
- package/esm/src/kernel/registry/vault.d.ts +11 -0
- package/esm/src/kernel/registry/vault.js +18 -0
- package/esm/src/kernel/types.d.ts +102 -78
- package/esm/src/observability/trace-attach.js +6 -20
- package/esm/src/presets/google.d.ts +50 -0
- package/esm/src/presets/google.js +96 -0
- package/esm/src/presets/mod.d.ts +11 -0
- package/esm/src/presets/mod.js +10 -0
- package/esm/src/providers/create-provider.d.ts +29 -0
- package/esm/src/providers/create-provider.js +38 -0
- package/esm/src/providers/gemini-tape.d.ts +1 -2
- package/esm/src/providers/gemini-tape.js +1 -1
- package/esm/src/providers/interactions.js +41 -16
- package/esm/src/{guardrails → providers}/keys.d.ts +10 -3
- package/esm/src/{guardrails → providers}/keys.js +10 -13
- package/esm/src/providers/mod.d.ts +4 -7
- package/esm/src/providers/mod.js +2 -5
- package/esm/src/providers/openrouter-mod.d.ts +13 -0
- package/esm/src/providers/openrouter-mod.js +12 -0
- package/esm/src/providers/openrouter-payload.d.ts +11 -3
- package/esm/src/providers/openrouter-payload.js +28 -26
- package/esm/src/providers/openrouter.d.ts +5 -7
- package/esm/src/providers/openrouter.js +488 -231
- package/esm/src/providers/pcm.d.ts +7 -0
- package/esm/src/providers/pcm.js +35 -0
- package/esm/src/providers/provider.d.ts +3 -1
- package/esm/src/providers/provider.js +45 -2
- package/esm/src/providers/speech.d.ts +23 -0
- package/esm/src/providers/speech.js +125 -0
- package/package.json +20 -3
- package/esm/src/providers/media.d.ts +0 -5
- package/esm/src/providers/media.js +0 -125
- package/esm/src/providers/tts.d.ts +0 -24
- package/esm/src/providers/tts.js +0 -144
|
@@ -7,22 +7,17 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
import { TheorumError } from '../../guardrails/error.js';
|
|
10
|
-
import { resolveGeminiBucket } from '../../guardrails/keys.js';
|
|
11
10
|
import { sanitizeTurnRequest } from '../../guardrails/sanitize.js';
|
|
12
|
-
import { assertImageGrounding, resolveImageFormat, resolveInputParts, } from '../../providers/media.js';
|
|
13
11
|
import { mintCanary } from '../engine/boundary.js';
|
|
14
|
-
import { CATALOG, clampThinkingLevel,
|
|
12
|
+
import { CATALOG, clampThinkingLevel, getTool, listBuiltinIds, requireModelSpec, } from './catalog.js';
|
|
13
|
+
import { assertImageGrounding, assertSpeechRole, resolveImageFormat, resolveInputParts, } from './ingress.js';
|
|
15
14
|
import { getProfile } from './profiles.js';
|
|
16
|
-
|
|
15
|
+
import { resolveGeminiBucket } from './vault.js';
|
|
17
16
|
function applyBuiltinMutualExclusions(requested) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
if (maps && (search || urlContext)) {
|
|
23
|
-
return requested.filter((id) => id !== 'googleMaps');
|
|
24
|
-
}
|
|
25
|
-
return requested;
|
|
17
|
+
return requested.filter((id) => {
|
|
18
|
+
const conflicts = getTool(id)?.conflictsWith ?? [];
|
|
19
|
+
return !conflicts.some((other) => requested.includes(other));
|
|
20
|
+
});
|
|
26
21
|
}
|
|
27
22
|
function firstSelectKey(selectMap) {
|
|
28
23
|
const [key] = Object.keys(selectMap);
|
|
@@ -60,12 +55,11 @@ function pickModel(profile, select) {
|
|
|
60
55
|
}
|
|
61
56
|
return only;
|
|
62
57
|
}
|
|
63
|
-
function thinkingFromControl(
|
|
64
|
-
const catalog = modelEntry(modelId);
|
|
58
|
+
function thinkingFromControl(spec, thinkingOn) {
|
|
65
59
|
if (thinkingOn) {
|
|
66
|
-
return
|
|
60
|
+
return spec.thinking.on;
|
|
67
61
|
}
|
|
68
|
-
return
|
|
62
|
+
return spec.thinking.off;
|
|
69
63
|
}
|
|
70
64
|
function pinnedLevel(pinned, key) {
|
|
71
65
|
if (!key) {
|
|
@@ -91,25 +85,20 @@ function thinkingFromPin(profile, select) {
|
|
|
91
85
|
}
|
|
92
86
|
throw new TheorumError(`Profile ${profile.id} must pin thinking or list it in controls`);
|
|
93
87
|
}
|
|
94
|
-
function resolveThinking(profile,
|
|
88
|
+
function resolveThinking(profile, spec, thinkingOn, select) {
|
|
95
89
|
const raw = profile.model.controls?.includes('thinking')
|
|
96
|
-
? thinkingFromControl(
|
|
90
|
+
? thinkingFromControl(spec, thinkingOn)
|
|
97
91
|
: thinkingFromPin(profile, select);
|
|
98
|
-
return clampThinkingLevel(
|
|
92
|
+
return clampThinkingLevel(spec, raw);
|
|
99
93
|
}
|
|
100
|
-
function resolveSummaries(profile,
|
|
101
|
-
const override = profile.model.override?.[modelId]?.summaries;
|
|
102
|
-
if (override) {
|
|
103
|
-
return override;
|
|
104
|
-
}
|
|
105
|
-
const entry = modelEntry(modelId);
|
|
94
|
+
function resolveSummaries(profile, spec, thinkingOn) {
|
|
106
95
|
if (profile.model.controls?.includes('thinking')) {
|
|
107
96
|
if (thinkingOn) {
|
|
108
|
-
return
|
|
97
|
+
return spec.summaries.on;
|
|
109
98
|
}
|
|
110
|
-
return
|
|
99
|
+
return spec.summaries.off;
|
|
111
100
|
}
|
|
112
|
-
return
|
|
101
|
+
return spec.summaries.on;
|
|
113
102
|
}
|
|
114
103
|
function isGatedOn(requested, id) {
|
|
115
104
|
if (!requested) {
|
|
@@ -119,7 +108,7 @@ function isGatedOn(requested, id) {
|
|
|
119
108
|
}
|
|
120
109
|
function resolveBuiltins(profile, requested) {
|
|
121
110
|
const allowed = profile.tools.allow.filter((id) => CATALOG.tools[id]?.kind === 'builtin');
|
|
122
|
-
const picked =
|
|
111
|
+
const picked = listBuiltinIds().filter((id) => allowed.includes(id) && isGatedOn(requested, id));
|
|
123
112
|
return applyBuiltinMutualExclusions(picked);
|
|
124
113
|
}
|
|
125
114
|
function resolveCustom(profile, requested) {
|
|
@@ -147,34 +136,32 @@ function resolveStructured(profile, slots) {
|
|
|
147
136
|
}
|
|
148
137
|
return structured.fallback;
|
|
149
138
|
}
|
|
150
|
-
function generationLimits(profile, model) {
|
|
151
|
-
const catalog = modelEntry(model);
|
|
152
|
-
const ov = profile.model.override?.[model];
|
|
153
|
-
return {
|
|
154
|
-
maxOutputTokens: ov?.maxOutputTokens ?? catalog.maxOutputTokens,
|
|
155
|
-
temperature: ov?.temperature ?? catalog.temperature,
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
139
|
/** Resolve a host `TurnRequest` into provider-ready generation state. */
|
|
159
140
|
function resolveTurn(req) {
|
|
160
141
|
const safe = sanitizeTurnRequest(req);
|
|
161
142
|
const input = safe.input ?? {};
|
|
162
143
|
const profile = getProfile(safe.profile);
|
|
163
144
|
const model = pickModel(profile, safe.select);
|
|
145
|
+
const spec = requireModelSpec(profile, model);
|
|
164
146
|
const thinkingOn = safe.thinking === true;
|
|
165
|
-
const limits = generationLimits(profile, model);
|
|
166
147
|
const builtins = resolveBuiltins(profile, safe.tools);
|
|
167
|
-
assertImageGrounding(model, builtins);
|
|
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;
|
|
168
153
|
return {
|
|
169
154
|
profile,
|
|
170
155
|
generation: {
|
|
171
156
|
model,
|
|
157
|
+
apiId: spec.apiId,
|
|
158
|
+
openRouterId: spec.openRouterId,
|
|
172
159
|
previousInteractionId: safe.previousInteractionId,
|
|
173
160
|
store: safe.store,
|
|
174
|
-
thinking: resolveThinking(profile,
|
|
175
|
-
summaries: resolveSummaries(profile,
|
|
176
|
-
maxOutputTokens:
|
|
177
|
-
temperature:
|
|
161
|
+
thinking: resolveThinking(profile, spec, thinkingOn, safe.select),
|
|
162
|
+
summaries: resolveSummaries(profile, spec, thinkingOn),
|
|
163
|
+
maxOutputTokens: spec.maxOutputTokens,
|
|
164
|
+
temperature: spec.temperature,
|
|
178
165
|
builtins,
|
|
179
166
|
custom: resolveCustom(profile, safe.tools),
|
|
180
167
|
dynamicTools: safe.dynamicTools,
|
|
@@ -184,21 +171,16 @@ function resolveTurn(req) {
|
|
|
184
171
|
maxSteps: profile.model.maxSteps ?? 1,
|
|
185
172
|
structured: resolveStructured(profile, input.slots),
|
|
186
173
|
image: resolveImageFormat(profile, model, input.slots),
|
|
187
|
-
|
|
174
|
+
speech: profile.outputs.speech,
|
|
188
175
|
input: resolveInputParts(profile, model, safe),
|
|
189
|
-
geminiBucket
|
|
176
|
+
geminiBucket,
|
|
190
177
|
canary: profile.guardrails.canary !== false ? mintCanary() : '',
|
|
191
178
|
},
|
|
192
179
|
};
|
|
193
180
|
}
|
|
194
|
-
function primaryImageSpec(
|
|
195
|
-
|
|
196
|
-
if (!primary) {
|
|
197
|
-
return undefined;
|
|
198
|
-
}
|
|
199
|
-
return modelEntry(primary).image;
|
|
181
|
+
function primaryImageSpec(profile) {
|
|
182
|
+
return profile.outputs.image;
|
|
200
183
|
}
|
|
201
|
-
/** UI projection: catalog ∩ profile. Swatches are not included. */
|
|
202
184
|
/** Project a registered profile into a safe host/UI inspection object. */
|
|
203
185
|
function projectProfile(id) {
|
|
204
186
|
const profile = getProfile(id);
|
|
@@ -221,7 +203,7 @@ function projectProfile(id) {
|
|
|
221
203
|
inputs,
|
|
222
204
|
slots: slots ?? {},
|
|
223
205
|
outputs,
|
|
224
|
-
image: primaryImageSpec(
|
|
206
|
+
image: primaryImageSpec(profile),
|
|
225
207
|
};
|
|
226
208
|
}
|
|
227
209
|
function pickSystemRole(profile, requested) {
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
import {
|
|
9
|
+
import { getTool } from './catalog.js';
|
|
10
10
|
import { assertToolAllowed } from './resolve.js';
|
|
11
11
|
function executeAskUser(args) {
|
|
12
12
|
const { kind, prompt } = args;
|
|
@@ -19,7 +19,7 @@ function executeAskUser(args) {
|
|
|
19
19
|
return {
|
|
20
20
|
status: 'pause',
|
|
21
21
|
finding: prompt,
|
|
22
|
-
data: { ...args, schema:
|
|
22
|
+
data: { ...args, schema: getTool('askUser')?.schema },
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
/** Execute a static tool after enforcing the profile allowlist. */
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini vault slot selection for Google Interactions transport.
|
|
3
|
+
*
|
|
4
|
+
* Host-owned policy over `ModelSpec.key` / `keyBuiltins`. Pure; no network.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
import type { BuiltinToolId, GeminiBucket, GeminiFreeBucket, ModelSpec } from '../types.js';
|
|
9
|
+
/** Pick the vault slot for a turn from profile key, model pin, and builtins. */
|
|
10
|
+
declare function resolveGeminiBucket(profileKey: GeminiFreeBucket, spec: ModelSpec, builtins: BuiltinToolId[]): GeminiBucket;
|
|
11
|
+
export { resolveGeminiBucket };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gemini vault slot selection for Google Interactions transport.
|
|
3
|
+
*
|
|
4
|
+
* Host-owned policy over `ModelSpec.key` / `keyBuiltins`. Pure; no network.
|
|
5
|
+
*
|
|
6
|
+
* @module
|
|
7
|
+
*/
|
|
8
|
+
/** Pick the vault slot for a turn from profile key, model pin, and builtins. */
|
|
9
|
+
function resolveGeminiBucket(profileKey, spec, builtins) {
|
|
10
|
+
if (spec.key) {
|
|
11
|
+
return spec.key;
|
|
12
|
+
}
|
|
13
|
+
if (builtins.some((id) => !spec.keyBuiltins.includes(id))) {
|
|
14
|
+
return 'paid';
|
|
15
|
+
}
|
|
16
|
+
return profileKey;
|
|
17
|
+
}
|
|
18
|
+
export { resolveGeminiBucket };
|
|
@@ -8,17 +8,15 @@
|
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
10
|
/** Model reasoning effort level normalized across provider adapters. */
|
|
11
|
-
export type ThinkingLevel = 'minimal' | 'low' | 'medium' | 'high';
|
|
12
|
-
/**
|
|
13
|
-
export type
|
|
14
|
-
/**
|
|
15
|
-
export type
|
|
16
|
-
/**
|
|
17
|
-
export type
|
|
18
|
-
/**
|
|
19
|
-
export type
|
|
20
|
-
/** Host-owned custom tool id. */
|
|
21
|
-
export type CustomToolId = StandardCustomToolId | (string & {});
|
|
11
|
+
export type ThinkingLevel = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
|
|
12
|
+
/** Any host-declared model id. */
|
|
13
|
+
export type ModelId = string;
|
|
14
|
+
/** Provider-projected builtin tool id (registered by presets/adapters). */
|
|
15
|
+
export type BuiltinToolId = string;
|
|
16
|
+
/** Harness custom tool that ships with THEORUM. */
|
|
17
|
+
export type HarnessToolId = 'askUser';
|
|
18
|
+
/** Host-owned or harness custom tool id. */
|
|
19
|
+
export type CustomToolId = HarnessToolId | (string & {});
|
|
22
20
|
/** Any tool id accepted by profile allowlists and per-turn gates. */
|
|
23
21
|
export type ToolId = BuiltinToolId | CustomToolId;
|
|
24
22
|
/** Id of a host-registered structured output schema. */
|
|
@@ -35,10 +33,23 @@ export type GeminiFreeBucket = Exclude<GeminiBucket, 'paid'>;
|
|
|
35
33
|
export type ChatRole = 'system' | 'user' | 'assistant';
|
|
36
34
|
/** Profile-level control a caller may toggle at turn time. */
|
|
37
35
|
export type ControlId = 'thinking';
|
|
38
|
-
/**
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Image-role output pins owned by the host profile.
|
|
38
|
+
* The image model itself lives in `model.allow` / `model.config`.
|
|
39
|
+
* Aspect/size/mime values are host strings (presets/apps own the vocabularies).
|
|
40
|
+
*/
|
|
41
|
+
export interface ProfileImageSpec {
|
|
42
|
+
/** Default aspect ratio when the turn does not set `slots.aspectRatio`. */
|
|
43
|
+
aspectRatio?: string;
|
|
44
|
+
/** Default size / resolution when the turn does not set `slots.size`. */
|
|
45
|
+
size?: string;
|
|
46
|
+
/** Output MIME for generated images. */
|
|
47
|
+
mimeType?: string;
|
|
48
|
+
/** When false, grounding builtins are rejected on this profile. */
|
|
49
|
+
allowsGrounding?: boolean;
|
|
50
|
+
/** Cap on reference images in one turn. */
|
|
51
|
+
maxInputImages?: number;
|
|
52
|
+
}
|
|
42
53
|
/** Public event types emitted by `runTurn` and provider adapters. */
|
|
43
54
|
export type TurnEventType = 'thought' | 'text' | 'tool' | 'structured' | 'media' | 'grounding' | 'evidence' | 'tokens' | 'done' | 'error';
|
|
44
55
|
/** Provider thinking levels used when a boolean thinking control is on or off. */
|
|
@@ -51,44 +62,48 @@ export interface SummaryMap {
|
|
|
51
62
|
on: 'auto' | 'none';
|
|
52
63
|
off: 'auto' | 'none';
|
|
53
64
|
}
|
|
54
|
-
/**
|
|
55
|
-
export interface
|
|
56
|
-
maxInputImages: number;
|
|
57
|
-
inputMimes: string[];
|
|
58
|
-
sizes: ImageSize[];
|
|
59
|
-
aspectRatios: ImageAspectRatio[];
|
|
60
|
-
outputMime: string;
|
|
61
|
-
allowsGrounding: boolean;
|
|
62
|
-
}
|
|
63
|
-
/** Static metadata THEORUM needs to safely call a model id. */
|
|
64
|
-
export interface ModelCatalogEntry {
|
|
65
|
+
/** Host-declared metadata THEORUM needs to call a model safely. */
|
|
66
|
+
export interface ModelSpec {
|
|
65
67
|
apiId: string;
|
|
66
68
|
/** Provider-native id for OpenRouter-compatible gateways. Defaults to `google/${apiId}`. */
|
|
67
69
|
openRouterId?: string;
|
|
68
70
|
thinking: ThinkingMap;
|
|
69
|
-
/** Levels this model accepts
|
|
71
|
+
/** Levels this model accepts. Illegal values are clamped via `thinkingLevels`. */
|
|
70
72
|
thinkingLevels: ThinkingLevel[];
|
|
71
73
|
summaries: SummaryMap;
|
|
72
74
|
maxOutputTokens: number;
|
|
73
75
|
temperature: number;
|
|
74
|
-
/**
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Builtins that may use `profile.model.key`.
|
|
78
|
+
* Any other enabled builtin selects the overflow vault slot (`paid`).
|
|
79
|
+
* Host-owned policy — THEORUM does not infer tool pricing.
|
|
80
|
+
*/
|
|
81
|
+
keyBuiltins: BuiltinToolId[];
|
|
82
|
+
/**
|
|
83
|
+
* Optional vault slot for this model. When set, overrides `profile.model.key`
|
|
84
|
+
* (and builtin routing). Host-owned — e.g. pin image models to `paid`.
|
|
85
|
+
*/
|
|
86
|
+
key?: GeminiBucket;
|
|
87
|
+
}
|
|
88
|
+
/** Static metadata for harness, preset, and host-registered tools. */
|
|
79
89
|
export interface ToolCatalogEntry {
|
|
80
90
|
kind: 'builtin' | 'custom';
|
|
81
91
|
ui: boolean;
|
|
82
92
|
schema?: Record<string, unknown>;
|
|
93
|
+
/** Interactions API `tools[].type` when this builtin is projected. */
|
|
94
|
+
interactionsType?: string;
|
|
95
|
+
/** OpenRouter plugin id enabled when this builtin is on. */
|
|
96
|
+
openRouterPlugin?: string;
|
|
97
|
+
/** Drop this builtin when any listed sibling builtin is also requested. */
|
|
98
|
+
conflictsWith?: ToolId[];
|
|
83
99
|
}
|
|
84
100
|
/** Host-registered structured output schema and enforcement mode. */
|
|
85
101
|
export interface StructuredSpec {
|
|
86
102
|
enforced: 'responseFormat' | 'prompt';
|
|
87
103
|
jsonSchema?: Record<string, unknown>;
|
|
88
104
|
}
|
|
89
|
-
/** In-memory
|
|
105
|
+
/** In-memory tool catalog shape. */
|
|
90
106
|
export interface Catalog {
|
|
91
|
-
models: Record<ModelId, ModelCatalogEntry>;
|
|
92
107
|
tools: Record<ToolId, ToolCatalogEntry>;
|
|
93
108
|
}
|
|
94
109
|
/** Per-turn file, byte, and MIME-specific input limits. */
|
|
@@ -114,16 +129,6 @@ export interface StructuredBySlot {
|
|
|
114
129
|
map: Record<string, string>;
|
|
115
130
|
fallback: string;
|
|
116
131
|
}
|
|
117
|
-
/** Legacy-compatible model selection block used by profile builders. */
|
|
118
|
-
export interface ProfileModels {
|
|
119
|
-
allow: ModelId[];
|
|
120
|
-
select?: Record<string, ModelId>;
|
|
121
|
-
/** Pinned level when `thinking` is not in `controls`. */
|
|
122
|
-
thinking?: ThinkingLevel | Record<string, ThinkingLevel>;
|
|
123
|
-
override?: Partial<Record<ModelId, Partial<Pick<ModelCatalogEntry, 'maxOutputTokens' | 'temperature'> & {
|
|
124
|
-
summaries?: 'auto' | 'none';
|
|
125
|
-
}>>>;
|
|
126
|
-
}
|
|
127
132
|
/** Result returned by a profile output validator. */
|
|
128
133
|
export interface ValidationResult {
|
|
129
134
|
isValid: boolean;
|
|
@@ -140,14 +145,26 @@ export interface ProfileValidationSpec {
|
|
|
140
145
|
maxRetries?: number;
|
|
141
146
|
repairGuidance?: string;
|
|
142
147
|
}
|
|
143
|
-
/**
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Audio container for speech generation output.
|
|
150
|
+
* - `openAi` speech (`/audio/speech`): sent as wire `response_format`.
|
|
151
|
+
* - `geminiInteractions`: only `pcm` (or omit). Google returns PCM; THEORUM emits WAV.
|
|
152
|
+
* `mp3` is rejected at resolve.
|
|
153
|
+
*/
|
|
154
|
+
export type SpeechAudioFormat = 'pcm' | 'mp3';
|
|
155
|
+
/**
|
|
156
|
+
* Speech-role output pins owned by the host profile.
|
|
157
|
+
* The speech model itself lives in `model.allow` / `model.config`.
|
|
158
|
+
* Namespaced under `outputs.speech` so `voice` here is the TTS voice id,
|
|
159
|
+
* not ingress audio (`inputs.voice`).
|
|
160
|
+
*/
|
|
161
|
+
export interface ProfileSpeechSpec {
|
|
162
|
+
voice?: string;
|
|
163
|
+
/**
|
|
164
|
+
* Output container. `pcm` (default) → WAV media on both transports.
|
|
165
|
+
* `mp3` requires `protocol: 'openAi'` speech; rejected on Interactions.
|
|
166
|
+
*/
|
|
167
|
+
format?: SpeechAudioFormat;
|
|
151
168
|
}
|
|
152
169
|
/** Stream delivery controls enforced by the kernel. */
|
|
153
170
|
export interface ProfileStreamingSpec {
|
|
@@ -194,17 +211,15 @@ export interface ProfileGuardrailsSpec {
|
|
|
194
211
|
export interface ProfileModelSpec {
|
|
195
212
|
protocol: 'geminiInteractions' | 'openAi';
|
|
196
213
|
provider: 'google' | 'openrouter';
|
|
214
|
+
/** Ids this profile may select. Each id must exist in `config`. */
|
|
197
215
|
allow: ModelId[];
|
|
216
|
+
/** Host-owned wire config keyed by the same ids used in `allow` / `select`. */
|
|
217
|
+
config: Record<ModelId, ModelSpec>;
|
|
198
218
|
select?: Record<string, ModelId>;
|
|
199
219
|
thinking?: ThinkingLevel | Record<string, ThinkingLevel>;
|
|
200
220
|
controls?: ControlId[];
|
|
201
221
|
maxSteps?: number;
|
|
202
222
|
key?: GeminiFreeBucket;
|
|
203
|
-
override?: Record<string, {
|
|
204
|
-
maxOutputTokens?: number;
|
|
205
|
-
temperature?: number;
|
|
206
|
-
summaries?: 'auto' | 'none';
|
|
207
|
-
}>;
|
|
208
223
|
}
|
|
209
224
|
/** Text, attachment, voice, slot, and size rules for a profile. */
|
|
210
225
|
export interface ProfileInputsSpec {
|
|
@@ -221,11 +236,13 @@ export interface ProfileInputsSpec {
|
|
|
221
236
|
limitsByMime?: Record<string, number>;
|
|
222
237
|
slots?: Record<string, string[]>;
|
|
223
238
|
}
|
|
224
|
-
/** Output schema,
|
|
239
|
+
/** Output schema, image, speech, validation, and stream rules for a profile. */
|
|
225
240
|
export interface ProfileOutputsSpec {
|
|
226
241
|
structured?: StructuredSchemaId | StructuredBySlot | null;
|
|
227
|
-
|
|
228
|
-
|
|
242
|
+
/** Pins for an image-role profile. Model id is on `model`. */
|
|
243
|
+
image?: ProfileImageSpec;
|
|
244
|
+
/** Pins for a speech-role profile (`voice` / `format`). Model id is on `model`. */
|
|
245
|
+
speech?: ProfileSpeechSpec;
|
|
229
246
|
validation?: ProfileValidationSpec;
|
|
230
247
|
streaming?: ProfileStreamingSpec;
|
|
231
248
|
}
|
|
@@ -263,8 +280,9 @@ export type InteractionPart = InteractionTextPart | InteractionMediaPart;
|
|
|
263
280
|
export interface ImageResponseFormat {
|
|
264
281
|
type: 'image';
|
|
265
282
|
mimeType: string;
|
|
266
|
-
aspectRatio:
|
|
267
|
-
imageSize
|
|
283
|
+
aspectRatio: string;
|
|
284
|
+
/** Authoring / kernel name; adapters map to provider wire keys (e.g. Google `imageSize`). */
|
|
285
|
+
size: string;
|
|
268
286
|
}
|
|
269
287
|
/** Base64-encoded blob supplied by a host turn request. */
|
|
270
288
|
export interface TurnBlob {
|
|
@@ -386,11 +404,14 @@ export interface ProjectedProfile {
|
|
|
386
404
|
inputs: Profile['inputs'];
|
|
387
405
|
slots: Record<string, string[]>;
|
|
388
406
|
outputs: Profile['outputs'];
|
|
389
|
-
image?:
|
|
407
|
+
image?: ProfileImageSpec | null;
|
|
390
408
|
}
|
|
391
|
-
/**
|
|
392
|
-
export interface
|
|
409
|
+
/** Provider selection and generation knobs shared before and after resolution. */
|
|
410
|
+
export interface ProviderGenerationConfig {
|
|
393
411
|
model: ModelId;
|
|
412
|
+
/** Provider-native model id taken from the profile model spec. */
|
|
413
|
+
apiId: string;
|
|
414
|
+
openRouterId?: string;
|
|
394
415
|
previousInteractionId?: string;
|
|
395
416
|
store?: boolean;
|
|
396
417
|
thinking: ThinkingLevel;
|
|
@@ -398,6 +419,9 @@ export interface ResolvedGeneration {
|
|
|
398
419
|
maxOutputTokens: number;
|
|
399
420
|
temperature: number;
|
|
400
421
|
builtins: BuiltinToolId[];
|
|
422
|
+
}
|
|
423
|
+
/** Fully-resolved provider request state created from a `TurnRequest`. */
|
|
424
|
+
export interface ResolvedGeneration extends ProviderGenerationConfig {
|
|
401
425
|
custom: CustomToolId[];
|
|
402
426
|
dynamicTools?: DynamicToolDeclaration[];
|
|
403
427
|
dynamicToolLoader?: DynamicToolLoader;
|
|
@@ -406,9 +430,13 @@ export interface ResolvedGeneration {
|
|
|
406
430
|
maxSteps: number;
|
|
407
431
|
structured: StructuredSchemaId | null;
|
|
408
432
|
image: ImageResponseFormat | null;
|
|
409
|
-
|
|
433
|
+
speech?: ProfileSpeechSpec;
|
|
410
434
|
input: InteractionPart[];
|
|
411
|
-
|
|
435
|
+
/**
|
|
436
|
+
* Gemini vault slot for Google Interactions transport only.
|
|
437
|
+
* Omitted for non-Google providers; never sent on the wire.
|
|
438
|
+
*/
|
|
439
|
+
geminiBucket?: GeminiBucket;
|
|
412
440
|
canary: string;
|
|
413
441
|
}
|
|
414
442
|
/** Tool execution status returned to the model and stream. */
|
|
@@ -470,15 +498,7 @@ export interface TurnEvent {
|
|
|
470
498
|
error?: string;
|
|
471
499
|
}
|
|
472
500
|
/** Provider-neutral request object sent from the kernel to a model adapter. */
|
|
473
|
-
export interface ProviderCompleteRequest {
|
|
474
|
-
model: ModelId;
|
|
475
|
-
previousInteractionId?: string;
|
|
476
|
-
store?: boolean;
|
|
477
|
-
thinking: ThinkingLevel;
|
|
478
|
-
summaries: 'auto' | 'none';
|
|
479
|
-
maxOutputTokens: number;
|
|
480
|
-
temperature: number;
|
|
481
|
-
builtins: BuiltinToolId[];
|
|
501
|
+
export interface ProviderCompleteRequest extends ProviderGenerationConfig {
|
|
482
502
|
system: string;
|
|
483
503
|
input: InteractionPart[];
|
|
484
504
|
history?: TurnHistoryMessage[];
|
|
@@ -486,8 +506,12 @@ export interface ProviderCompleteRequest {
|
|
|
486
506
|
dynamicToolLoader?: DynamicToolLoader;
|
|
487
507
|
structured: StructuredSchemaId | null;
|
|
488
508
|
image: ImageResponseFormat | null;
|
|
489
|
-
|
|
490
|
-
|
|
509
|
+
speech?: ProfileSpeechSpec;
|
|
510
|
+
/**
|
|
511
|
+
* Gemini vault slot for Google Interactions transport only.
|
|
512
|
+
* Required when completing via Google Interactions.
|
|
513
|
+
*/
|
|
514
|
+
geminiBucket?: GeminiBucket;
|
|
491
515
|
/** Scrubbed SSE / HTTP rows for traces. */
|
|
492
516
|
tapGemini?: (row: Record<string, unknown>) => void;
|
|
493
517
|
}
|
|
@@ -1,24 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { providerCompleteRequest } from '../kernel/registry/provider-request.js';
|
|
2
2
|
import { tapeGemini } from '../providers/gemini-tape.js';
|
|
3
3
|
import { toInteractionsBody } from '../providers/interactions.js';
|
|
4
4
|
import { httpStatus } from './trace-usage.js';
|
|
5
|
-
function completeRequest(generation, system) {
|
|
6
|
-
return {
|
|
7
|
-
model: generation.model,
|
|
8
|
-
previousInteractionId: generation.previousInteractionId,
|
|
9
|
-
store: generation.store,
|
|
10
|
-
thinking: generation.thinking,
|
|
11
|
-
summaries: generation.summaries,
|
|
12
|
-
maxOutputTokens: generation.maxOutputTokens,
|
|
13
|
-
temperature: generation.temperature,
|
|
14
|
-
builtins: generation.builtins,
|
|
15
|
-
system,
|
|
16
|
-
input: generation.input,
|
|
17
|
-
structured: generation.structured,
|
|
18
|
-
image: generation.image,
|
|
19
|
-
geminiBucket: generation.geminiBucket,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
5
|
function attachResolved(record, args) {
|
|
23
6
|
const { safe, model, bucket, generation } = args;
|
|
24
7
|
if (safe.projectId) {
|
|
@@ -37,7 +20,10 @@ function attachResolved(record, args) {
|
|
|
37
20
|
record.metadata = safe.metadata;
|
|
38
21
|
}
|
|
39
22
|
if (model) {
|
|
40
|
-
record.model = {
|
|
23
|
+
record.model = {
|
|
24
|
+
id: model,
|
|
25
|
+
apiId: generation?.apiId ?? model,
|
|
26
|
+
};
|
|
41
27
|
}
|
|
42
28
|
if (bucket) {
|
|
43
29
|
record.bucket = bucket;
|
|
@@ -61,7 +47,7 @@ async function attachTape(record, args) {
|
|
|
61
47
|
record.gemini = await tapeGemini(gemini, canary ?? '');
|
|
62
48
|
}
|
|
63
49
|
if (generation && system !== undefined) {
|
|
64
|
-
record.wire = await tapeGemini(toInteractionsBody(
|
|
50
|
+
record.wire = await tapeGemini(toInteractionsBody(providerCompleteRequest(generation, system)), canary ?? '');
|
|
65
51
|
}
|
|
66
52
|
}
|
|
67
53
|
function attachUsage(record, gemini, done) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google / Gemini convenience preset.
|
|
3
|
+
*
|
|
4
|
+
* Kernel stays open (`string` pins). This pack owns Google vocabularies as
|
|
5
|
+
* real unions so host profiles stay typed when they opt into the preset.
|
|
6
|
+
*
|
|
7
|
+
* Call `registerGooglePreset()` at host startup for tools; use the exported
|
|
8
|
+
* types/constants when authoring image/speech-adjacent profile fields.
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import "../../_dnt.polyfills.js";
|
|
13
|
+
import type { ProfileImageSpec, ProfileSpeechSpec, ToolCatalogEntry } from '../kernel/types.js';
|
|
14
|
+
/** Google Interactions / Gemini grounding builtins. */
|
|
15
|
+
declare const GOOGLE_BUILTIN_TOOLS: Record<string, ToolCatalogEntry>;
|
|
16
|
+
/** Common Gemini image input MIME allowlist. */
|
|
17
|
+
declare const GOOGLE_IMAGE_INPUT_MIMES: readonly ["image/png", "image/jpeg", "image/webp", "image/heic", "image/heif"];
|
|
18
|
+
/** Common voice/audio input MIME allowlist for Gemini multimodal. */
|
|
19
|
+
declare const GOOGLE_VOICE_INPUT_MIMES: readonly ["audio/webm", "audio/wav", "audio/mpeg", "audio/mp4"];
|
|
20
|
+
/** Common Gemini TTS voice names for `outputs.speech.voice`. */
|
|
21
|
+
declare const GOOGLE_SPEECH_VOICES: readonly ["Zephyr", "Puck", "Charon", "Kore", "Fenrir", "Leda", "Orus", "Aoede", "Callirrhoe", "Autonoe", "Enceladus", "Iapetus", "Umbriel", "Algieba", "Despina", "Erinome", "Algenib", "Rasalgethi", "Laomedeia", "Achernar", "Alnilam", "Schedar", "Gacrux", "Pulcherrima", "Achird", "Zubenelgenubi", "Vindemiatrix", "Sadachbia", "Sadaltager", "Sulafat"];
|
|
22
|
+
type GoogleSpeechVoice = (typeof GOOGLE_SPEECH_VOICES)[number];
|
|
23
|
+
/**
|
|
24
|
+
* `outputs.speech` pins narrowed to Google TTS vocabulary.
|
|
25
|
+
* Assignable to kernel `ProfileSpeechSpec`.
|
|
26
|
+
*/
|
|
27
|
+
type GoogleSpeechPins = Omit<ProfileSpeechSpec, 'voice'> & {
|
|
28
|
+
voice?: GoogleSpeechVoice;
|
|
29
|
+
};
|
|
30
|
+
/** Aspect ratios commonly accepted by Gemini image models. */
|
|
31
|
+
declare const GOOGLE_IMAGE_ASPECT_RATIOS: readonly ["1:1", "3:2", "2:3", "3:4", "4:3", "4:5", "5:4", "9:16", "16:9", "21:9"];
|
|
32
|
+
/** Image sizes commonly accepted by Gemini Flash Lite image. */
|
|
33
|
+
declare const GOOGLE_IMAGE_SIZES: readonly ["1K"];
|
|
34
|
+
type GoogleImageInputMime = (typeof GOOGLE_IMAGE_INPUT_MIMES)[number];
|
|
35
|
+
type GoogleVoiceInputMime = (typeof GOOGLE_VOICE_INPUT_MIMES)[number];
|
|
36
|
+
type GoogleImageAspectRatio = (typeof GOOGLE_IMAGE_ASPECT_RATIOS)[number];
|
|
37
|
+
type GoogleImageSize = (typeof GOOGLE_IMAGE_SIZES)[number];
|
|
38
|
+
/**
|
|
39
|
+
* `outputs.image` pins narrowed to Google image vocabulary.
|
|
40
|
+
* Assignable to kernel `ProfileImageSpec`.
|
|
41
|
+
*/
|
|
42
|
+
type GoogleImagePins = Omit<ProfileImageSpec, 'aspectRatio' | 'size' | 'mimeType'> & {
|
|
43
|
+
aspectRatio?: GoogleImageAspectRatio;
|
|
44
|
+
size?: GoogleImageSize;
|
|
45
|
+
mimeType?: GoogleImageInputMime | 'image/jpeg';
|
|
46
|
+
};
|
|
47
|
+
/** Register Google provider builtins into the process-local tool catalog. */
|
|
48
|
+
declare function registerGooglePreset(): void;
|
|
49
|
+
export type { GoogleImageAspectRatio, GoogleImageInputMime, GoogleImagePins, GoogleImageSize, GoogleSpeechPins, GoogleSpeechVoice, GoogleVoiceInputMime, };
|
|
50
|
+
export { GOOGLE_BUILTIN_TOOLS, GOOGLE_IMAGE_ASPECT_RATIOS, GOOGLE_IMAGE_INPUT_MIMES, GOOGLE_IMAGE_SIZES, GOOGLE_SPEECH_VOICES, GOOGLE_VOICE_INPUT_MIMES, registerGooglePreset, };
|