theorum 0.1.14 → 0.1.15
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 +2 -0
- package/docs/kernel.md +1 -1
- package/docs/providers.md +1 -0
- package/esm/src/kernel/engine/delta.js +92 -0
- package/esm/src/providers/provider.js +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
|
|
11
11
|
# THEORUM: The Flat Agent Kernel
|
|
12
12
|
|
|
13
|
+
**Current release: `0.1.15`** (`jsr:@theorum/core` / npm `theorum`).
|
|
14
|
+
|
|
13
15
|
> **"Profiles describe the contract. Providers move bytes. The runner enforces the turn."**
|
|
14
16
|
|
|
15
17
|
THEORUM is a compact TypeScript agent kernel for apps that need deterministic agent execution without embedding product logic inside the runtime. It gives a host application one runner, typed profiles, multimodal input normalization, dynamic tool dispatch, provider adapters, trace sinks, and guardrail hooks.
|
package/docs/kernel.md
CHANGED
|
@@ -102,7 +102,7 @@ different transport than the primary turn.
|
|
|
102
102
|
| `tool` | Tool call envelope (`ok` / `error` / `pause`) |
|
|
103
103
|
| `structured` | Parsed JSON object when schema enforced |
|
|
104
104
|
| `media` | Generated image/audio bytes + mime |
|
|
105
|
-
| `grounding` | Search/maps grounding metadata |
|
|
105
|
+
| `grounding` | Search/maps grounding metadata (classic `grounding_metadata` and Interactions tool results such as `google_search_result.search_suggestions`) |
|
|
106
106
|
| `evidence` | Provider-native evidence attachments |
|
|
107
107
|
| `tokens` | `input` / `output` / `total` usage (billing; may gate `meter: 'input'`) |
|
|
108
108
|
| `done` | Terminal: `stop`, `tokens`, `compaction`, final text pointer |
|
package/docs/providers.md
CHANGED
|
@@ -76,6 +76,7 @@ OpenRouter Vercel AI SDK loads **only** on first `complete` for `openAi` +
|
|
|
76
76
|
| Structured | `responseFormat` JSON schema when enforced |
|
|
77
77
|
| Output modes | Image / speech / structured are mutually exclusive |
|
|
78
78
|
| Tools | Catalog `interactionsType` + plugins |
|
|
79
|
+
| Grounding | Classic `grounding_metadata` **and** Interactions `google_search_result` / maps tool payloads (`search_suggestions` chips, annotations). Emits `grounding` (normalized) plus `evidence` with the raw tool payload so hosts can decide what to surface. |
|
|
79
80
|
| Stop | `turnStopFromInteractionStatus` on terminal status |
|
|
80
81
|
|
|
81
82
|
## Local provider
|
|
@@ -168,6 +168,96 @@ function searchHtml(metadata) {
|
|
|
168
168
|
}
|
|
169
169
|
return undefined;
|
|
170
170
|
}
|
|
171
|
+
function nonEmptyString(value) {
|
|
172
|
+
if (typeof value === 'string' && value.trim()) {
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
function searchSuggestionsFromRecord(record) {
|
|
178
|
+
return nonEmptyString(record.search_suggestions ?? record.searchSuggestions);
|
|
179
|
+
}
|
|
180
|
+
function firstSearchSuggestions(items) {
|
|
181
|
+
if (!Array.isArray(items)) {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
for (const item of items) {
|
|
185
|
+
const record = asRecord(item);
|
|
186
|
+
if (!record) {
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
const html = searchSuggestionsFromRecord(record);
|
|
190
|
+
if (html) {
|
|
191
|
+
return html;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
/** Interactions streams search chips as `search_suggestions` HTML, not classic entry points. */
|
|
197
|
+
function searchSuggestionsHtml(step) {
|
|
198
|
+
return (searchSuggestionsFromRecord(step) ??
|
|
199
|
+
firstSearchSuggestions(step.result) ??
|
|
200
|
+
firstSearchSuggestions(step.content));
|
|
201
|
+
}
|
|
202
|
+
function sourceFromAnnotation(ann) {
|
|
203
|
+
const record = asRecord(ann);
|
|
204
|
+
if (!record) {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
const uri = nonEmptyString(record.url ?? record.uri);
|
|
208
|
+
if (!uri) {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
const kind = String(record.type ?? '');
|
|
212
|
+
const title = nonEmptyString(record.title ?? record.name) ?? uri;
|
|
213
|
+
if (kind === 'place_citation') {
|
|
214
|
+
return { type: 'maps', uri, title };
|
|
215
|
+
}
|
|
216
|
+
if (kind === 'url_citation' || kind === 'citation' || !kind) {
|
|
217
|
+
return { type: 'web', uri, title };
|
|
218
|
+
}
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
function appendAnnotationSources(into, annotations) {
|
|
222
|
+
for (const source of sourcesFromAnnotations(annotations)) {
|
|
223
|
+
pushUniqueSource(into, source);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function sourcesFromAnnotations(annotations) {
|
|
227
|
+
if (!Array.isArray(annotations)) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
const sources = [];
|
|
231
|
+
for (const ann of annotations) {
|
|
232
|
+
pushUniqueSource(sources, sourceFromAnnotation(ann));
|
|
233
|
+
}
|
|
234
|
+
return sources;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Wrap Interactions tool-result steps (google_search_result, maps, etc.) into grounding.
|
|
238
|
+
* Preserves the raw step on `metadata` so hosts can inspect everything Gemini returned.
|
|
239
|
+
*/
|
|
240
|
+
function groundingFromInteractionsTool(step) {
|
|
241
|
+
const sources = [];
|
|
242
|
+
appendAnnotationSources(sources, step.annotations);
|
|
243
|
+
if (Array.isArray(step.content)) {
|
|
244
|
+
for (const block of step.content) {
|
|
245
|
+
const record = asRecord(block);
|
|
246
|
+
if (record) {
|
|
247
|
+
appendAnnotationSources(sources, record.annotations);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
const html = searchSuggestionsHtml(step);
|
|
252
|
+
if (!html && sources.length === 0) {
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
return {
|
|
256
|
+
metadata: step,
|
|
257
|
+
...(html ? { searchHtml: html } : {}),
|
|
258
|
+
sources,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
171
261
|
function sourcesFromChunks(chunks) {
|
|
172
262
|
const sources = [];
|
|
173
263
|
for (const chunk of chunks) {
|
|
@@ -238,6 +328,8 @@ function groundingFromStep(stepValue) {
|
|
|
238
328
|
grounding = mergeGrounding(grounding, groundingFromMetadata(groundingMetadataFromRecord(asRecord(block) ?? {})));
|
|
239
329
|
}
|
|
240
330
|
}
|
|
331
|
+
// Interactions search/maps tool results: chips + citations live on the step/delta itself.
|
|
332
|
+
grounding = mergeGrounding(grounding, groundingFromInteractionsTool(step));
|
|
241
333
|
return grounding;
|
|
242
334
|
}
|
|
243
335
|
function groundingFromEvent(event) {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { isAbortError, TheorumError, toErrorEvent } from '../guardrails/error.js';
|
|
12
12
|
import { eventsFromComplete, eventsFromDelta, extractTokenEvent, groundingFromEvent, tryStructured, } from '../kernel/engine/delta.js';
|
|
13
|
+
import { asRecord } from '../kernel/engine/record.js';
|
|
13
14
|
import { exposeForTests } from './expose-for-tests.js';
|
|
14
15
|
import { tapFetch } from './google-tap.js';
|
|
15
16
|
import { toInteractionsBody } from './interactions.js';
|
|
@@ -109,8 +110,32 @@ function foldPayload(event, acc) {
|
|
|
109
110
|
if (groundingEvent && !events.some((e) => e.type === 'grounding')) {
|
|
110
111
|
events.push(groundingEvent);
|
|
111
112
|
}
|
|
113
|
+
const evidenceEvent = evidenceFromGooglePayload(event);
|
|
114
|
+
if (evidenceEvent && !events.some((e) => e.type === 'evidence')) {
|
|
115
|
+
events.push(evidenceEvent);
|
|
116
|
+
}
|
|
112
117
|
return events;
|
|
113
118
|
}
|
|
119
|
+
/** Preserve raw Google Interactions tool payloads so hosts can inspect everything returned. */
|
|
120
|
+
function evidenceFromGooglePayload(event) {
|
|
121
|
+
for (const key of ['delta', 'step']) {
|
|
122
|
+
const payload = asRecord(event[key]);
|
|
123
|
+
if (!payload) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const type = String(payload.type ?? '');
|
|
127
|
+
if (type === 'google_search_result' ||
|
|
128
|
+
type === 'google_maps' ||
|
|
129
|
+
type === 'google_maps_result' ||
|
|
130
|
+
type.startsWith('google_')) {
|
|
131
|
+
return {
|
|
132
|
+
type: 'evidence',
|
|
133
|
+
evidence: { provider: 'google', raw: payload },
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
114
139
|
function withTap(req, transport) {
|
|
115
140
|
return {
|
|
116
141
|
...transport,
|
|
@@ -172,5 +197,6 @@ exposeForTests('provider', {
|
|
|
172
197
|
isCompleteEvent,
|
|
173
198
|
foldDeltaPayload,
|
|
174
199
|
foldPayload,
|
|
200
|
+
evidenceFromGooglePayload,
|
|
175
201
|
withTap,
|
|
176
202
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "theorum",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "A flat TypeScript agent kernel for typed profiles, deterministic turn execution, dynamic tools, provider adapters, guardrails, and host-injected traces.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|