@theoremjs/agents 0.3.4-next.480.ge8c8d47 → 0.3.4-next.484.g20d8b9d
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.
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type Protocol } from '../../kernel/protocols/mod.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/**
|
|
3
|
+
* OpenRouter's decision API: questions about a state, answered in one call. It takes no options:
|
|
4
|
+
* images and box questions need no opt-in, and a request with an image runs in long context.
|
|
5
|
+
*/
|
|
6
|
+
export declare const openRouterDecisions: Protocol<Record<string, never>>;
|
|
@@ -1,9 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { jsonObjectSchema } from '../../kernel/json.js';
|
|
3
|
+
import { defineProtocol } from '../../kernel/protocols/mod.js';
|
|
4
|
+
import { decisionAnswered } from '../system-one/protocol.js';
|
|
5
|
+
/**
|
|
6
|
+
* OpenRouter's decision API: questions about a state, answered in one call. It takes no options:
|
|
7
|
+
* images and box questions need no opt-in, and a request with an image runs in long context.
|
|
8
|
+
*/
|
|
9
|
+
export const openRouterDecisions = defineProtocol({
|
|
5
10
|
id: 'openRouterDecisions',
|
|
6
11
|
name: 'OpenRouter Decisions',
|
|
7
12
|
description: "OpenRouter's decision API: questions about a state, answered in one call.", // labels-exempt: builder field description, read by the studio and docs
|
|
8
13
|
endpoints: { decision: '/alpha/decisions' },
|
|
14
|
+
options: z.strictObject({}),
|
|
15
|
+
create(context) {
|
|
16
|
+
return {
|
|
17
|
+
decide(request) {
|
|
18
|
+
const assets = request.assets ?? {};
|
|
19
|
+
const body = jsonObjectSchema.parse({
|
|
20
|
+
model: context.apiId,
|
|
21
|
+
state: withImages(request.state, assets),
|
|
22
|
+
questions: Object.fromEntries(Object.entries(request.questions).map(([id, question]) => [
|
|
23
|
+
id,
|
|
24
|
+
{
|
|
25
|
+
...question,
|
|
26
|
+
instructions: withImages(question.instructions, assets),
|
|
27
|
+
...('criteria' in question && question.criteria !== undefined
|
|
28
|
+
? { criteria: withImages(question.criteria, assets) }
|
|
29
|
+
: {}),
|
|
30
|
+
},
|
|
31
|
+
])),
|
|
32
|
+
});
|
|
33
|
+
return decisionAnswered('openRouterDecisions', context.send(body, { stream: false }));
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
},
|
|
9
37
|
});
|
|
38
|
+
/**
|
|
39
|
+
* Each reference becomes the reference followed by its image, where the reference was.
|
|
40
|
+
* why: OpenRouter ignores an `assets` map; it reads image parts in place.
|
|
41
|
+
*/
|
|
42
|
+
function withImages(value, assets) {
|
|
43
|
+
if (typeof value === 'string') {
|
|
44
|
+
const asset = assets[value];
|
|
45
|
+
return asset
|
|
46
|
+
? [
|
|
47
|
+
value,
|
|
48
|
+
{ type: 'image_url', image_url: { url: `data:${asset.mimeType};base64,${asset.data}` } },
|
|
49
|
+
]
|
|
50
|
+
: value;
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(value))
|
|
53
|
+
return value.map((item) => withImages(item, assets));
|
|
54
|
+
if (value !== null && typeof value === 'object')
|
|
55
|
+
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, withImages(item, assets)]));
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type JsonObject } from '../../kernel/json.js';
|
|
1
2
|
import { type Protocol } from '../../kernel/protocols/mod.js';
|
|
3
|
+
import type { DecisionResult } from '../../kernel/types.js';
|
|
2
4
|
/** What a System One binding may set. Both are TypeSafe's opt-in "danger zone" headers. */
|
|
3
5
|
export interface SystemOneOptions {
|
|
4
6
|
images?: boolean;
|
|
@@ -6,3 +8,5 @@ export interface SystemOneOptions {
|
|
|
6
8
|
}
|
|
7
9
|
/** TypeSafe's decision API: questions about a state, answered in one call. */
|
|
8
10
|
export declare const systemOne: Protocol<SystemOneOptions>;
|
|
11
|
+
/** The first decision reply, read into the kernel's result. Shared by every decision API that answers as System One does. */
|
|
12
|
+
export declare function decisionAnswered(protocol: string, rows: AsyncIterable<JsonObject>): Promise<DecisionResult>;
|
|
@@ -56,34 +56,35 @@ export const systemOne = defineProtocol({
|
|
|
56
56
|
? { assets: assetsOnWire(request.assets) }
|
|
57
57
|
: {}),
|
|
58
58
|
});
|
|
59
|
-
|
|
60
|
-
const parsed = reply.safeParse(row);
|
|
61
|
-
if (!parsed.success)
|
|
62
|
-
throw new TheoremError('bad_response', labelText('protocol.reply_shape', {
|
|
63
|
-
protocol: 'systemOne',
|
|
64
|
-
issues: z.prettifyError(parsed.error),
|
|
65
|
-
}));
|
|
66
|
-
const { model, answers, usage } = parsed.data;
|
|
67
|
-
// invariant: The kernel validates every answer against its question before exposing it.
|
|
68
|
-
return {
|
|
69
|
-
model,
|
|
70
|
-
answers: answers,
|
|
71
|
-
...(usage
|
|
72
|
-
? {
|
|
73
|
-
usage: {
|
|
74
|
-
inputTokens: usage.input_tokens,
|
|
75
|
-
outputTokens: usage.output_tokens,
|
|
76
|
-
...(usage.cost === undefined ? {} : { costUsd: usage.cost }),
|
|
77
|
-
},
|
|
78
|
-
}
|
|
79
|
-
: {}),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
throw new TheoremError('bad_response', labelText('provider.decision_failed'));
|
|
59
|
+
return await decisionAnswered('systemOne', context.send(body, { stream: false, headers }));
|
|
83
60
|
},
|
|
84
61
|
};
|
|
85
62
|
},
|
|
86
63
|
});
|
|
64
|
+
/** The first decision reply, read into the kernel's result. Shared by every decision API that answers as System One does. */
|
|
65
|
+
export async function decisionAnswered(protocol, rows) {
|
|
66
|
+
for await (const row of rows) {
|
|
67
|
+
const parsed = reply.safeParse(row);
|
|
68
|
+
if (!parsed.success)
|
|
69
|
+
throw new TheoremError('bad_response', labelText('protocol.reply_shape', { protocol, issues: z.prettifyError(parsed.error) }));
|
|
70
|
+
const { model, answers, usage } = parsed.data;
|
|
71
|
+
// invariant: The kernel validates every answer against its question before exposing it.
|
|
72
|
+
return {
|
|
73
|
+
model,
|
|
74
|
+
answers: answers,
|
|
75
|
+
...(usage
|
|
76
|
+
? {
|
|
77
|
+
usage: {
|
|
78
|
+
inputTokens: usage.input_tokens,
|
|
79
|
+
outputTokens: usage.output_tokens,
|
|
80
|
+
...(usage.cost === undefined ? {} : { costUsd: usage.cost }),
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
: {}),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
throw new TheoremError('bad_response', labelText('provider.decision_failed'));
|
|
87
|
+
}
|
|
87
88
|
const FORMATS = { 'image/png': 'png', 'image/jpeg': 'jpeg' };
|
|
88
89
|
function assetsOnWire(assets) {
|
|
89
90
|
return Object.fromEntries(Object.entries(assets).map(([reference, { mimeType, data }]) => [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@theoremjs/agents",
|
|
3
|
-
"version": "0.3.4-next.
|
|
3
|
+
"version": "0.3.4-next.484.g20d8b9d",
|
|
4
4
|
"description": "A flat TypeScript agent kernel for typed profiles, deterministic turn execution, registered tools, provider adapters, guardrails, and host-injected traces.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|