theorum 0.1.15 → 1.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 +241 -98
- package/esm/mod.d.ts +57 -28
- package/esm/mod.js +43 -23
- package/esm/src/cli/commands/bench.js +18 -18
- package/esm/src/cli/commands/fuzz-canary.d.ts +13 -0
- package/esm/src/cli/commands/fuzz-canary.js +191 -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/guardrails-eval.d.ts +14 -0
- package/esm/src/cli/commands/guardrails-eval.js +15 -0
- package/esm/src/cli/commands/profile.js +35 -15
- package/esm/src/cli/commands/run.d.ts +3 -0
- package/esm/src/cli/commands/run.js +23 -32
- package/esm/src/cli/commands/test.d.ts +10 -1
- package/esm/src/cli/commands/test.js +34 -34
- 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 +57 -11
- package/esm/src/cli/matrix/synthesizer.d.ts +10 -12
- package/esm/src/cli/matrix/synthesizer.js +45 -118
- package/esm/src/guardrails/canary-gate.d.ts +21 -0
- package/esm/src/guardrails/canary-gate.js +32 -0
- package/esm/src/guardrails/canary.d.ts +34 -0
- package/esm/src/guardrails/canary.js +150 -0
- package/esm/src/guardrails/corpus/canary-egress-attacks.d.ts +17 -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 +213 -0
- package/esm/src/guardrails/corpus/inbound-payloads.d.ts +10 -0
- package/esm/src/guardrails/corpus/inbound-payloads.js +125 -0
- package/esm/src/guardrails/corpus/live-attacks.d.ts +20 -0
- package/esm/src/guardrails/corpus/live-attacks.js +231 -0
- package/esm/src/guardrails/corpus/mod.d.ts +14 -0
- package/esm/src/guardrails/corpus/mod.js +11 -0
- package/esm/src/guardrails/corpus/secrets.d.ts +17 -0
- package/esm/src/guardrails/corpus/secrets.js +17 -0
- package/esm/src/guardrails/corpus/strings.d.ts +28 -0
- package/esm/src/guardrails/corpus/strings.js +34 -0
- package/esm/src/guardrails/corpus/types.d.ts +38 -0
- package/esm/src/guardrails/corpus/types.js +6 -0
- package/esm/src/guardrails/egress.d.ts +32 -0
- package/esm/src/guardrails/egress.js +87 -0
- package/esm/src/guardrails/error.d.ts +14 -23
- package/esm/src/guardrails/error.js +87 -76
- package/esm/src/guardrails/eval/corpus.d.ts +108 -0
- package/esm/src/guardrails/eval/corpus.js +978 -0
- package/esm/src/guardrails/eval/mod.d.ts +51 -0
- package/esm/src/guardrails/eval/mod.js +133 -0
- package/esm/src/guardrails/eval/score.d.ts +66 -0
- package/esm/src/guardrails/eval/score.js +114 -0
- package/esm/src/guardrails/events.d.ts +25 -0
- package/esm/src/guardrails/events.js +56 -0
- package/esm/src/guardrails/hits.d.ts +24 -0
- package/esm/src/guardrails/hits.js +45 -0
- package/esm/src/guardrails/injection.js +28 -5
- package/esm/src/guardrails/lexicon.d.ts +39 -0
- package/esm/src/guardrails/lexicon.js +200 -0
- package/esm/src/guardrails/live-outbound-gate.d.ts +41 -0
- package/esm/src/guardrails/live-outbound-gate.js +222 -0
- package/esm/src/guardrails/mod.d.ts +30 -6
- package/esm/src/guardrails/mod.js +20 -5
- package/esm/src/guardrails/network.d.ts +19 -0
- package/esm/src/guardrails/network.js +234 -0
- package/esm/src/guardrails/policy.d.ts +35 -0
- package/esm/src/guardrails/policy.js +50 -0
- package/esm/src/guardrails/progressive-yield.d.ts +51 -0
- package/esm/src/guardrails/progressive-yield.js +98 -0
- package/esm/src/guardrails/quota.d.ts +17 -3
- package/esm/src/guardrails/quota.js +18 -4
- package/esm/src/guardrails/sanitize.d.ts +45 -19
- package/esm/src/guardrails/sanitize.js +177 -94
- package/esm/src/guardrails/sensitive.js +2 -1
- package/esm/src/guardrails/serialize.d.ts +35 -0
- package/esm/src/guardrails/serialize.js +58 -0
- package/esm/src/guardrails/testing.d.ts +17 -0
- package/esm/src/guardrails/testing.js +13 -0
- package/esm/src/guardrails/theorum-error.d.ts +12 -0
- package/esm/src/guardrails/theorum-error.js +15 -0
- package/esm/src/guardrails/tool-directives.d.ts +48 -0
- package/esm/src/guardrails/tool-directives.js +124 -0
- package/esm/src/guardrails/tool-result.d.ts +93 -0
- package/esm/src/guardrails/tool-result.js +276 -0
- package/esm/src/guardrails/types.d.ts +291 -0
- package/esm/src/guardrails/types.js +72 -0
- package/esm/src/host/client-turn.d.ts +19 -0
- package/esm/src/host/client-turn.js +36 -0
- package/esm/src/host/mint-trace.d.ts +1 -1
- package/esm/src/host/mod.d.ts +5 -3
- package/esm/src/host/mod.js +4 -3
- package/esm/src/kernel/auth/crypto.d.ts +42 -0
- package/esm/src/kernel/auth/crypto.js +106 -0
- package/esm/src/kernel/auth/mod.d.ts +11 -0
- package/esm/src/kernel/auth/mod.js +11 -0
- package/esm/src/kernel/auth/oauth.d.ts +47 -0
- package/esm/src/kernel/auth/oauth.js +278 -0
- package/esm/src/kernel/auth/types.d.ts +133 -0
- package/esm/src/kernel/auth/types.js +13 -0
- package/esm/src/kernel/engine/delta.d.ts +24 -2
- package/esm/src/kernel/engine/delta.js +478 -39
- package/esm/src/kernel/engine/live-inbound.d.ts +21 -0
- package/esm/src/kernel/engine/live-inbound.js +31 -0
- package/esm/src/kernel/engine/live-ingress.d.ts +19 -0
- package/esm/src/kernel/engine/live-ingress.js +47 -0
- package/esm/src/kernel/engine/repair.js +13 -12
- package/esm/src/kernel/engine/runner/gates.d.ts +1 -1
- package/esm/src/kernel/engine/runner/gates.js +130 -43
- package/esm/src/kernel/engine/runner/mod.d.ts +6 -4
- package/esm/src/kernel/engine/runner/mod.js +192 -53
- package/esm/src/kernel/engine/runner/schema-validation.js +3 -3
- package/esm/src/kernel/engine/runner/stages.d.ts +39 -0
- package/esm/src/kernel/engine/runner/stages.js +89 -0
- package/esm/src/kernel/engine/runner/state.d.ts +31 -0
- package/esm/src/kernel/engine/runner/steps.d.ts +1 -1
- package/esm/src/kernel/engine/runner/steps.js +244 -43
- package/esm/src/kernel/engine/runner/stream.d.ts +9 -3
- package/esm/src/kernel/engine/runner/stream.js +140 -44
- package/esm/src/kernel/engine/session/mod.d.ts +25 -0
- package/esm/src/kernel/engine/session/mod.js +557 -0
- package/esm/src/kernel/interaction-parts.d.ts +14 -0
- package/esm/src/kernel/interaction-parts.js +23 -0
- package/esm/src/kernel/mod.d.ts +21 -10
- package/esm/src/kernel/mod.js +11 -8
- package/esm/src/kernel/profile-graph.d.ts +159 -0
- package/esm/src/kernel/profile-graph.js +156 -0
- package/esm/src/kernel/registry/attachments.d.ts +12 -10
- package/esm/src/kernel/registry/attachments.js +33 -27
- package/esm/src/kernel/registry/catalog.d.ts +25 -24
- package/esm/src/kernel/registry/catalog.js +60 -101
- package/esm/src/kernel/registry/ingress.d.ts +9 -4
- package/esm/src/kernel/registry/ingress.js +97 -75
- package/esm/src/kernel/registry/profile-outputs.d.ts +4 -0
- package/esm/src/kernel/registry/profile-outputs.js +8 -0
- package/esm/src/kernel/registry/profiles.d.ts +55 -12
- package/esm/src/kernel/registry/profiles.js +413 -73
- package/esm/src/kernel/registry/provider-request.js +13 -7
- package/esm/src/kernel/registry/resolve.d.ts +8 -8
- package/esm/src/kernel/registry/resolve.js +169 -154
- package/esm/src/kernel/registry/schemas.js +1 -1
- package/esm/src/kernel/registry/sole-model.d.ts +8 -0
- package/esm/src/kernel/registry/sole-model.js +10 -0
- package/esm/src/kernel/registry/system-prompt.d.ts +10 -0
- package/esm/src/kernel/registry/system-prompt.js +40 -0
- package/esm/src/kernel/registry/system-role.d.ts +8 -0
- package/esm/src/kernel/registry/system-role.js +14 -0
- package/esm/src/kernel/registry/vault.d.ts +12 -7
- package/esm/src/kernel/registry/vault.js +32 -10
- package/esm/src/kernel/schema.d.ts +231 -0
- package/esm/src/kernel/schema.js +607 -0
- package/esm/src/kernel/stages.d.ts +175 -0
- package/esm/src/kernel/stages.js +476 -0
- package/esm/src/kernel/stop.d.ts +78 -19
- package/esm/src/kernel/stop.js +51 -16
- package/esm/src/kernel/tools/events.d.ts +41 -0
- package/esm/src/kernel/tools/events.js +71 -0
- package/esm/src/kernel/tools/execute.d.ts +84 -0
- package/esm/src/kernel/tools/execute.js +614 -0
- package/esm/src/kernel/tools/harness.d.ts +8 -0
- package/esm/src/kernel/tools/harness.js +46 -0
- package/esm/src/kernel/tools/invoke.d.ts +10 -0
- package/esm/src/kernel/tools/invoke.js +101 -0
- package/esm/src/kernel/tools/mod.d.ts +13 -0
- package/esm/src/kernel/tools/mod.js +11 -0
- package/esm/src/kernel/tools/permission.d.ts +15 -0
- package/esm/src/kernel/tools/permission.js +47 -0
- package/esm/src/kernel/tools/project.d.ts +12 -0
- package/esm/src/kernel/tools/project.js +36 -0
- package/esm/src/kernel/tools/registry.d.ts +23 -0
- package/esm/src/kernel/tools/registry.js +81 -0
- package/esm/src/kernel/tools/remote.d.ts +94 -0
- package/esm/src/kernel/tools/remote.js +577 -0
- package/esm/src/kernel/tools/resolve.d.ts +39 -0
- package/esm/src/kernel/tools/resolve.js +283 -0
- package/esm/src/kernel/tools/schema.d.ts +15 -0
- package/esm/src/kernel/tools/schema.js +176 -0
- package/esm/src/kernel/tools/stage-run.d.ts +105 -0
- package/esm/src/kernel/tools/stage-run.js +155 -0
- package/esm/src/kernel/tools/types.d.ts +394 -0
- package/esm/src/kernel/tools/types.js +9 -0
- package/esm/src/kernel/types.d.ts +540 -256
- package/esm/src/kernel/util/find-last.d.ts +2 -0
- package/esm/src/kernel/util/find-last.js +10 -0
- package/esm/src/observability/destinations.d.ts +31 -0
- package/esm/src/observability/destinations.js +67 -0
- package/esm/src/observability/mod.d.ts +10 -3
- package/esm/src/observability/mod.js +6 -2
- package/esm/src/observability/policy.d.ts +27 -0
- package/esm/src/observability/policy.js +80 -0
- package/esm/src/observability/resolve-policy.d.ts +16 -0
- package/esm/src/observability/resolve-policy.js +64 -0
- package/esm/src/observability/trace-attach.d.ts +8 -4
- package/esm/src/observability/trace-attach.js +50 -29
- package/esm/src/observability/trace-record.d.ts +23 -13
- package/esm/src/observability/trace-record.js +96 -39
- package/esm/src/observability/trace-sink.d.ts +19 -0
- package/esm/src/observability/trace-sink.js +10 -0
- 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 +18 -7
- package/esm/src/observability/trace.js +34 -17
- package/esm/src/observability/types.d.ts +113 -0
- package/esm/src/observability/types.js +11 -0
- 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 +20 -17
- package/esm/src/providers/create-provider.js +72 -26
- package/esm/src/providers/google/interactions/framing.d.ts +23 -0
- package/esm/src/providers/google/interactions/framing.js +269 -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 +49 -0
- package/esm/src/providers/google/live/framing.js +552 -0
- package/esm/src/providers/google/live/openapi-schema.d.ts +6 -0
- package/esm/src/providers/google/live/openapi-schema.js +46 -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 +45 -0
- package/esm/src/providers/google/live/stream.js +214 -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/cache-control.d.ts +24 -0
- package/esm/src/providers/openrouter/cache-control.js +23 -0
- package/esm/src/providers/openrouter/chat.d.ts +107 -0
- package/esm/src/providers/{openrouter.js → openrouter/chat.js} +117 -231
- package/esm/src/providers/openrouter/image.d.ts +34 -0
- package/esm/src/providers/openrouter/image.js +275 -0
- package/esm/src/providers/openrouter/openai/chat-payload.d.ts +24 -0
- package/esm/src/providers/openrouter/openai/chat-payload.js +82 -0
- package/esm/src/providers/openrouter/openai/compat.d.ts +53 -0
- package/esm/src/providers/openrouter/openai/compat.js +213 -0
- package/esm/src/providers/openrouter/openai/image-payload.d.ts +18 -0
- package/esm/src/providers/openrouter/openai/image-payload.js +90 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.d.ts +22 -0
- package/esm/src/providers/openrouter/openai/sdk-messages.js +122 -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
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime vocabulary and field catalog for THEORUM profile types.
|
|
3
|
+
*
|
|
4
|
+
* Closed unions live here as `as const` arrays; TypeScript types are derived
|
|
5
|
+
* from those arrays. Host UIs and docs import this module (no Deno APIs) so
|
|
6
|
+
* dropdowns and hover tips stay in lockstep with the kernel.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
/** lexicon-exempt-file: authoring field-meta / closed unions — not runtime user or model copy (P2) */
|
|
11
|
+
import { EGRESS_ON_BLOCK } from '../guardrails/types.js';
|
|
12
|
+
import { GOOGLE_SPEECH_VOICES } from '../presets/google/speech-voices.js';
|
|
13
|
+
export { EGRESS_ON_BLOCK };
|
|
14
|
+
/** Primary profile archetype. Discriminated union key for `ProfileDefinition` and `Profile`. */
|
|
15
|
+
export const PROFILE_TYPES = ['text', 'image', 'speech', 'live', 'host'];
|
|
16
|
+
/** Model reasoning effort level normalized across provider adapters. */
|
|
17
|
+
export const THINKING_LEVELS = [
|
|
18
|
+
'none',
|
|
19
|
+
'minimal',
|
|
20
|
+
'low',
|
|
21
|
+
'medium',
|
|
22
|
+
'high',
|
|
23
|
+
'xhigh',
|
|
24
|
+
'max',
|
|
25
|
+
];
|
|
26
|
+
/** Wire protocol for a profile. */
|
|
27
|
+
export const PROTOCOLS = ['geminiInteractions', 'geminiLive', 'openAi'];
|
|
28
|
+
/** Transport provider for a profile. */
|
|
29
|
+
export const PROVIDERS = ['google', 'openrouter', 'local'];
|
|
30
|
+
/**
|
|
31
|
+
* Legal `createProvider` pairs. Keep this table in lockstep with the factory.
|
|
32
|
+
* Keys are protocols; values are the providers that protocol may bind.
|
|
33
|
+
*/
|
|
34
|
+
export const PROTOCOL_PROVIDERS = {
|
|
35
|
+
geminiInteractions: ['google'],
|
|
36
|
+
geminiLive: ['google'],
|
|
37
|
+
openAi: ['openrouter', 'local'],
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Legal wire protocols for each profile archetype.
|
|
41
|
+
* 'live' profiles require 'geminiLive'; turn-based archetypes require turn protocols;
|
|
42
|
+
* 'host' never runs a model and binds no protocol.
|
|
43
|
+
*/
|
|
44
|
+
export const PROFILE_TYPE_PROTOCOLS = {
|
|
45
|
+
text: ['geminiInteractions', 'openAi'],
|
|
46
|
+
image: ['geminiInteractions', 'openAi'],
|
|
47
|
+
speech: ['geminiInteractions', 'openAi'],
|
|
48
|
+
live: ['geminiLive'],
|
|
49
|
+
host: [],
|
|
50
|
+
};
|
|
51
|
+
/** Protocols allowed for a profile archetype (`type`). */
|
|
52
|
+
export function protocolsForProfileType(type) {
|
|
53
|
+
return PROFILE_TYPE_PROTOCOLS[type];
|
|
54
|
+
}
|
|
55
|
+
/** True when the protocol is valid for the given profile archetype. */
|
|
56
|
+
export function isValidProfileProtocol(type, protocol) {
|
|
57
|
+
return PROFILE_TYPE_PROTOCOLS[type].includes(protocol);
|
|
58
|
+
}
|
|
59
|
+
/** Named vault key slots for host-supplied credentials (provider-neutral). */
|
|
60
|
+
export const KEY_SLOTS = ['slotA', 'slotB', 'slotC', 'paid'];
|
|
61
|
+
/** Key slots that may overflow to `paid` after quota backoff. */
|
|
62
|
+
export const OVERFLOW_KEY_SLOTS = ['slotA', 'slotB', 'slotC'];
|
|
63
|
+
/** Profile-level control a caller may toggle at turn time. */
|
|
64
|
+
/** Normalized multimodal part category. */
|
|
65
|
+
export const MEDIA_INPUT_KIND_VALUES = ['image', 'audio', 'video', 'document'];
|
|
66
|
+
/** Provider thinking-summary behavior. */
|
|
67
|
+
export const SUMMARY_MODES = ['auto', 'none'];
|
|
68
|
+
/** Stream delivery mode. */
|
|
69
|
+
export const STREAM_MODES = ['sse', 'buffered'];
|
|
70
|
+
/** Audio container for speech generation output. */
|
|
71
|
+
export const SPEECH_AUDIO_FORMATS = ['pcm', 'mp3'];
|
|
72
|
+
/** Speech `format` values legal for a wire protocol (`assertSpeechRole` / UI). */
|
|
73
|
+
export function speechFormatsForProtocol(protocol) {
|
|
74
|
+
return protocol === 'openAi' ? SPEECH_AUDIO_FORMATS : ['pcm'];
|
|
75
|
+
}
|
|
76
|
+
export function isSpeechFormatAllowedForProtocol(protocol, format) {
|
|
77
|
+
return speechFormatsForProtocol(protocol).includes(format);
|
|
78
|
+
}
|
|
79
|
+
/** Snap an illegal or omitted format to the first legal value for the protocol. */
|
|
80
|
+
export function coerceSpeechFormat(protocol, format) {
|
|
81
|
+
const allowed = speechFormatsForProtocol(protocol);
|
|
82
|
+
if (format && allowed.includes(format))
|
|
83
|
+
return format;
|
|
84
|
+
return allowed[0];
|
|
85
|
+
}
|
|
86
|
+
/** Live session activity handling (barge-in behavior). */
|
|
87
|
+
export const LIVE_ACTIVITY_HANDLINGS = ['START_OF_ACTIVITY_INTERRUPTS', 'NO_INTERRUPTION'];
|
|
88
|
+
/** Live session voice activity detection sensitivity. */
|
|
89
|
+
export const LIVE_SPEECH_SENSITIVITIES = [
|
|
90
|
+
'START_SENSITIVITY_LOW',
|
|
91
|
+
'START_SENSITIVITY_HIGH',
|
|
92
|
+
'END_SENSITIVITY_LOW',
|
|
93
|
+
'END_SENSITIVITY_HIGH',
|
|
94
|
+
];
|
|
95
|
+
/** Live session context window compression mode. */
|
|
96
|
+
export const LIVE_CONTEXT_COMPRESSIONS = ['slidingWindow', 'none'];
|
|
97
|
+
/** Structured-output enforcement mode. */
|
|
98
|
+
export const SCHEMA_ENFORCEMENTS = ['responseFormat', 'prompt'];
|
|
99
|
+
/** Compaction threshold meter. */
|
|
100
|
+
export const COMPACTION_METERS = ['history', 'input'];
|
|
101
|
+
/** When compaction runs relative to the primary turn. */
|
|
102
|
+
export const COMPACTION_TIMINGS = ['before', 'after'];
|
|
103
|
+
/** OpenRouter prompt-cache mode (models.*.cache.mode). */
|
|
104
|
+
export const CACHE_MODES = ['automatic', 'system'];
|
|
105
|
+
/** OpenRouter ephemeral cache TTL (models.*.cache.ttl). */
|
|
106
|
+
export const CACHE_TTLS = ['5m', '1h'];
|
|
107
|
+
/** Why a turn ended (provider-neutral). */
|
|
108
|
+
export const TURN_STOP_KINDS = [
|
|
109
|
+
'completed',
|
|
110
|
+
'length',
|
|
111
|
+
/**
|
|
112
|
+
* @deprecated Shipping pause fiction (`tool.phase: 'pause'`). Target: use `gate`
|
|
113
|
+
* for confirm/permission/auth suspension; awaiting is a completed tool result.
|
|
114
|
+
* Removed when stages slices release.
|
|
115
|
+
*/
|
|
116
|
+
'tool',
|
|
117
|
+
/**
|
|
118
|
+
* Honest suspension: `pre_tool` confirm / permission / auth blocked the body.
|
|
119
|
+
* Host resumes via invokeTool/executeTool; not continueFrom.
|
|
120
|
+
*/
|
|
121
|
+
'gate',
|
|
122
|
+
'filtered',
|
|
123
|
+
'provider_error',
|
|
124
|
+
'cancelled',
|
|
125
|
+
'stream_incomplete',
|
|
126
|
+
'interrupted',
|
|
127
|
+
/** Live: model finished generating audio/text for this utterance; turn may still be open. */
|
|
128
|
+
'generation_complete',
|
|
129
|
+
];
|
|
130
|
+
/**
|
|
131
|
+
* Stop kinds eligible for `continueFrom` / resumption allowlists.
|
|
132
|
+
* Excludes terminal-success, user abort, tool/gate suspension, filter, and live-only
|
|
133
|
+
* boundaries — those use other host paths (or are not resumeable).
|
|
134
|
+
*/
|
|
135
|
+
export const CONTINUE_STOP_KINDS = ['length', 'stream_incomplete', 'provider_error'];
|
|
136
|
+
/**
|
|
137
|
+
* Turn / utterance-cycle timeline stages (`docs/contracts/stages.md`).
|
|
138
|
+
* Replaces the former steer barriers (`pre_llm` / `pre_tool_followup`).
|
|
139
|
+
*/
|
|
140
|
+
export const TURN_STAGES = [
|
|
141
|
+
'pre_turn',
|
|
142
|
+
'pre_tool',
|
|
143
|
+
'post_tool',
|
|
144
|
+
'before_end',
|
|
145
|
+
'post_turn',
|
|
146
|
+
];
|
|
147
|
+
const TURN_STAGE_SET = new Set(TURN_STAGES);
|
|
148
|
+
/** True when `value` is a known `TurnStage`. */
|
|
149
|
+
export function isTurnStage(value) {
|
|
150
|
+
return typeof value === 'string' && TURN_STAGE_SET.has(value);
|
|
151
|
+
}
|
|
152
|
+
/** Stages where inject is physically meaningful (still requires inject gate). */
|
|
153
|
+
export const TURN_INJECT_STAGES = ['pre_turn', 'post_tool', 'before_end'];
|
|
154
|
+
const TURN_INJECT_STAGE_SET = new Set(TURN_INJECT_STAGES);
|
|
155
|
+
/** True when inject is physically meaningful at this stage (gate still required). */
|
|
156
|
+
export function isTurnInjectStage(value) {
|
|
157
|
+
return typeof value === 'string' && TURN_INJECT_STAGE_SET.has(value);
|
|
158
|
+
}
|
|
159
|
+
/** `pre_tool` gate kinds — confirm-to-run / permission / auth. Not awaiting. */
|
|
160
|
+
export const TOOL_GATE_KINDS = ['confirmation', 'permission', 'auth'];
|
|
161
|
+
const TOOL_GATE_KIND_SET = new Set(TOOL_GATE_KINDS);
|
|
162
|
+
/** True when `value` is a known tool-gate kind. */
|
|
163
|
+
export function isToolGateKind(value) {
|
|
164
|
+
return typeof value === 'string' && TOOL_GATE_KIND_SET.has(value);
|
|
165
|
+
}
|
|
166
|
+
/** `awaiting_user_input.kind` — harness ask_user / human-as-product completions. */
|
|
167
|
+
export const AWAITING_USER_INPUT_KINDS = ['confirm', 'choice', 'text'];
|
|
168
|
+
/** Discriminator on tool output for awaiting completions. */
|
|
169
|
+
export const AWAITING_USER_INPUT_STATUS = 'awaiting_user_input';
|
|
170
|
+
/** Per-tool visibility tier — enforced by the kernel at resolve time. */
|
|
171
|
+
export const TOOL_LOAD_TIERS = ['T0', 'T1', 'T2'];
|
|
172
|
+
/** HTTP verbs supported by declarative HTTP tools. */
|
|
173
|
+
export const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
|
|
174
|
+
/** When remote tool auth is missing or expired. */
|
|
175
|
+
export const AUTH_UNAUTHENTICATED_POLICIES = ['pause', 'report_to_model'];
|
|
176
|
+
/** Registered tool discriminant (`registerTool`). */
|
|
177
|
+
export const TOOL_TYPES = ['builtin', 'function', 'http', 'mcp'];
|
|
178
|
+
/** Semantic access level — host policy / UI; not enforced by execute. */
|
|
179
|
+
export const TOOL_ACCESS = ['read-only', 'read-write', 'destructive'];
|
|
180
|
+
/** Execution authorization tier for registered tools. */
|
|
181
|
+
export const TOOL_PERMISSION = ['auto', 'session_consent', 'always_confirm'];
|
|
182
|
+
/** Credential attachment modes for HTTP and MCP tools (`auth.type`). */
|
|
183
|
+
export const TOOL_AUTH_TYPES = ['bearer', 'api_key', 'oauth2'];
|
|
184
|
+
/** Playground auth select — includes UI-only `none` (omits auth at compile time). */
|
|
185
|
+
export const PLAYGROUND_AUTH_TYPES = ['none', ...TOOL_AUTH_TYPES];
|
|
186
|
+
/**
|
|
187
|
+
* MIME essence → normalized media part category.
|
|
188
|
+
*
|
|
189
|
+
* This table is the complete media-input vocabulary of the package: every MIME
|
|
190
|
+
* any supported transport may carry on a turn appears here exactly once, and
|
|
191
|
+
* nothing else is a media input type. `assertMediaMime` (`registry/ingress.ts`)
|
|
192
|
+
* refuses anything absent from it, so hosts declare what they accept in
|
|
193
|
+
* `inputs.attachments.accept` / `inputs.voice.accept` and keep no second table.
|
|
194
|
+
*
|
|
195
|
+
* Contents are the union of the documented provider input lists:
|
|
196
|
+
* - Google Interactions / Live (image, audio, video, document lists verified
|
|
197
|
+
* 2026-09-12) — the widest of the three and therefore the table's shape. The
|
|
198
|
+
* document row is Google's document-understanding list in full: PDF, plain
|
|
199
|
+
* text, HTML, CSS, Markdown (`text/md`), CSV, XML, RTF, JavaScript
|
|
200
|
+
* (`text/javascript`, `application/x-javascript`) and Python
|
|
201
|
+
* (`text/x-python`, `application/x-python`); `application/json` is an
|
|
202
|
+
* established row alongside it. TypeScript, `application/xml` and
|
|
203
|
+
* `application/rtf` are NOT on Google's list and are therefore not rows.
|
|
204
|
+
* - OpenRouter / OpenAI-compat (`providers/openrouter/openai/compat.ts`,
|
|
205
|
+
* `sdk-messages.ts`): the adapters wire every `MediaInputKind` (image →
|
|
206
|
+
* `image_url`/`image`, audio → `input_audio`, video and document → `file`)
|
|
207
|
+
* and forward the part's MIME verbatim, so their accepted set is open-ended
|
|
208
|
+
* and adds no rows. What they cannot carry — a `uri` reference part — is
|
|
209
|
+
* refused at request time with `TheorumError`, not by a second MIME list.
|
|
210
|
+
*
|
|
211
|
+
* Alias essences that providers also emit (`image/jpg`, `video/mov`,
|
|
212
|
+
* `audio/x-wav`, `video/x-ms-wmv`, …) are rows here; `resolveInputParts`
|
|
213
|
+
* canonicalizes `image/jpg` to `image/jpeg` on the wire.
|
|
214
|
+
*/
|
|
215
|
+
export const MEDIA_INPUT_KINDS = {
|
|
216
|
+
'image/png': 'image',
|
|
217
|
+
'image/jpeg': 'image',
|
|
218
|
+
'image/jpg': 'image',
|
|
219
|
+
'image/webp': 'image',
|
|
220
|
+
'image/heic': 'image',
|
|
221
|
+
'image/heif': 'image',
|
|
222
|
+
'audio/wav': 'audio',
|
|
223
|
+
'audio/x-wav': 'audio',
|
|
224
|
+
'audio/mpeg': 'audio',
|
|
225
|
+
'audio/mp3': 'audio',
|
|
226
|
+
'audio/aiff': 'audio',
|
|
227
|
+
'audio/aac': 'audio',
|
|
228
|
+
'audio/ogg': 'audio',
|
|
229
|
+
'audio/flac': 'audio',
|
|
230
|
+
'audio/webm': 'audio',
|
|
231
|
+
'audio/mp4': 'audio',
|
|
232
|
+
'audio/pcm': 'audio',
|
|
233
|
+
'audio/m4a': 'audio',
|
|
234
|
+
'audio/opus': 'audio',
|
|
235
|
+
'audio/l16': 'audio',
|
|
236
|
+
'audio/alaw': 'audio',
|
|
237
|
+
'audio/mulaw': 'audio',
|
|
238
|
+
'video/mp4': 'video',
|
|
239
|
+
'video/mpeg': 'video',
|
|
240
|
+
'video/quicktime': 'video',
|
|
241
|
+
'video/mov': 'video',
|
|
242
|
+
'video/x-msvideo': 'video',
|
|
243
|
+
'video/avi': 'video',
|
|
244
|
+
'video/x-flv': 'video',
|
|
245
|
+
'video/mpg': 'video',
|
|
246
|
+
'video/webm': 'video',
|
|
247
|
+
'video/wmv': 'video',
|
|
248
|
+
'video/x-ms-wmv': 'video',
|
|
249
|
+
'video/3gpp': 'video',
|
|
250
|
+
'application/pdf': 'document',
|
|
251
|
+
'text/plain': 'document',
|
|
252
|
+
'text/csv': 'document',
|
|
253
|
+
'text/markdown': 'document',
|
|
254
|
+
'text/md': 'document',
|
|
255
|
+
'text/html': 'document',
|
|
256
|
+
'text/css': 'document',
|
|
257
|
+
'text/xml': 'document',
|
|
258
|
+
'text/rtf': 'document',
|
|
259
|
+
'text/javascript': 'document',
|
|
260
|
+
'application/x-javascript': 'document',
|
|
261
|
+
'text/x-python': 'document',
|
|
262
|
+
'application/x-python': 'document',
|
|
263
|
+
'application/json': 'document',
|
|
264
|
+
};
|
|
265
|
+
/** Type-prefix wildcards accepted by `mimeAllowed`. */
|
|
266
|
+
export const MEDIA_WILDCARDS = ['image/*', 'audio/*', 'video/*'];
|
|
267
|
+
function mimesOf(kind) {
|
|
268
|
+
return Object.keys(MEDIA_INPUT_KINDS).filter((mime) => MEDIA_INPUT_KINDS[mime] === kind);
|
|
269
|
+
}
|
|
270
|
+
/** Attachment `accept` values the kernel can classify (wildcards + known types). */
|
|
271
|
+
export const ATTACHMENT_ACCEPT_MIMES = [
|
|
272
|
+
'image/*',
|
|
273
|
+
'video/*',
|
|
274
|
+
...mimesOf('image'),
|
|
275
|
+
...mimesOf('video'),
|
|
276
|
+
...mimesOf('document'),
|
|
277
|
+
];
|
|
278
|
+
/** Voice `accept` values the kernel can classify (wildcard + known audio types). */
|
|
279
|
+
export const VOICE_ACCEPT_MIMES = ['audio/*', ...mimesOf('audio')];
|
|
280
|
+
/** Providers allowed for a protocol. */
|
|
281
|
+
export function providersFor(protocol) {
|
|
282
|
+
return PROTOCOL_PROVIDERS[protocol];
|
|
283
|
+
}
|
|
284
|
+
/** Protocols allowed for a provider. */
|
|
285
|
+
export function protocolsFor(provider) {
|
|
286
|
+
const found = [];
|
|
287
|
+
for (const protocol of PROTOCOLS) {
|
|
288
|
+
if (PROTOCOL_PROVIDERS[protocol].includes(provider)) {
|
|
289
|
+
found.push(protocol);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return found;
|
|
293
|
+
}
|
|
294
|
+
/** True when `createProvider` will accept this pair. */
|
|
295
|
+
export function isValidPair(protocol, provider) {
|
|
296
|
+
return PROTOCOL_PROVIDERS[protocol].includes(provider);
|
|
297
|
+
}
|
|
298
|
+
/** When protocol changes, snap provider to a valid partner. */
|
|
299
|
+
export function coerceProvider(protocol, provider) {
|
|
300
|
+
const allowed = providersFor(protocol);
|
|
301
|
+
const [first] = allowed;
|
|
302
|
+
return allowed.includes(provider) ? provider : first;
|
|
303
|
+
}
|
|
304
|
+
/** When provider changes, snap protocol to a valid partner. */
|
|
305
|
+
export function coerceProtocol(protocol, provider) {
|
|
306
|
+
const allowed = protocolsFor(provider);
|
|
307
|
+
const [first] = allowed;
|
|
308
|
+
return allowed.includes(protocol) ? protocol : first;
|
|
309
|
+
}
|
|
310
|
+
function unionType(values) {
|
|
311
|
+
return values.map((value) => `'${value}'`).join(' | ');
|
|
312
|
+
}
|
|
313
|
+
function field(type, doc, options, optionDescriptionsOrNote, optionNote) {
|
|
314
|
+
if (options) {
|
|
315
|
+
if (typeof optionDescriptionsOrNote === 'object') {
|
|
316
|
+
return optionNote
|
|
317
|
+
? { type, doc, options, optionDescriptions: optionDescriptionsOrNote, optionNote }
|
|
318
|
+
: { type, doc, options, optionDescriptions: optionDescriptionsOrNote };
|
|
319
|
+
}
|
|
320
|
+
if (typeof optionDescriptionsOrNote === 'string') {
|
|
321
|
+
return { type, doc, options, optionNote: optionDescriptionsOrNote };
|
|
322
|
+
}
|
|
323
|
+
return { type, doc, options };
|
|
324
|
+
}
|
|
325
|
+
return { type, doc };
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Parents whose next key is a host-owned map key (model id, slot name, …).
|
|
329
|
+
* The annotator substitutes `*` so `models.flash.apiId` → `models.*.apiId`.
|
|
330
|
+
*/
|
|
331
|
+
export const DYNAMIC_FIELD_PARENTS = new Set([
|
|
332
|
+
'models',
|
|
333
|
+
'models.*.efforts',
|
|
334
|
+
'identity.systemByRole',
|
|
335
|
+
'inputs.slots',
|
|
336
|
+
'inputs.limitsByMime',
|
|
337
|
+
'outputs.validation.fields',
|
|
338
|
+
]);
|
|
339
|
+
/** Resolve a key stack from authored source into a catalog path. */
|
|
340
|
+
export function catalogPathFor(keys) {
|
|
341
|
+
const resolved = [];
|
|
342
|
+
for (const key of keys) {
|
|
343
|
+
const prefix = resolved.join('.');
|
|
344
|
+
if (DYNAMIC_FIELD_PARENTS.has(prefix)) {
|
|
345
|
+
resolved.push('*');
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
resolved.push(key);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return resolved.join('.');
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Authoring-surface catalog for `Profile` / `defineProfile`.
|
|
355
|
+
* Hover UIs look up dotted paths. Adding a profile field? Add it here.
|
|
356
|
+
*/
|
|
357
|
+
export const PROFILE_FIELDS = {
|
|
358
|
+
id: field('string', 'Host-owned profile identifier.'),
|
|
359
|
+
type: field("'text' | 'image' | 'speech' | 'live' | 'host'", 'Required profile archetype. host = tool-execution ceiling for invokeTool; never runs a model.'),
|
|
360
|
+
identity: field('{ handle, system?, systemByRole? }', 'Display handle and system instruction the model receives each turn.'),
|
|
361
|
+
'identity.handle': field('string', 'Public handle for this agent.'),
|
|
362
|
+
'identity.system': field('string', 'System instruction merged into every turn.'),
|
|
363
|
+
'identity.systemByRole': field('Record<string, string>', 'Optional system instruction keyed by turn role.'),
|
|
364
|
+
'identity.systemByRole.*': field('string', 'System instruction merged when this turn role is active.'),
|
|
365
|
+
models: field('Record<ModelId, ModelBinding>', 'Host-named model bindings. Keys are model ids; each entry carries protocol, provider, and wire config.'),
|
|
366
|
+
'models.*': field('ModelBinding', 'Wire binding for one host-named model id.'),
|
|
367
|
+
'models.*.protocol': field(unionType(PROTOCOLS), 'Wire protocol for this model. Must be valid for profile type.', PROTOCOLS, {
|
|
368
|
+
geminiInteractions: 'Google Gemini Interactions wire protocol (Gemini 2.5 / 3+).',
|
|
369
|
+
geminiLive: 'Gemini Live bidirectional WebSocket protocol.',
|
|
370
|
+
openAi: 'OpenAI-compatible chat completions and streaming protocol.',
|
|
371
|
+
}),
|
|
372
|
+
'models.*.provider': field(unionType(PROVIDERS), 'Transport for this model. Must form a legal pair with protocol.', PROVIDERS, {
|
|
373
|
+
google: 'Direct Google Gemini API transport.',
|
|
374
|
+
openrouter: 'OpenRouter multi-provider API proxy.',
|
|
375
|
+
local: 'Local OpenAI-compatible server (Ollama, llama.cpp, vLLM).',
|
|
376
|
+
}),
|
|
377
|
+
'models.*.apiId': field('string', 'Provider wire model id.'),
|
|
378
|
+
'models.*.efforts': field('Record<string, ThinkingLevel>', 'Alias → thinking level. One entry = fixed; two+ may be selectable at turn time.'),
|
|
379
|
+
'models.*.efforts.*': field(unionType(THINKING_LEVELS), 'Wire thinking level for this effort alias.', THINKING_LEVELS, {
|
|
380
|
+
none: 'Disable reasoning tokens completely.',
|
|
381
|
+
minimal: 'Minimal reasoning tokens for fastest response.',
|
|
382
|
+
low: 'Low reasoning budget for basic structured tasks.',
|
|
383
|
+
medium: 'Balanced reasoning for multi-step agent actions.',
|
|
384
|
+
high: 'Deep reasoning for complex planning and code.',
|
|
385
|
+
xhigh: 'Extended reasoning budget for hard problems.',
|
|
386
|
+
max: 'Maximum reasoning tokens supported by model.',
|
|
387
|
+
}),
|
|
388
|
+
'models.*.defaultEffort': field('string', 'Effort alias when the turn omits effort.'),
|
|
389
|
+
'models.*.allowEffortSelect': field('boolean', 'Turn may pass effort. Requires two or more efforts keys.'),
|
|
390
|
+
'models.*.summaries': field('boolean', 'Emit thinking summaries on the stream.'),
|
|
391
|
+
'models.*.maxOutputTokens': field('number', 'Maximum tokens the model may emit.'),
|
|
392
|
+
'models.*.temperature': field('number', 'Sampling temperature.'),
|
|
393
|
+
'models.*.builtInTools': field('BuiltinToolId[]', 'Provider-native builtins enabled whenever this model is selected.'),
|
|
394
|
+
'models.*.key': field(unionType(KEY_SLOTS), 'Optional vault slot for this model. Overrides profile.key.', KEY_SLOTS),
|
|
395
|
+
'models.*.compaction': field('CompactionSpec', 'Optional compaction policy for this model.'),
|
|
396
|
+
'models.*.compaction.maxTokens': field('number', 'Token budget compared by the trigger (compactAt * maxTokens).'),
|
|
397
|
+
'models.*.compaction.compactAt': field('number', 'Fraction of maxTokens at which compaction fires. Must be in (0, 1).'),
|
|
398
|
+
'models.*.compaction.previousExchanges': field('number', '≥ 1 = exchange count, (0, 1) = fraction of maxTokens, 0 = compact all.'),
|
|
399
|
+
'models.*.compaction.profile': field('ProfileId', 'Compaction agent profile id. Must be registered before the owning profile.'),
|
|
400
|
+
'models.*.compaction.timing': field(unionType(COMPACTION_TIMINGS), 'When compaction runs relative to the primary turn.', COMPACTION_TIMINGS, {
|
|
401
|
+
before: 'Compact synchronously before running the turn request.',
|
|
402
|
+
after: 'Signal on done for host async background compaction.',
|
|
403
|
+
}),
|
|
404
|
+
'models.*.compaction.meter': field(unionType(COMPACTION_METERS), 'What the threshold meters. Defaults to history.', COMPACTION_METERS, {
|
|
405
|
+
history: 'Meters token count across prior conversation turns.',
|
|
406
|
+
input: 'Meters full turn input token count (system + history + attachments).',
|
|
407
|
+
}),
|
|
408
|
+
'models.*.cache': field('CacheSpec', 'OpenRouter prompt-cache policy. Only valid when provider is openrouter.'),
|
|
409
|
+
'models.*.cache.mode': field(unionType(CACHE_MODES), 'How to place cache_control on OpenRouter requests.', CACHE_MODES, {
|
|
410
|
+
automatic: 'Top-level cache_control; breakpoint advances with the conversation.',
|
|
411
|
+
system: 'Explicit cache_control breakpoint on the system instruction only.',
|
|
412
|
+
}),
|
|
413
|
+
'models.*.cache.ttl': field(unionType(CACHE_TTLS), 'Ephemeral cache TTL. Omit → provider default (typically 5m on Anthropic).', CACHE_TTLS, {
|
|
414
|
+
'5m': 'Five-minute ephemeral cache (default when ttl is omitted).',
|
|
415
|
+
'1h': 'One-hour ephemeral cache (higher write cost; better for long sessions).',
|
|
416
|
+
}),
|
|
417
|
+
'models.*.store': field('boolean', 'Gemini Interactions: whether the provider stores the interaction. Omit → provider default.'),
|
|
418
|
+
'models.*.persistViaInteractionId': field('boolean', 'Gemini Interactions: prefer previous_interaction_id over client-owned history. Omit → host/turn decides.'),
|
|
419
|
+
defaultModel: field('ModelId', 'Default model id when the turn omits model.'),
|
|
420
|
+
allowModelSelect: field('boolean', 'Turn may pass model. Requires two or more models keys.'),
|
|
421
|
+
maxSteps: field('number', 'Tool-loop ceiling. <=0 unbounded, 1 one-shot, >1 ceiling. Omit → unbounded.'),
|
|
422
|
+
key: field(unionType(OVERFLOW_KEY_SLOTS), 'Vault key slot (slotA/B/C). Paid is overflow-only via models.*.key or forcePaidKey builtins.', OVERFLOW_KEY_SLOTS),
|
|
423
|
+
tools: field('{ allow: ToolId[]; t1Policy?; t2Loader? }', 'Custom tools (allow), optional T1 policy, optional T2 loader function id. Builtins belong on models.*.builtInTools. Live and host profiles use `{ allow }` only — live wires every allowed tool at session setup; host executes every allowed tool.'),
|
|
424
|
+
'tools.allow': field('ToolId[]', 'Custom tools the agent may call. Builtins are declared per model, not here. On type live every listed id is wired at session setup regardless of loadTier; on type host every listed id is executable.'),
|
|
425
|
+
'tools.t1Policy': field('(ctx) => ToolId[] | Promise<ToolId[]>', 'Optional T1 policy — which eligible loadTier:T1 tools to wire at turn start. Not supported on type live.'),
|
|
426
|
+
'tools.t2Loader': field('ToolId', 'Optional function tool id for T2 promotion. Must be in tools.allow; handler returns { loaded: string[] }. Not supported on type live.'),
|
|
427
|
+
inputs: field('ProfileInputsSpec', 'Text, attachment, voice, slot, and size rules.'),
|
|
428
|
+
'inputs.text': field('boolean', 'Whether the profile accepts text on a turn. False rejects text.'),
|
|
429
|
+
'inputs.attachments': field('{ accept: string[] }', 'File upload allowlist.'),
|
|
430
|
+
'inputs.attachments.accept': field('string[]', 'MIME allowlist for uploaded files. Type-prefix wildcards (image/*, …) are allowed.', ATTACHMENT_ACCEPT_MIMES, 'Kernel-known types (plus wildcards). Hosts may list any MIME; unknown types are rejected at ingress.'),
|
|
431
|
+
'inputs.voice': field('{ accept: string[] }', 'Voice ingress block — not a bare string. Use accept for audio MIME allowlist.'),
|
|
432
|
+
'inputs.voice.accept': field('string[]', 'MIME allowlist for voice blobs. audio/* wildcards are allowed.', VOICE_ACCEPT_MIMES, 'Kernel-known audio types (plus audio/*).'),
|
|
433
|
+
'inputs.maxFiles': field('number', 'Max files per turn. Required when attachments or voice is set.'),
|
|
434
|
+
'inputs.maxBytes': field('number', 'Max bytes per file. Required when attachments or voice is set.'),
|
|
435
|
+
'inputs.maxTurnBytes': field('number', 'Max total bytes per turn. Required when attachments or voice is set.'),
|
|
436
|
+
'inputs.limitsByMime': field('Record<string, number>', 'Optional per-MIME byte caps.'),
|
|
437
|
+
'inputs.limitsByMime.*': field('number', 'Maximum byte limit for files of this MIME type.'),
|
|
438
|
+
'inputs.slots': field('Record<string, string[]>', 'Optional turn-time selectors (e.g. language: ["html", "tsx"]).'),
|
|
439
|
+
'inputs.slots.*': field('string[]', 'Allowed choices for this turn selector.'),
|
|
440
|
+
outputs: field('ProfileOutputsSpec', 'Structured, validation, and streaming output policy.'),
|
|
441
|
+
'outputs.structured': field('StructuredSchemaId | StructuredBySlot | null', 'Registered schema id, slot-mapped ids, or null for free text.'),
|
|
442
|
+
image: field('ProfileImageSpec', 'Pins for an image-role profile. Model id is on model.'),
|
|
443
|
+
'image.aspectRatio': field('string', 'Optional output aspect ratio. Omitted → provider default.'),
|
|
444
|
+
'image.size': field('string', 'Optional output size / resolution. Omitted → provider default.'),
|
|
445
|
+
'image.mimeType': field('string', 'Output MIME for generated images.'),
|
|
446
|
+
'image.maxInputImages': field('number', 'Cap on reference images in one turn.'),
|
|
447
|
+
'image.includeText': field('boolean', 'When true, request interleaved assistant text alongside generated images.'),
|
|
448
|
+
speech: field('ProfileSpeechSpec', 'TTS pins. Model id is on model.'),
|
|
449
|
+
'speech.voice': field('string', 'TTS voice id. Kernel accepts any string; Google preset narrows to named voices.'),
|
|
450
|
+
'speech.format': field(unionType(SPEECH_AUDIO_FORMATS), 'pcm (default) → WAV on both transports. mp3 requires protocol openAi.', SPEECH_AUDIO_FORMATS, {
|
|
451
|
+
pcm: 'Raw 24kHz 16-bit PCM audio (→ WAV container). Supported by Google and OpenAI.',
|
|
452
|
+
mp3: 'MP3 encoded stream. Requires openAi protocol.',
|
|
453
|
+
}),
|
|
454
|
+
live: field('ProfileLiveSpec', 'Bidirectional live audio/video streaming session pins.'),
|
|
455
|
+
'live.ingress': field('LiveIngressSpec', 'Realtime ingress toggles for sendAudio / sendVideo / sendText — not turn file attachments.'),
|
|
456
|
+
'live.ingress.audio': field('boolean', 'Microphone PCM via LiveSession.sendAudio. Omit → enabled.'),
|
|
457
|
+
'live.ingress.video': field('boolean', 'Webcam JPEG frames via LiveSession.sendVideo. Omit → enabled.'),
|
|
458
|
+
'live.ingress.text': field('boolean', 'Typed text via LiveSession.sendText. Omit → disabled.'),
|
|
459
|
+
'live.voice': field('string', 'TTS voice name for live audio output (e.g. Puck, Aoede, Charon).', GOOGLE_SPEECH_VOICES, 'Google preset vocabulary; kernel accepts any string.'),
|
|
460
|
+
'live.vad': field('LiveVadSpec', 'Voice activity detection, barge-in, and endpointing sensitivity.'),
|
|
461
|
+
'live.vad.activityHandling': field(unionType(LIVE_ACTIVITY_HANDLINGS), 'Barge-in handling when user speaks.', LIVE_ACTIVITY_HANDLINGS),
|
|
462
|
+
'live.vad.startSensitivity': field(unionType(LIVE_SPEECH_SENSITIVITIES), 'Sensitivity for detecting start of speech.', LIVE_SPEECH_SENSITIVITIES),
|
|
463
|
+
'live.vad.endSensitivity': field(unionType(LIVE_SPEECH_SENSITIVITIES), 'Sensitivity for detecting end of speech.', LIVE_SPEECH_SENSITIVITIES),
|
|
464
|
+
'live.vad.prefixPaddingMs': field('number', 'Speech prefix buffer duration in ms.'),
|
|
465
|
+
'live.vad.silenceDurationMs': field('number', 'Required silence before committing end-of-speech in ms.'),
|
|
466
|
+
'live.sessionResumption': field('boolean', 'Enable session resumption handles across WebSocket reconnects.'),
|
|
467
|
+
'live.contextCompression': field(unionType(LIVE_CONTEXT_COMPRESSIONS), 'Context window compression mechanism.', LIVE_CONTEXT_COMPRESSIONS),
|
|
468
|
+
'live.proactiveAudio': field('boolean', 'Allow model to reject responding or stay silent if unprompted.'),
|
|
469
|
+
'live.transcription': field('LiveTranscriptionSpec', 'Enable real-time input/output audio transcriptions.'),
|
|
470
|
+
'live.transcription.input': field('boolean', 'Transcribe user input speech.'),
|
|
471
|
+
'live.transcription.output': field('boolean', 'Transcribe model output speech.'),
|
|
472
|
+
'outputs.validation': field('ProfileValidationSpec', 'Host domain validators and repair policy.'),
|
|
473
|
+
'outputs.validation.fields': field('Record<string, ProfileValidator>', 'Validators keyed by dotted paths into structured output (e.g. diagram.mermaid).'),
|
|
474
|
+
'outputs.validation.fields.*': field('(source: unknown) => { isValid: boolean; error?: string }', 'Host-owned validator function for this structured output field.'),
|
|
475
|
+
'outputs.validation.maxRetries': field('number', 'Repair-turn ceiling after a validator reject.'),
|
|
476
|
+
'outputs.validation.repairGuidance': field('string', 'Instruction appended on a validation repair turn.'),
|
|
477
|
+
'outputs.streaming': field('ProfileStreamingSpec', 'How the turn emits live events.'),
|
|
478
|
+
'outputs.streaming.mode': field(unionType(STREAM_MODES), 'sse or buffered. Omit → THEORUM SSE default (ResolvedGeneration.stream = true).', STREAM_MODES, {
|
|
479
|
+
sse: 'Server-Sent Events emitting live incremental TurnEvents (THEORUM default when mode omitted).',
|
|
480
|
+
buffered: 'Buffers response into a single completed turn event.',
|
|
481
|
+
}),
|
|
482
|
+
'outputs.streaming.streamThoughts': field('boolean', 'Emit model thinking on the turn stream.'),
|
|
483
|
+
turnBehaviour: field('ProfileTurnBehaviourSpec', 'Resume after a non-user stop (text/image/speech); text and live may also allow mid-turn inject via allowSteering.'),
|
|
484
|
+
'turnBehaviour.resumption': field('ProfileTurnResumptionSpec', 'Continue after a non-user stop (continueFrom). Not valid on live — use live.sessionResumption.'),
|
|
485
|
+
'turnBehaviour.resumption.allowContinue': field('ContinueStopKind[]', 'Kinds eligible for a Continue / continueFrom turn. Not tool/cancelled/completed/filtered/live boundaries.', CONTINUE_STOP_KINDS, {
|
|
486
|
+
length: 'Model hit maximum output token ceiling.',
|
|
487
|
+
stream_incomplete: 'Network connection or stream dropped prematurely.',
|
|
488
|
+
provider_error: 'Upstream provider returned an error code or timeout.',
|
|
489
|
+
}),
|
|
490
|
+
'turnBehaviour.resumption.autoContinue': field('ContinueStopKind[]', 'Kinds the host may auto-continue once without a CTA. Subset of ContinueStopKind.', CONTINUE_STOP_KINDS, {
|
|
491
|
+
length: 'Model hit maximum output token ceiling.',
|
|
492
|
+
stream_incomplete: 'Network connection or stream dropped prematurely.',
|
|
493
|
+
provider_error: 'Upstream provider returned an error code or timeout.',
|
|
494
|
+
}),
|
|
495
|
+
'turnBehaviour.resumption.maxContinues': field('number', 'Max continueFrom rounds the kernel accepts (compared to TurnRequest.continuation).'),
|
|
496
|
+
'turnBehaviour.resumption.continueInstruction': field('string', 'Host replacement for the continue instruction appended on continueFrom turns. Omitted: registered default.'),
|
|
497
|
+
'turnBehaviour.allowSteering': field('boolean', 'Text and live. When true (default), host onStage inject affordances are applied. Image/speech must omit.'),
|
|
498
|
+
guardrails: field('ProfileGuardrailsSpec', 'Quota, canary, sanitize, redact, egress, network, and taint switches. On type host only the invokeTool-path guards are accepted (HostGuardrailsSpec: sanitizeInput, redactSensitive, network, taint) — quota, canary, and egress guard a model turn and are refused.'),
|
|
499
|
+
'guardrails.quota': field('QuotaGuardrailSpec', 'Host HTTP helper — not enforced inside runTurn.'),
|
|
500
|
+
'guardrails.quota.perDay': field('number', 'Daily turn cap used by host quota middleware.'),
|
|
501
|
+
'guardrails.quota.message': field('string', 'Host copy surfaced by quotaExhausted when the quota trips. The kernel ships no fallback.'),
|
|
502
|
+
'guardrails.canary': field('boolean | CanaryGuardrailSpec', 'Per-turn canary token bound to system prompt. Default true; set false to opt out; object form supplies bindNote.'),
|
|
503
|
+
'guardrails.canary.bindNote': field('string', 'Host template appended to the system prompt; must contain the {canary} placeholder. Omitted: registered default.'),
|
|
504
|
+
'guardrails.sanitizeInput': field('boolean', 'Strip inbound injection spans.'),
|
|
505
|
+
'guardrails.redactSensitive': field('boolean', 'Redact sensitive spans.'),
|
|
506
|
+
'guardrails.egress': field('ProfileEgressSpec', 'Host check before user-visible text is released.'),
|
|
507
|
+
'guardrails.egress.enforce': field('EgressEnforcer', 'Host function: (context) => { blocked, text, … }.'),
|
|
508
|
+
'guardrails.egress.onBlock': field(unionType(EGRESS_ON_BLOCK), 'reject_to_agent retries; refuse_to_user stops the turn.', EGRESS_ON_BLOCK, {
|
|
509
|
+
reject_to_agent: 'Feeds rejection error back to model for automatic repair turn.',
|
|
510
|
+
refuse_to_user: 'Halts turn immediately and returns refusal to user.',
|
|
511
|
+
}),
|
|
512
|
+
'guardrails.egress.maxRetries': field('number', 'Repair-turn ceiling after an egress block.'),
|
|
513
|
+
'guardrails.egress.repairGuidance': field('string', 'Instruction appended on an egress repair turn.'),
|
|
514
|
+
'guardrails.network': field('NetworkGuardrailSpec', 'SSRF guardrails for declarative HTTP and MCP tools.'),
|
|
515
|
+
'guardrails.network.allowPrivateNetworks': field('boolean', 'Allow loopback and private-network targets when resolving tool URLs.'),
|
|
516
|
+
'guardrails.network.allowedHosts': field('string[]', 'Explicit hostname allowlist for declarative HTTP and MCP egress.'),
|
|
517
|
+
observability: field('ProfileObservabilitySpec', 'Trace destination, scrub, include, and sampling policy for this profile.'),
|
|
518
|
+
'observability.writeTo': field('false | string | TraceSink', 'false = off; string = registerTraceDestination id; TraceSink = inline writer. runTurn third arg overrides.'),
|
|
519
|
+
'observability.sampleRate': field('number', 'Fraction of turns to record (0–1). Default 1. Ignored when runTurn passes an explicit sink.'),
|
|
520
|
+
'observability.include': field('TraceIncludeSpec', 'Which TraceRecord payloads to keep (upstreamLog, outboundWire, evidenceRaw, usage, guardrailDecisions, guardrailMatchPreview).'),
|
|
521
|
+
'observability.include.upstreamLog': field('boolean', 'Scrubbed provider HTTP/SSE rows. Default true.'),
|
|
522
|
+
'observability.include.outboundWire': field('boolean', 'Scrubbed outbound request body. Default false.'),
|
|
523
|
+
'observability.include.evidenceRaw': field('boolean', 'Verbatim provider step JSON on events. Default false.'),
|
|
524
|
+
'observability.include.usage': field('boolean', 'Token / usage fields. Default true.'),
|
|
525
|
+
'observability.include.guardrailDecisions': field('boolean', 'Persist { type: "guardrail" } decisions in the TraceRecord. Default true.'),
|
|
526
|
+
'observability.include.guardrailMatchPreview': field('boolean', 'Keep GuardrailHit.match (capped matched substring) on stream + TraceRecord. Default false — debugging only.'),
|
|
527
|
+
'observability.scrub': field('TraceScrubSpec', 'Scrubbing of stored records — independent of profile.guardrails. Defaults on.'),
|
|
528
|
+
'observability.scrub.sensitive': field('boolean', 'Strip credentials / PII spans in stored text. Default true.'),
|
|
529
|
+
'observability.scrub.injection': field('boolean', 'Strip injection spans in the stored request copy. Default true.'),
|
|
530
|
+
'observability.scrub.canary': field('boolean', 'Never persist the canary token. Default true.'),
|
|
531
|
+
'observability.retainForDays': field('number', 'JSONL retention days when writeTo resolves to a jsonl destination. Default 14.'),
|
|
532
|
+
'observability.rotateAfterMiB': field('number', 'JSONL rotate threshold in MiB when writeTo resolves to a jsonl destination. Default 32.'),
|
|
533
|
+
'observability.onWriteError': field('(err: unknown) => void', 'Host hook when record build or destination write fails. Must not throw.'),
|
|
534
|
+
};
|
|
535
|
+
const TOOL_TYPE_FIELD = field(unionType(TOOL_TYPES), 'Discriminator: builtin (provider-native), function (host handler), http (declarative HTTP), or mcp (remote MCP).', TOOL_TYPES, {
|
|
536
|
+
builtin: 'Provider-native capability; wire maps to the provider adapter.',
|
|
537
|
+
function: 'Host-owned tool with Zod input/output and a handler. Profile tools.t2Loader may promote T2 tools when output includes { loaded }.',
|
|
538
|
+
http: 'Declarative HTTP tool calling remote REST/JSON endpoint with optional auth/PKCE.',
|
|
539
|
+
mcp: 'Remote Model Context Protocol tool calling remote MCP server with JSON-RPC.',
|
|
540
|
+
});
|
|
541
|
+
/** Adjacent tool catalog fields that appear next to profile examples. */
|
|
542
|
+
export const EXTRA_FIELDS = {
|
|
543
|
+
/** Playground / UI path — avoids collision with profile `type` in fieldMeta(). */
|
|
544
|
+
'registerTool.type': TOOL_TYPE_FIELD,
|
|
545
|
+
name: field('string', 'Wire tool id — custom: tools.allow; provider builtin: models.*.builtInTools. Visibility via loadTier (T0/T1/T2).'),
|
|
546
|
+
description: field('string', 'Model-facing description included in function declarations.'),
|
|
547
|
+
input: field('ZodSchema', 'Zod input schema for function tools; converted to JSON Schema at registration.'),
|
|
548
|
+
output: field('ZodSchema', 'Zod output schema for function tools; validates handler results.'),
|
|
549
|
+
handler: field('ToolHandler', 'Host function or async generator run on model tool calls and invokeTool resumes.'),
|
|
550
|
+
endpoint: field('string', 'HTTP URL template for declarative tools. Use {param} placeholders for path segments.'),
|
|
551
|
+
method: field(unionType(HTTP_METHODS), 'HTTP verb for declarative tools.', HTTP_METHODS),
|
|
552
|
+
headers: field('Record<string, string>', 'Optional static headers merged on every HTTP or MCP request.'),
|
|
553
|
+
mapping: field('{ pathParams?, queryParams?, bodyParam? }', 'Maps tool input fields to URL path segments, query string, or JSON body.'),
|
|
554
|
+
'mapping.pathParams': field('string[]', 'Input keys substituted into {name} path segments on the endpoint template.'),
|
|
555
|
+
'mapping.queryParams': field('string[]', 'Input keys appended as query-string parameters.'),
|
|
556
|
+
'mapping.bodyParam': field('string', 'Single input key sent as the JSON request body (POST/PUT/PATCH).'),
|
|
557
|
+
serverUrl: field('string', 'Streamable HTTP MCP server endpoint (JSON-RPC tools/call).'),
|
|
558
|
+
mcpToolName: field('string', 'Remote tool name on the MCP server (tools/list → tools/call).'),
|
|
559
|
+
auth: field('HttpToolAuthConfig', 'Optional credential slot and header wiring for HTTP and MCP tools.'),
|
|
560
|
+
'auth.type': field(unionType(TOOL_AUTH_TYPES), 'How credentials from the slot are attached to outbound requests.', TOOL_AUTH_TYPES, {
|
|
561
|
+
bearer: 'Authorization header with optional prefix (default Bearer).',
|
|
562
|
+
api_key: 'Named header carries the raw key or token.',
|
|
563
|
+
oauth2: 'OAuth2 access token with optional refresh via the credential slot.',
|
|
564
|
+
}),
|
|
565
|
+
'auth.slot': field('string', 'Credential slot id resolved from ToolContext.credentials at execution time.'),
|
|
566
|
+
'auth.headerName': field('string', "Request header for bearer/api_key auth (default 'Authorization')."),
|
|
567
|
+
'auth.headerPrefix': field('string', "Prefix before the secret (default 'Bearer ' for bearer auth)."),
|
|
568
|
+
'auth.onUnauthenticated': field(unionType(AUTH_UNAUTHENTICATED_POLICIES), 'Whether a missing/expired credential gates the turn or reports to the model.', AUTH_UNAUTHENTICATED_POLICIES, {
|
|
569
|
+
pause: 'Emit ToolGate { kind: auth } (tool.phase gate + stop.kind gate) and wait for host credential injection. Schema id remains `pause`.',
|
|
570
|
+
report_to_model: 'Return a model-visible finding without gating the turn.',
|
|
571
|
+
}),
|
|
572
|
+
'auth.scopes': field('string[]', 'OAuth2 scopes requested during authorization.'),
|
|
573
|
+
'auth.clientId': field('string', 'OAuth2 client id for the authorization code flow.'),
|
|
574
|
+
'auth.redirectUri': field('string', 'OAuth2 redirect URI registered for this client.'),
|
|
575
|
+
'playground.authType': field(unionType(PLAYGROUND_AUTH_TYPES), 'Playground auth select — `none` omits auth when compiling registerTool.', PLAYGROUND_AUTH_TYPES, {
|
|
576
|
+
none: 'No credential slot — tool runs without Authorization headers.',
|
|
577
|
+
bearer: 'Authorization header with optional prefix (default Bearer).',
|
|
578
|
+
api_key: 'Named header carries the raw key or token.',
|
|
579
|
+
oauth2: 'OAuth2 access token with optional refresh via the credential slot.',
|
|
580
|
+
}),
|
|
581
|
+
'playground.testCredential': field('string', 'Playground-only: one-shot credential for the pre-run connectivity check (not compiled into registerTool).'),
|
|
582
|
+
'playground.stubOutput': field('Record<string, unknown>', 'Playground-only: fixed JSON object returned by function tool stubs when no demo handler exists.'),
|
|
583
|
+
'registerStructured.enforced': field(unionType(SCHEMA_ENFORCEMENTS), 'How structured output is enforced on the wire.', SCHEMA_ENFORCEMENTS),
|
|
584
|
+
'registerStructured.jsonSchema': field('Record<string, unknown>', 'JSON Schema body registered under outputs.structured id.'),
|
|
585
|
+
access: field(unionType(TOOL_ACCESS), 'Semantic access level for policy and UI.', TOOL_ACCESS, {
|
|
586
|
+
'read-only': 'Reads host or remote state; no lasting mutation.',
|
|
587
|
+
'read-write': 'May create or update host state.',
|
|
588
|
+
destructive: 'May delete, charge, or otherwise hard-to-undo actions.',
|
|
589
|
+
}),
|
|
590
|
+
loadTier: field(unionType(TOOL_LOAD_TIERS), 'When this tool is wired to the model (profile allow / builtInTools is still required). Live sessions wire every allowed tool at setup; host profiles execute every allowed tool.', TOOL_LOAD_TIERS, {
|
|
591
|
+
T0: 'Wired at turn/session start when allowed (custom on allow / builtin on the model).',
|
|
592
|
+
T1: 'Wired when profile.tools.t1Policy selects it (text/image turns; live wires it at setup).',
|
|
593
|
+
T2: 'Deferred until profile.tools.t2Loader returns { loaded } and the kernel promotes those ids (text/image turns; live wires it at setup).',
|
|
594
|
+
}),
|
|
595
|
+
permission: field(unionType(TOOL_PERMISSION), 'Default permission tier for this tool before the handler runs.', TOOL_PERMISSION, {
|
|
596
|
+
auto: 'Run without an extra host consent step.',
|
|
597
|
+
session_consent: 'Ask once per session, then remember grant.',
|
|
598
|
+
always_confirm: 'Confirm on every invocation.',
|
|
599
|
+
}),
|
|
600
|
+
category: field('string', 'Grouping label for settings and discovery.'),
|
|
601
|
+
paths: field('string[]', "Channel/path availability. Use ['*'] for all paths; omit turn path only matches '*'."),
|
|
602
|
+
};
|
|
603
|
+
/** Look up hover metadata for a dotted path (profile first, then extra). */
|
|
604
|
+
export function fieldMeta(path) {
|
|
605
|
+
return PROFILE_FIELDS[path] ?? EXTRA_FIELDS[path];
|
|
606
|
+
}
|
|
607
|
+
export { PROFILE_GRAPH, profileGraphFacet, spineFacetsForProfileType, } from './profile-graph.js';
|