@corbits/system-one 0.1.0 → 0.3.0
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 +162 -220
- package/dist/adapter.d.ts +6 -7
- package/dist/adapter.js +68 -9
- package/dist/client.d.ts +11 -6
- package/dist/client.js +32 -18
- package/dist/config.d.ts +11 -4
- package/dist/config.js +11 -12
- package/dist/errors.d.ts +12 -25
- package/dist/errors.js +20 -34
- package/dist/evaluate.d.ts +22 -7
- package/dist/evaluate.js +36 -27
- package/dist/index.d.ts +7 -7
- package/dist/index.js +5 -6
- package/dist/schemas.d.ts +0 -23
- package/dist/schemas.js +0 -3
- package/dist/telemetry.d.ts +0 -14
- package/dist/telemetry.js +4 -35
- package/package.json +40 -34
package/README.md
CHANGED
|
@@ -1,279 +1,221 @@
|
|
|
1
1
|
# @corbits/system-one
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](#development)
|
|
5
|
-
|
|
6
|
-
**Typed decisions from System One (Jev-class) models — as an Interchange
|
|
7
|
-
inference provider, or as a direct `evaluate()` call.**
|
|
8
|
-
|
|
9
|
-
Ask choice, score, and boolean questions over a state payload. You get
|
|
10
|
-
back per-kind decisions, or a typed fallback when the backend is
|
|
11
|
-
unreachable. Official, gateway, and custom endpoints are config, not
|
|
12
|
-
forked code.
|
|
13
|
-
|
|
14
|
-
## Contents
|
|
15
|
-
|
|
16
|
-
- [Why](#why)
|
|
17
|
-
- [Quickstart](#quickstart)
|
|
18
|
-
- [How it works](#how-it-works)
|
|
19
|
-
- [Development](#development)
|
|
20
|
-
- [License](#license)
|
|
21
|
-
|
|
22
|
-
## Why
|
|
23
|
-
|
|
24
|
-
Interchange agents and workflows already speak providers. This package
|
|
25
|
-
is the System One adapter for that surface:
|
|
26
|
-
|
|
27
|
-
- **One provider id.** `SYSTEM_ONE_PROVIDER` is `"corbits-system-one"`
|
|
28
|
-
— same naming as the other Corbits libraries, not a generic
|
|
29
|
-
`"system-one"`. Use it in `defineAgent` / workflow inference sources
|
|
30
|
-
the way you would `"anthropic"`.
|
|
31
|
-
- **Questions on the call.** Pass Jev questions (and optional state)
|
|
32
|
-
through `providerOptions.systemOne`. The transcript is the default
|
|
33
|
-
state when you omit it.
|
|
34
|
-
- **Two output shapes.** Direct `evaluate()` returns an
|
|
35
|
-
`EvaluateResult` or `FallbackResult`. The adapter unwraps the same
|
|
36
|
-
decisions into Interchange `inference.text.delta` / `inference.usage`
|
|
37
|
-
events so an agent step can consume them.
|
|
38
|
-
- **Host-owned credentials.** The adapter sends Interchange's bearer
|
|
39
|
-
sentinel; the harness injects the real key. Peers are
|
|
40
|
-
`@intx/inference` and `@intx/types` — one copy, the host's.
|
|
3
|
+
Typed choice, score and yes/no decisions about a JSON state from TypeSafe's Jev model, returned as a validated result or a typed fallback. An inference provider for Corbits and Interchange agents: registers as an `@intx/inference` adapter, and also works standalone through `evaluate()`.
|
|
41
4
|
|
|
42
|
-
##
|
|
5
|
+
## Why @corbits/system-one?
|
|
43
6
|
|
|
44
|
-
|
|
45
|
-
|
|
7
|
+
1. **Typed decisions, not free text.** You send questions with ids; you get back one validated decision per id, with probabilities and confidence. No prompt parsing.
|
|
8
|
+
2. **Failures are data.** A missing key, timeout, HTTP error or bad body returns a `FallbackResult` with a `reason`, so a gate can fail closed without a `try`. Only invalid caller input throws.
|
|
9
|
+
3. **One call, many questions.** Every question in a list goes out in one POST, bounded by a 1.5 s default timeout.
|
|
46
10
|
|
|
47
|
-
|
|
48
|
-
bun add @corbits/system-one
|
|
49
|
-
```
|
|
11
|
+
It evaluates structured state against questions. For open-ended chat completions, use a general inference provider such as [`@corbits/openai-responses`](https://github.com/corbitsdev/corbits-openai-responses).
|
|
50
12
|
|
|
51
|
-
|
|
13
|
+
## Install
|
|
52
14
|
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
{
|
|
56
|
-
id: "route",
|
|
57
|
-
type: "choice",
|
|
58
|
-
instructions: "What permission decision does this request warrant?",
|
|
59
|
-
criteria: { allow: "Low-risk request", deny: "Refuse the request" },
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
id: "escalate",
|
|
63
|
-
type: "boolean",
|
|
64
|
-
instructions: "Must this request be escalated for human approval?",
|
|
65
|
-
},
|
|
66
|
-
];
|
|
15
|
+
```bash
|
|
16
|
+
bun add @corbits/system-one @intx/inference@^0.4.0 @intx/types@^0.4.0
|
|
67
17
|
```
|
|
68
18
|
|
|
69
|
-
|
|
19
|
+
Runs on Bun >= 1.2 or Node >= 24.
|
|
20
|
+
|
|
21
|
+
## Quickstart
|
|
70
22
|
|
|
71
|
-
|
|
72
|
-
(`fallback: false`) or a typed fallback (`fallback: true`). Boolean
|
|
73
|
-
questions answer as native `noul` (0..1).
|
|
23
|
+
Needs `TYPESAFE_API_KEY` set.
|
|
74
24
|
|
|
75
25
|
```ts
|
|
76
26
|
import { evaluate } from "@corbits/system-one";
|
|
77
27
|
|
|
78
28
|
const result = await evaluate({
|
|
79
29
|
state: { action: "deploy", env: "production" },
|
|
80
|
-
questions
|
|
81
|
-
config: { apiKey: process.env.TYPESAFE_API_KEY },
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Success looks like:
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
{
|
|
89
|
-
fallback: false,
|
|
90
|
-
backend: "corbits-system-one", // official endpoint; "gateway" | "custom" otherwise
|
|
91
|
-
modelId: "jev-1.13.0",
|
|
92
|
-
latencyMs: 412,
|
|
93
|
-
usage: { inputTokens: 296, outputTokens: 20 },
|
|
94
|
-
decisions: [
|
|
95
|
-
{
|
|
96
|
-
id: "route",
|
|
97
|
-
type: "choice",
|
|
98
|
-
choice: "deny",
|
|
99
|
-
confidence: 0.86,
|
|
100
|
-
probabilities: { allow: 0.14, deny: 0.86 },
|
|
101
|
-
},
|
|
30
|
+
questions: [
|
|
102
31
|
{
|
|
103
32
|
id: "escalate",
|
|
104
|
-
type: "
|
|
105
|
-
|
|
33
|
+
type: "boolean",
|
|
34
|
+
instructions: "Must this request be escalated for human approval?",
|
|
106
35
|
},
|
|
107
36
|
],
|
|
108
|
-
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
console.log(result.fallback ? result.reason : result.decisions);
|
|
109
40
|
```
|
|
110
41
|
|
|
111
|
-
|
|
42
|
+
On success it prints one decision per question, or the fallback reason on failure:
|
|
112
43
|
|
|
113
44
|
```ts
|
|
114
|
-
{
|
|
115
|
-
fallback: true,
|
|
116
|
-
reason: "no-key", // or "timeout" | "network" | "http-error" | "parse-error" | "backend-unreachable"
|
|
117
|
-
latencyMs: 2,
|
|
118
|
-
backendAttempted: "https://api.typesafe.ai/...",
|
|
119
|
-
detail: "no API key in config.apiKey, TYPESAFE_API_KEY, or SYSTEM_ONE_API_KEY",
|
|
120
|
-
}
|
|
45
|
+
[{ id: "escalate", type: "noul", noul: 0.91 }];
|
|
121
46
|
```
|
|
122
47
|
|
|
123
|
-
|
|
124
|
-
still **throws** a `SystemOneError` — that is not a fallback.
|
|
48
|
+
Boolean questions answer as `noul`, a probability from 0 to 1 that the answer is yes.
|
|
125
49
|
|
|
126
|
-
|
|
127
|
-
`AI_GATEWAY_API_KEY` / `VERCEL_OIDC_TOKEN` (gateway), else
|
|
128
|
-
`SYSTEM_ONE_API_KEY`. Endpoint: omit for official (`jev-latest`);
|
|
129
|
-
`{ kind: "gateway" }`; `{ kind: "custom", url }`.
|
|
50
|
+
## Where it fits
|
|
130
51
|
|
|
131
|
-
|
|
52
|
+
[Interchange](https://github.com/faremeter/interchange) runs AI agents as principals (accounts that hold their own identity, permissions and credentials). Corbits packages add what an agent product needs around it.
|
|
132
53
|
|
|
133
|
-
`
|
|
134
|
-
`
|
|
135
|
-
|
|
54
|
+
- **Runs in:** the agent sidecar (the runtime next to each agent), or any process. `evaluate()` needs no Interchange runtime.
|
|
55
|
+
- **Plugs into:** the [`@intx/inference`](https://github.com/faremeter/interchange/tree/main/packages/inference) adapter registry, as the adapter for the `corbits-system-one` provider id.
|
|
56
|
+
- **Pairs with:** [`@corbits/openai-responses`](https://github.com/corbitsdev/corbits-openai-responses) and [`@corbits/ollama-adapter`](https://github.com/corbitsdev/corbits-ollama-adapter), the other Corbits inference providers.
|
|
136
57
|
|
|
137
|
-
|
|
138
|
-
import { createAgent, defineAgent } from "@intx/agent";
|
|
139
|
-
import {
|
|
140
|
-
createSystemOneAdapter,
|
|
141
|
-
SYSTEM_ONE_PROVIDER, // "corbits-system-one"
|
|
142
|
-
} from "@corbits/system-one";
|
|
58
|
+
## Reference
|
|
143
59
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
60
|
+
| Export | Description |
|
|
61
|
+
| --------------------------------- | ----------------------------------------------------------------------------------- |
|
|
62
|
+
| `evaluate(input, options?)` | Runs one evaluation. Returns `EvaluateResult`: decisions or a `FallbackResult`. |
|
|
63
|
+
| `createSystemOneAdapter(config?)` | Returns a `ProviderAdapter` for `runInference`. `config` is an `EvaluateConfig`. |
|
|
64
|
+
| `createSystemOneAdapterFactory` | Interchange `AdapterFactory` for `SIDECAR_ADAPTER_MANIFEST`; takes offering quirks. |
|
|
65
|
+
| `SYSTEM_ONE_PROVIDER` | The `"corbits-system-one"` provider id. |
|
|
66
|
+
| `DEFAULT_TIMEOUT_MS` | `1500`, the default `timeoutMs`. |
|
|
67
|
+
| `SystemOneError` | Thrown for invalid input or a `custom` endpoint without a `url`. |
|
|
68
|
+
| `SystemOneTelemetryEvent` | Schema and type for events passed to `onTelemetry`. |
|
|
69
|
+
| `EvaluateOptions`, `EvaluateDeps` | Types for `options`: `onTelemetry`, and `deps: { fetch, scheduler }`. |
|
|
153
70
|
|
|
154
|
-
|
|
155
|
-
source: {
|
|
156
|
-
id: SYSTEM_ONE_PROVIDER,
|
|
157
|
-
provider: SYSTEM_ONE_PROVIDER,
|
|
158
|
-
model: "jev-latest",
|
|
159
|
-
apiKey: process.env.TYPESAFE_API_KEY,
|
|
160
|
-
adapter: createSystemOneAdapter(),
|
|
161
|
-
},
|
|
162
|
-
});
|
|
71
|
+
`Question`, `QuestionList`, `Decision`, `EvaluateInput`, `EvaluateConfig`, `EndpointConfig`, `EvaluateResult` and `FallbackResult` are exported as arktype schemas and types.
|
|
163
72
|
|
|
164
|
-
|
|
165
|
-
providerOptions: { systemOne: { questions } },
|
|
166
|
-
});
|
|
167
|
-
```
|
|
73
|
+
### Questions
|
|
168
74
|
|
|
169
|
-
|
|
75
|
+
| `type` | Fields | Decision fields |
|
|
76
|
+
| --------- | ------------------------------------------------------------------------------- | ------------------------------------------------ |
|
|
77
|
+
| `choice` | `instructions`, `criteria` (option name → description or `null`, 1–255 options) | `choice`, `probabilities`, `confidence` |
|
|
78
|
+
| `score` | `instructions`, `criteria` (2–10 descriptions) | `score`, `legend`, `probabilities`, `confidence` |
|
|
79
|
+
| `boolean` | `instructions`, optional `criteria: { true?, false? }` | `noul` |
|
|
80
|
+
| `noul` | Same as `boolean` | `noul` |
|
|
170
81
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
type: "inference.text.delta",
|
|
183
|
-
data: {
|
|
184
|
-
index: 1,
|
|
185
|
-
token: '{"id":"escalate","type":"noul","noul":0.91}',
|
|
186
|
-
},
|
|
187
|
-
},
|
|
188
|
-
{
|
|
189
|
-
type: "inference.usage",
|
|
190
|
-
data: {
|
|
191
|
-
usage: {
|
|
192
|
-
input: 296,
|
|
193
|
-
output: 20,
|
|
194
|
-
cacheRead: 0,
|
|
195
|
-
cacheWrite: 0,
|
|
196
|
-
thinking: 0,
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
|
-
];
|
|
201
|
-
```
|
|
82
|
+
Every question has an `id`, unique within the list.
|
|
83
|
+
|
|
84
|
+
### Config
|
|
85
|
+
|
|
86
|
+
`input.config` for `evaluate`, or the argument to `createSystemOneAdapter`:
|
|
87
|
+
|
|
88
|
+
| Field | Type | Default | Description |
|
|
89
|
+
| ----------- | ---------------- | ---------------------- | -------------------------------------------------------------------------------- |
|
|
90
|
+
| `endpoint` | `EndpointConfig` | `{ kind: "official" }` | `official`, `gateway`, or `custom` with a `url`. Each takes an optional `model`. |
|
|
91
|
+
| `timeoutMs` | `number` | `1500` | Bound for the whole round trip. |
|
|
92
|
+
| `apiKey` | `string` | from the environment | Overrides the environment key. |
|
|
202
93
|
|
|
203
|
-
|
|
204
|
-
`result.decisions`. There is no `fallback` flag on this path: a bad
|
|
205
|
-
wire body is a `ProtocolMismatchError`; auth/retry stay with the
|
|
206
|
-
harness (`retry-after` is surfaced for 429/529).
|
|
94
|
+
### Endpoints and keys
|
|
207
95
|
|
|
208
|
-
|
|
96
|
+
| `kind` | URL | Default model | Key from the environment |
|
|
97
|
+
| ---------- | ---------------------------------------------------- | ----------------- | ---------------------------------------------- |
|
|
98
|
+
| `official` | `https://api.typesafe.ai/v1/systemone` | `jev-latest` | `TYPESAFE_API_KEY` |
|
|
99
|
+
| `gateway` | `https://ai-gateway.vercel.sh/typesafe/v1/systemone` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY`, then `VERCEL_OIDC_TOKEN` |
|
|
100
|
+
| `custom` | `url` | `typesafe-ai/jev` | `SYSTEM_ONE_API_KEY` |
|
|
209
101
|
|
|
210
|
-
|
|
102
|
+
`SYSTEM_ONE_API_KEY` is also a supported alias on every endpoint, read after the endpoint's own key.
|
|
103
|
+
|
|
104
|
+
### Fallback reasons
|
|
105
|
+
|
|
106
|
+
| `reason` | When |
|
|
107
|
+
| ------------- | ------------------------------------------------------------- |
|
|
108
|
+
| `no-key` | No key in `apiKey` or the environment. No request is sent. |
|
|
109
|
+
| `timeout` | The round trip, including the body read, exceeds `timeoutMs`. |
|
|
110
|
+
| `network` | The request fails before a response. |
|
|
111
|
+
| `http-error` | Non-2xx response. `httpStatus` holds the status. |
|
|
112
|
+
| `parse-error` | The body is not JSON or fails validation. |
|
|
113
|
+
|
|
114
|
+
`detail` carries the underlying message.
|
|
115
|
+
|
|
116
|
+
## Using with Interchange
|
|
117
|
+
|
|
118
|
+
Register the adapter under `SYSTEM_ONE_PROVIDER` and pass questions per call in `providerOptions.systemOne` (`{ state?, questions? }`). Without `state`, the adapter sends the transcript text as state. Without `questions`, it asks one boolean question with id `response`.
|
|
211
119
|
|
|
212
120
|
```ts
|
|
213
|
-
import {
|
|
121
|
+
import { createDependencies, runInference } from "@intx/inference";
|
|
214
122
|
import {
|
|
215
123
|
createSystemOneAdapter,
|
|
216
124
|
SYSTEM_ONE_PROVIDER,
|
|
125
|
+
type QuestionList,
|
|
217
126
|
} from "@corbits/system-one";
|
|
218
127
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
128
|
+
const deps = createDependencies({
|
|
129
|
+
has: (provider) => provider === SYSTEM_ONE_PROVIDER,
|
|
130
|
+
resolve: () => createSystemOneAdapter(),
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const questions = [
|
|
134
|
+
{
|
|
135
|
+
id: "escalate",
|
|
136
|
+
type: "boolean",
|
|
137
|
+
instructions: "Must this request be escalated for human approval?",
|
|
138
|
+
},
|
|
139
|
+
] satisfies QuestionList;
|
|
140
|
+
|
|
141
|
+
let seq = 0;
|
|
142
|
+
for await (const event of runInference({
|
|
143
|
+
deps,
|
|
144
|
+
source: {
|
|
145
|
+
id: "system-one",
|
|
146
|
+
provider: SYSTEM_ONE_PROVIDER,
|
|
147
|
+
baseURL: "https://api.typesafe.ai/v1/systemone",
|
|
148
|
+
credentialId: "TYPESAFE_API_KEY",
|
|
149
|
+
model: "jev-latest",
|
|
150
|
+
},
|
|
151
|
+
turns: [
|
|
222
152
|
{
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
provider: SYSTEM_ONE_PROVIDER,
|
|
227
|
-
model: "jev-latest",
|
|
228
|
-
adapter: createSystemOneAdapter(),
|
|
229
|
-
},
|
|
230
|
-
providerOptions: {
|
|
231
|
-
systemOne: {
|
|
232
|
-
state: { amount: 48, priorRefunds: 1 },
|
|
233
|
-
questions: [
|
|
234
|
-
{
|
|
235
|
-
id: "approve",
|
|
236
|
-
type: "boolean",
|
|
237
|
-
instructions: "Approve this refund without review?",
|
|
238
|
-
},
|
|
239
|
-
],
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
},
|
|
153
|
+
role: "user",
|
|
154
|
+
timestamp: Date.now(),
|
|
155
|
+
content: [{ type: "text", text: "Deploy to production?" }],
|
|
243
156
|
},
|
|
244
157
|
],
|
|
245
|
-
}
|
|
158
|
+
inferenceOptions: { providerOptions: { systemOne: { questions } } },
|
|
159
|
+
nextSeq: () => seq++,
|
|
160
|
+
readMaterial: (id) => {
|
|
161
|
+
const secret = process.env[id];
|
|
162
|
+
if (secret === undefined) throw new Error(`${id} is not set`);
|
|
163
|
+
return { secret };
|
|
164
|
+
},
|
|
165
|
+
})) {
|
|
166
|
+
if (event.type === "inference.text.delta")
|
|
167
|
+
console.log(JSON.parse(event.data.token));
|
|
168
|
+
}
|
|
246
169
|
```
|
|
247
170
|
|
|
248
|
-
The
|
|
249
|
-
whose token is `{"id":"approve","type":"noul","noul":0.2}`, then
|
|
250
|
-
usage.
|
|
251
|
-
|
|
252
|
-
## How it works
|
|
171
|
+
The adapter emits one `inference.text.delta` per decision, whose `token` is the decision as JSON, then an `inference.usage` event. The harness supplies the credential through `readMaterial` and owns retries. A malformed response body is a `ProtocolMismatchError`, not a fallback.
|
|
253
172
|
|
|
254
|
-
|
|
255
|
-
`state` is string | object | array; questions go out as an id-keyed
|
|
256
|
-
map; answers come back the same way.
|
|
257
|
-
- **Adapter.** Transcript → evaluation state; each decision →
|
|
258
|
-
`inference.text.delta`; token counts → `inference.usage`.
|
|
259
|
-
- **Schemas.** Every trust boundary is arktype (`src/schemas.ts`).
|
|
260
|
-
Confidence is narrowed, not clamped. Public surface is
|
|
261
|
-
`src/index.ts` only.
|
|
262
|
-
- **Telemetry.** Direct `evaluate()` records `evaluate.start` /
|
|
263
|
-
`.success` / `.fallback` in-memory (`drainTelemetryEvents`). No keys
|
|
264
|
-
in events.
|
|
173
|
+
### Manifest factory
|
|
265
174
|
|
|
266
|
-
|
|
175
|
+
`createSystemOneAdapterFactory(source, quirks?)` is an Interchange `AdapterFactory`, so a stock sidecar loads it from `SIDECAR_ADAPTER_MANIFEST` with no custom code:
|
|
267
176
|
|
|
177
|
+
```json
|
|
178
|
+
[
|
|
179
|
+
{
|
|
180
|
+
"provider": "corbits-system-one",
|
|
181
|
+
"specifier": "@corbits/system-one",
|
|
182
|
+
"export": "createSystemOneAdapterFactory"
|
|
183
|
+
}
|
|
184
|
+
]
|
|
268
185
|
```
|
|
269
|
-
|
|
270
|
-
|
|
186
|
+
|
|
187
|
+
The hub offering's `quirks` are validated and all optional:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"endpoint": {
|
|
192
|
+
"kind": "custom",
|
|
193
|
+
"url": "https://opencode.ai/zen/v1/systemone"
|
|
194
|
+
},
|
|
195
|
+
"model": "jev-1.13",
|
|
196
|
+
"questions": [{ "type": "boolean", "id": "gate", "instructions": "Allow?" }],
|
|
197
|
+
"state": {}
|
|
198
|
+
}
|
|
271
199
|
```
|
|
272
200
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
201
|
+
`questions` and `state` are per-call defaults; `providerOptions.systemOne` on a call wins field by field. A top-level `model` applies when `endpoint` sets none. Unknown keys throw. The adapter sends the bearer sentinel and the harness injects the offering's credential.
|
|
202
|
+
|
|
203
|
+
| Gateway | `endpoint` | `model` |
|
|
204
|
+
| ------------------ | ---------------------------------------------------------------- | ----------------------------- |
|
|
205
|
+
| Official (default) | omit, or `{"kind":"official"}` | `jev-latest` |
|
|
206
|
+
| Vercel AI Gateway | `{"kind":"gateway"}` | `typesafe-ai/jev` |
|
|
207
|
+
| OpenCode Zen | `{"kind":"custom","url":"https://opencode.ai/zen/v1/systemone"}` | `jev-1.13` or `jev-1.13-free` |
|
|
208
|
+
|
|
209
|
+
## Upgrading from 0.1
|
|
210
|
+
|
|
211
|
+
- `HttpError`, `NetworkError` and `TimeoutError` are removed. Transport failures return a `FallbackResult`.
|
|
212
|
+
- A 2xx body that is not JSON is `parse-error` (was `network`). A timeout during the body read is `timeout`.
|
|
213
|
+
- `recordTelemetryEvent` and `drainTelemetryEvents` are removed. Pass `evaluate(input, { onTelemetry })`.
|
|
214
|
+
- Wire helpers, quirks presets, `JsonRecord`, `Confidence` and the env-var name constants are no longer exported.
|
|
215
|
+
- A `custom` endpoint without a `model` sends `typesafe-ai/jev`.
|
|
216
|
+
- Peers are `@intx/inference` and `@intx/types` `^0.4.0`.
|
|
217
|
+
- Environment variables are unchanged, including `SYSTEM_ONE_API_KEY`.
|
|
276
218
|
|
|
277
219
|
## License
|
|
278
220
|
|
|
279
|
-
LGPL-2.1-only.
|
|
221
|
+
[LGPL-2.1-only](https://github.com/corbitsdev/corbits-system-one/blob/main/LICENSE)
|
package/dist/adapter.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { type ProviderAdapter } from "@intx/inference";
|
|
1
|
+
import { type AdapterFactory, type ProviderAdapter } from "@intx/inference";
|
|
2
2
|
import { type EvaluateConfig } from "./schemas.js";
|
|
3
3
|
/** Provider id this package serves. */
|
|
4
4
|
export declare const SYSTEM_ONE_PROVIDER = "corbits-system-one";
|
|
5
|
+
export declare function createSystemOneAdapter(config?: EvaluateConfig): ProviderAdapter;
|
|
5
6
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* a custom URL) and the per-call model default; the inference call's own
|
|
10
|
-
* `model` argument wins for the request body.
|
|
7
|
+
* Interchange `AdapterFactory` for `SIDECAR_ADAPTER_MANIFEST`: validates the
|
|
8
|
+
* offering's `quirks` and reuses `createSystemOneAdapter`. A top-level
|
|
9
|
+
* `model` fills the endpoint's model when the endpoint sets none.
|
|
11
10
|
*/
|
|
12
|
-
export declare
|
|
11
|
+
export declare const createSystemOneAdapterFactory: AdapterFactory;
|
package/dist/adapter.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type } from "arktype";
|
|
2
2
|
import { BEARER_CREDENTIAL_SENTINEL, ProtocolMismatchError, } from "@intx/inference";
|
|
3
3
|
import { resolveEndpoint } from "./config.js";
|
|
4
|
-
import { Decision, toDecision, toWireQuestions, WireResponseBody, QuestionList, State, } from "./schemas.js";
|
|
4
|
+
import { Decision, toDecision, toWireQuestions, WireResponseBody, EndpointConfig, QuestionList, State, } from "./schemas.js";
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
6
6
|
// Adapter
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
@@ -100,7 +100,7 @@ function parseDecisions(body, provider) {
|
|
|
100
100
|
throw new ProtocolMismatchError(`${provider} parseJSONResponse: ${cause instanceof Error ? cause.message : String(cause)}`, parsed);
|
|
101
101
|
}
|
|
102
102
|
});
|
|
103
|
-
return { decisions, usage: envelope.usage };
|
|
103
|
+
return { decisions, model: envelope.model, usage: envelope.usage };
|
|
104
104
|
}
|
|
105
105
|
/**
|
|
106
106
|
* Builds the Interchange `ProviderAdapter` for System One against the
|
|
@@ -109,12 +109,12 @@ function parseDecisions(body, provider) {
|
|
|
109
109
|
* a custom URL) and the per-call model default; the inference call's own
|
|
110
110
|
* `model` argument wins for the request body.
|
|
111
111
|
*/
|
|
112
|
-
|
|
112
|
+
function createSystemOneProviderAdapter(config, source) {
|
|
113
113
|
const endpoint = resolveEndpoint(config?.endpoint);
|
|
114
|
-
const
|
|
114
|
+
const usageSource = source ?? {
|
|
115
115
|
sourceId: SYSTEM_ONE_PROVIDER,
|
|
116
116
|
provider: SYSTEM_ONE_PROVIDER,
|
|
117
|
-
model: endpoint.model
|
|
117
|
+
model: endpoint.model,
|
|
118
118
|
};
|
|
119
119
|
const buildRequest = (messages, model, options) => {
|
|
120
120
|
let state = { transcript: transcriptText(messages) };
|
|
@@ -130,8 +130,7 @@ export function createSystemOneAdapter(config) {
|
|
|
130
130
|
if (overrides.questions !== undefined)
|
|
131
131
|
questions = overrides.questions;
|
|
132
132
|
}
|
|
133
|
-
const requestModel = model || endpoint.model
|
|
134
|
-
source.model = requestModel;
|
|
133
|
+
const requestModel = model || endpoint.model;
|
|
135
134
|
const headers = {
|
|
136
135
|
"content-type": "application/json",
|
|
137
136
|
accept: "application/json",
|
|
@@ -148,7 +147,7 @@ export function createSystemOneAdapter(config) {
|
|
|
148
147
|
};
|
|
149
148
|
};
|
|
150
149
|
const parseJSONResponse = (responseBody) => {
|
|
151
|
-
const { decisions, usage } = parseDecisions(responseBody, SYSTEM_ONE_PROVIDER);
|
|
150
|
+
const { decisions, model, usage } = parseDecisions(responseBody, SYSTEM_ONE_PROVIDER);
|
|
152
151
|
const events = [];
|
|
153
152
|
let index = 0;
|
|
154
153
|
for (const decision of decisions) {
|
|
@@ -163,7 +162,13 @@ export function createSystemOneAdapter(config) {
|
|
|
163
162
|
events.push({
|
|
164
163
|
type: "inference.usage",
|
|
165
164
|
seq: 0,
|
|
166
|
-
data: {
|
|
165
|
+
data: {
|
|
166
|
+
usage: toTokenUsage(usage),
|
|
167
|
+
source: {
|
|
168
|
+
...usageSource,
|
|
169
|
+
model: model ?? usageSource.model,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
167
172
|
});
|
|
168
173
|
return events;
|
|
169
174
|
};
|
|
@@ -191,3 +196,57 @@ export function createSystemOneAdapter(config) {
|
|
|
191
196
|
extractRetryAfterMs,
|
|
192
197
|
};
|
|
193
198
|
}
|
|
199
|
+
export function createSystemOneAdapter(config) {
|
|
200
|
+
return createSystemOneProviderAdapter(config);
|
|
201
|
+
}
|
|
202
|
+
// Deployment quirks a hub offering carries for this provider. `questions`
|
|
203
|
+
// and `state` are per-call defaults: a call's own `providerOptions.systemOne`
|
|
204
|
+
// wins field by field.
|
|
205
|
+
const SystemOneFactoryQuirks = type({
|
|
206
|
+
"endpoint?": EndpointConfig,
|
|
207
|
+
"model?": "string",
|
|
208
|
+
"questions?": QuestionList,
|
|
209
|
+
"state?": State,
|
|
210
|
+
"+": "reject",
|
|
211
|
+
});
|
|
212
|
+
/**
|
|
213
|
+
* Interchange `AdapterFactory` for `SIDECAR_ADAPTER_MANIFEST`: validates the
|
|
214
|
+
* offering's `quirks` and reuses `createSystemOneAdapter`. A top-level
|
|
215
|
+
* `model` fills the endpoint's model when the endpoint sets none.
|
|
216
|
+
*/
|
|
217
|
+
export const createSystemOneAdapterFactory = (source, quirks) => {
|
|
218
|
+
const parsed = SystemOneFactoryQuirks(quirks ?? {});
|
|
219
|
+
if (parsed instanceof type.errors) {
|
|
220
|
+
throw new Error(`${SYSTEM_ONE_PROVIDER} adapter: invalid quirks: ${parsed.summary}`);
|
|
221
|
+
}
|
|
222
|
+
const endpoint = {
|
|
223
|
+
kind: "official",
|
|
224
|
+
...parsed.endpoint,
|
|
225
|
+
};
|
|
226
|
+
if (parsed.model !== undefined && endpoint.model === undefined) {
|
|
227
|
+
endpoint.model = parsed.model;
|
|
228
|
+
}
|
|
229
|
+
const adapter = createSystemOneProviderAdapter({ endpoint }, source);
|
|
230
|
+
const defaults = {
|
|
231
|
+
...(parsed.state !== undefined && { state: parsed.state }),
|
|
232
|
+
...(parsed.questions !== undefined && { questions: parsed.questions }),
|
|
233
|
+
};
|
|
234
|
+
if (Object.keys(defaults).length === 0)
|
|
235
|
+
return adapter;
|
|
236
|
+
return {
|
|
237
|
+
...adapter,
|
|
238
|
+
buildRequest: (messages, model, options) => {
|
|
239
|
+
const raw = options.providerOptions?.["systemOne"];
|
|
240
|
+
const call = raw === undefined ? {} : raw;
|
|
241
|
+
return adapter.buildRequest(messages, model, {
|
|
242
|
+
...options,
|
|
243
|
+
providerOptions: {
|
|
244
|
+
...options.providerOptions,
|
|
245
|
+
systemOne: typeof call === "object" && call !== null
|
|
246
|
+
? { ...defaults, ...call }
|
|
247
|
+
: call,
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
};
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { type Dependencies } from "@intx/inference";
|
|
1
2
|
/** Options for one evaluation POST: timeout and auth, resolved by `evaluate`. */
|
|
2
3
|
export type PostEvaluateOptions = {
|
|
3
4
|
timeoutMs?: number;
|
|
4
5
|
apiKey?: string;
|
|
5
6
|
};
|
|
7
|
+
/** Transport dependencies: the `fetch` to POST with and the timeout scheduler. */
|
|
8
|
+
export type EvaluateDeps = Pick<Dependencies, "fetch" | "scheduler">;
|
|
6
9
|
/** The decoded JSON body of a 2xx evaluation response, with its latency. */
|
|
7
10
|
export type PostEvaluateResponse = {
|
|
8
11
|
data: unknown;
|
|
@@ -12,10 +15,12 @@ export type PostEvaluateResponse = {
|
|
|
12
15
|
/**
|
|
13
16
|
* POSTs an evaluation payload and returns the decoded JSON body. Sends
|
|
14
17
|
* `Authorization: Bearer <apiKey>` only when a key is present; aborts the
|
|
15
|
-
* exchange when `timeoutMs` elapses. A `timeoutMs`
|
|
16
|
-
* number >= 0 falls back to `DEFAULT_TIMEOUT_MS`.
|
|
17
|
-
*
|
|
18
|
-
* `
|
|
19
|
-
*
|
|
18
|
+
* exchange when `timeoutMs` elapses on `deps.scheduler`. A `timeoutMs`
|
|
19
|
+
* that is not a finite number >= 0 falls back to `DEFAULT_TIMEOUT_MS`.
|
|
20
|
+
* Throws a `TransportError` carrying a `timeout` classification on
|
|
21
|
+
* timeout, a `classifyHTTPError` classification (status only, never the
|
|
22
|
+
* body) on non-2xx, a `classifyNetworkError` classification when no HTTP
|
|
23
|
+
* exchange completes, and a `classifyProtocolMismatch` classification when
|
|
24
|
+
* the 2xx body is not valid JSON.
|
|
20
25
|
*/
|
|
21
|
-
export declare function postEvaluate(url: string, body: unknown, options: PostEvaluateOptions): Promise<PostEvaluateResponse>;
|
|
26
|
+
export declare function postEvaluate(url: string, body: unknown, options: PostEvaluateOptions, deps: EvaluateDeps): Promise<PostEvaluateResponse>;
|