bkper 5.8.0 → 5.8.2

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.
Files changed (37) hide show
  1. package/lib/agent/bundle/agent-entry.js +3 -3
  2. package/lib/agent/extensions/bkper-ai-provider.d.ts.map +1 -1
  3. package/lib/agent/extensions/bkper-ai-provider.js +14 -4
  4. package/lib/agent/extensions/bkper-ai-provider.js.map +1 -1
  5. package/lib/agent/interactive/interactive-mode.d.ts +2 -1
  6. package/lib/agent/interactive/interactive-mode.d.ts.map +1 -1
  7. package/lib/agent/interactive/interactive-mode.js +5 -0
  8. package/lib/agent/interactive/interactive-mode.js.map +1 -1
  9. package/lib/agent/interactive/terminal.d.ts +8 -0
  10. package/lib/agent/interactive/terminal.d.ts.map +1 -0
  11. package/lib/agent/interactive/terminal.js +11 -0
  12. package/lib/agent/interactive/terminal.js.map +1 -0
  13. package/lib/agent/pi-shared-modules.d.ts +1 -1
  14. package/lib/agent/pi-shared-modules.d.ts.map +1 -1
  15. package/lib/agent/pi-shared-modules.js +1 -1
  16. package/lib/agent/pi-shared-modules.js.map +1 -1
  17. package/lib/agent/system-prompt.js +1 -1
  18. package/lib/agent/system-prompt.js.map +1 -1
  19. package/lib/commands/context/book-context.d.ts +1 -1
  20. package/lib/commands/context/book-context.js +1 -1
  21. package/lib/commands/context/domain-context.d.ts +1 -1
  22. package/lib/commands/context/domain-context.js +1 -1
  23. package/lib/commands/context/user-context.d.ts +1 -1
  24. package/lib/commands/context/user-context.js +1 -1
  25. package/lib/docs/ai/system-one-models.md +329 -0
  26. package/lib/docs/api/ai-gateway.md +122 -46
  27. package/lib/docs/api/managed-agent.md +95 -1
  28. package/lib/docs/apps/ai.md +71 -15
  29. package/lib/docs/apps/configuration.md +2 -1
  30. package/lib/docs/apps/context-menu.md +141 -1
  31. package/lib/docs/apps/development.md +27 -0
  32. package/lib/docs/apps/overview.md +1 -1
  33. package/lib/docs/apps/quality.md +1 -1
  34. package/lib/docs/core/core-concepts.md +1 -1
  35. package/lib/docs/index.md +4 -4
  36. package/package.json +1 -1
  37. package/lib/docs/ai/decision-models.md +0 -158
@@ -6,7 +6,8 @@ Model output is a suggestion, not permission to change a Book. Keep decisions ab
6
6
 
7
7
  ## Choose the kind of response
8
8
 
9
- - **A yes/no, a choice, or a level on a scale?** Ask a decision model, such as `jev`, with TypeSafe's SDK, `@typesafe-ai/sdk`.
9
+ - **A judgment: a yes/no, one of known options, or a level on a scale?** [Ask a System One model](#ask-a-system-one-model) a decision question, with a model such as `jev`.
10
+ - **A value read from a document, such as an invoice total, or a likely range for an uncertain number, such as days until an invoice is paid?** [Ask a System One model](#ask-a-system-one-model) an extraction question, with a model such as `clairic`.
10
11
  - **Text or a custom JSON object?** Ask a language model (LLM), such as `gpt-luna`, with AI SDK's Open Responses provider, `@ai-sdk/open-responses`.
11
12
  - **A conversation that works on Books?** Reading and comparing Books, computing with scripts, delivering files, remembering earlier messages: [run an agent](#run-an-agent) with the Managed Agent API instead of calling a model.
12
13
 
@@ -35,10 +36,19 @@ The client can call Bkper AI directly with `auth.authenticatedFetch()`, which se
35
36
 
36
37
  In both cases usage counts against the user's allowance. See [Call from a browser](https://bkper.com/docs/api/ai-gateway.md#call-from-a-browser) for a request example.
37
38
 
38
- ## Ask a decision model
39
+ ## Ask a System One model
40
+
41
+ Every System One question, decision or extraction, goes to `POST /v1/systemone`. There are two ways to send it:
42
+
43
+ - **TypeSafe's SDK**, `@typesafe-ai/sdk`, types decision questions and their answers for you. It does not send extraction questions or images.
44
+ - **`fetch`** sends any question type, and images.
45
+
46
+ Bkper AI validates every answer against its question before responding, so your code can use it directly. Keep the questions, the thresholds, and the function that turns answers and facts into an action in one module.
47
+
48
+ ### With TypeSafe's SDK
39
49
 
40
50
  ```ts
41
- import { score, TypeSafeClient } from '@typesafe-ai/sdk';
51
+ import { noul, TypeSafeClient } from '@typesafe-ai/sdk';
42
52
 
43
53
  const decisionClient = new TypeSafeClient({
44
54
  apiKey: 'bkper-platform-outbound',
@@ -46,26 +56,69 @@ const decisionClient = new TypeSafeClient({
46
56
  defaultModel: 'jev',
47
57
  });
48
58
 
49
- export async function scoreRecurring(description: string) {
59
+ export async function recurringProbability(description: string): Promise<number> {
50
60
  const { answers } = await decisionClient.systemOne({
51
61
  state: { description },
52
62
  questions: {
53
- recurring: score('How likely is this a recurring charge?', [
54
- 'Unlikely',
55
- 'Possible',
56
- 'Likely',
57
- ]),
63
+ recurring: noul('Is this a recurring charge, such as a subscription or a monthly bill?'),
58
64
  },
59
65
  });
60
- return answers.recurring;
66
+ return answers.recurring.noul;
61
67
  }
62
68
  ```
63
69
 
64
70
  - **`apiKey`** is required by the SDK. In a Platform Worker, pass any placeholder: platform outbound replaces it with the user's authorization.
65
71
  - **`baseURL`** has no `/v1`. The SDK calls `POST /v1/systemone`, which behaves exactly like `POST /v1/decisions`.
66
- - **The answer is typed** from the question. Bkper AI validates every answer against its question before responding, so your code can use it directly.
72
+ - **The answer is typed** from the question: here, `noul` is the probability of yes, which your code compares with a threshold.
73
+
74
+ ### With fetch
75
+
76
+ ```ts
77
+ interface ValueAnswer {
78
+ value: T | null;
79
+ guess?: T;
80
+ p_null: number;
81
+ confidence: number;
82
+ }
83
+
84
+ interface InvoiceReading {
85
+ model: string;
86
+ answers: { total: ValueAnswer<number>; issue_date: ValueAnswer<string> };
87
+ truncated?: boolean;
88
+ }
89
+
90
+ interface BkperAiErrorBody {
91
+ error: { code: string; message: string };
92
+ }
93
+
94
+ export async function readInvoice(email: string): Promise {
95
+ // No Authorization header: the platform adds the user's.
96
+ const response = await fetch('https://ai.bkper.app/v1/systemone', {
97
+ method: 'POST',
98
+ headers: { 'Content-Type': 'application/json' },
99
+ body: JSON.stringify({
100
+ model: 'clairic',
101
+ state: email,
102
+ questions: {
103
+ total: { type: 'number', decimals: 2, instructions: 'Invoice total' },
104
+ issue_date: { type: 'date', instructions: 'Invoice issue date' },
105
+ },
106
+ }),
107
+ });
108
+ if (!response.ok) {
109
+ const { error } = (await response.json()) as BkperAiErrorBody;
110
+ throw new Error(`${error.code}: ${error.message}`);
111
+ }
112
+ // Bkper AI validated each answer against its question.
113
+ return (await response.json()) as InvoiceReading;
114
+ }
115
+ ```
116
+
117
+ - **`value` can be `null`** when the email probably lacks it. Send such items, and any response with `truncated: true`, to a person with the `guess`.
118
+ - **The model reads; code checks.** Compare the total with the invoice lines, and compute dates such as the due date, before anything reaches a Book.
119
+ - **Images** go in the same request, as base64 `assets`.
67
120
 
68
- [Decision Models](https://bkper.com/docs/ai/decision-models.md) covers designing the questions, facts, and thresholds; the [AI Gateway API](https://bkper.com/docs/api/ai-gateway.md#decision-models) covers the request, answers, errors, and caching. The open-source [Merge Duplicates app](https://github.com/bkper/bkper-apps/tree/main/merge-duplicates) uses this setup to suggest duplicate pairs for human review.
121
+ [System One Models](https://bkper.com/docs/ai/system-one-models.md) covers designing the questions, facts, and thresholds, and every question type; the [AI Gateway API](https://bkper.com/docs/api/ai-gateway.md#decision-questions) covers the request, answers, errors, and caching. The open-source [Merge Duplicates app](https://github.com/bkper/bkper-apps/tree/main/merge-duplicates) uses TypeSafe's SDK to suggest duplicate pairs for human review.
69
122
 
70
123
  ## Generate a language response
71
124
 
@@ -98,7 +151,7 @@ Keep schemas simple. Constraints such as a string's minimum or maximum length ma
98
151
 
99
152
  ## Run an agent
100
153
 
101
- For a chat that does real work on Books, start a session on the [Managed Agent API](https://bkper.com/docs/api/managed-agent.md) from the app's server. Bkper runs the agent in the user's private cloud workspace, with the `bkper` CLI, files, and durable sessions. Your app keeps its screens, prompts, and instructions. The Managed Agent is in beta.
154
+ For a chat that does real work on Books, start a session on the [Managed Agent API](https://bkper.com/docs/api/managed-agent.md) from the app's server. Bkper runs the agent in the user's private cloud workspace, with the `bkper` CLI, files, and durable sessions. Your app keeps its screens, prompts, and instructions.
102
155
 
103
156
  ```ts
104
157
  // No Authorization header: the platform adds the user's.
@@ -123,6 +176,7 @@ const session = await response.json();
123
176
  Then follow the session's stream, or poll the input until it completes, as in the [quick start](https://bkper.com/docs/api/managed-agent.md#quick-start).
124
177
 
125
178
  - **The user's agent.** Sessions belong to the user, so work started in your app continues in Bkper Agent or any other app.
179
+ - **The user's procedures.** The agent follows the user's [agent context](https://bkper.com/docs/ai/agent-context.md): their company's, their own, and the session's Book's, loaded after your instructions.
126
180
  - **Your services as tools.** The agent can call your app's API as the user. Describe the routes in your instructions, and the agent can run your checks instead of redoing them.
127
181
  - **Real changes.** Unlike a model call, the agent can change Books with the user's permissions. Say in your instructions when it may.
128
182
 
@@ -174,6 +228,7 @@ Every Bkper AI error has the same envelope: `{ error: { message, type, param, co
174
228
 
175
229
  - **TypeSafe SDK:** an `APIError` with `status` and the envelope in `body`, so read `error.body.error.code`. Network failures and timeouts throw `APIConnectionError`.
176
230
  - **AI SDK:** an `APICallError` with `statusCode` and the envelope in `data`, so read `error.data.error.code`. Output that does not match your schema throws `NoObjectGeneratedError`.
231
+ - **`fetch`:** a response that is not `ok` has the envelope as its JSON body. `fetch` does not retry.
177
232
 
178
233
  Both SDKs retry rate limits and server errors twice by default. A failed attempt costs nothing: Bkper AI charges only successful answers.
179
234
 
@@ -183,7 +238,7 @@ Map these errors to your route's typed error response. Keep the code and message
183
238
 
184
239
  - **Passing your own `fetch`.** The TypeSafe SDK calls `fetch` as its own method, which the Workers runtime rejects with `Illegal invocation`. Wrap it: `fetch: (input, init) => myFetch(input, init)`. Without the option, the SDK's default works.
185
240
  - **No `null` values.** The TypeSafe SDK's types accept `null` for state, instructions, and some criteria. Bkper AI rejects them with `400`.
186
- - **No SDK image uploads.** The TypeSafe SDK uploads images as multipart, which Bkper AI rejects with `400`. Send image requests with `fetch` as JSON, with base64 `assets`. See [Decision Models](https://bkper.com/docs/ai/decision-models.md#jev-by-typesafe).
241
+ - **No SDK image uploads.** The TypeSafe SDK uploads images as multipart, which Bkper AI rejects with `400`. Send image requests [with `fetch`](#with-fetch) as JSON, with base64 `assets`. See [System One Models](https://bkper.com/docs/ai/system-one-models.md#models) for each model's image limits.
187
242
  - **No `client.models.list()`.** It expects TypeSafe's catalog shape. Use the [`GET /v1/models`](https://ai.bkper.app/v1/models) catalog.
188
243
  - **Other System One clients** take `https://ai.bkper.app/v1` as their base URL.
189
244
  - **Flexible JSON schemas.** Open Responses always requests `strict: true`. For a schema that needs `strict: false`, such as a typed dynamic map, use `@ai-sdk/openai` with base URL `https://ai.bkper.app/v1`, its `.responses()` model, and `strictJsonSchema: false`.
@@ -192,11 +247,12 @@ Map these errors to your route's typed error response. Keep the code and message
192
247
 
193
248
  - **Send only task-relevant data.** Validate input and Book permissions at the app API boundary.
194
249
  - **Keep writes deterministic.** An answer or generated text must not create, merge, or alter a Transaction without application rules and any required human confirmation.
250
+ - **Test the decision without the model.** Unit-test the function that turns answers and facts into an action with fixed answers, just below and just above each threshold.
195
251
  - **Test the service.** Mock `fetch` and check what is sent, that the Worker adds no user token, and that errors stay actionable. Then run the app's normal check and build.
196
252
 
197
253
  ## Next steps
198
254
 
199
- - [Decision Models](https://bkper.com/docs/ai/decision-models.md): questions, answers, thresholds, and caching.
255
+ - [System One Models](https://bkper.com/docs/ai/system-one-models.md): decision and extraction questions, answers, and thresholds.
200
256
  - [Models and Usage](https://bkper.com/docs/ai/models.md): models, usage rates, the allowance, and privacy.
201
257
  - [AI Gateway API](https://bkper.com/docs/api/ai-gateway.md): tokens, raw HTTP requests, capabilities, and errors.
202
258
  - [Managed Agent API](https://bkper.com/docs/api/managed-agent.md): sessions, instructions, files, and streams.
@@ -113,8 +113,9 @@ The following variables can be used in `menuUrl` and `menuUrlDev`:
113
113
  | `${group.id}` | Selected group ID |
114
114
  | `${group.name}` | Selected group name |
115
115
  | `${group.properties.xxx}` | Group property value |
116
- | `${transactions.ids}` | Comma-separated selected transaction IDs |
116
+ | `${transactions.ids}` | Space-separated selected transaction IDs |
117
117
  | `${transactions.query}` | Current search query |
118
+ | `${app.state}` | The App's state in the Book URL, URL-encoded; empty without one. See [Keeping state in the Book URL](https://bkper.com/docs/platform/apps/context-menu.md#keeping-state-in-the-book-url). |
118
119
 
119
120
  ### Event handling
120
121
 
@@ -114,7 +114,7 @@ Each time the App iframe finishes loading, Bkper announces the requests it suppo
114
114
  ```js
115
115
  {
116
116
  type: 'bkper:host-ready',
117
- supports: ['navigate', 'show-book', 'expand', 'login'],
117
+ supports: ['navigate', 'show-book', 'expand', 'login', 'app-state'],
118
118
  }
119
119
  ```
120
120
 
@@ -124,6 +124,7 @@ Send each request only after receiving this message with its name in `supports`:
124
124
  - `bkper:show-book` with `show-book`.
125
125
  - `bkper:expand` with `expand`.
126
126
  - `bkper:login` with `login`.
127
+ - `bkper:app-state` with `app-state`.
127
128
 
128
129
  Until then, keep the normal link behavior. Register the message listener when the App starts, so it does not miss the message.
129
130
 
@@ -247,6 +248,144 @@ Bkper ignores the message when it does not come from the App iframe currently op
247
248
 
248
249
  Bkper does not reply.
249
250
 
251
+ #### Keeping state in the Book URL
252
+
253
+ An App can keep a short state in the Book's URL, such as the report or item open in it. Reloading the Book, going Back, or opening a shared link of the Book then opens the App where the user left it:
254
+
255
+ ```js
256
+ window.parent.postMessage({ type: 'bkper:app-state', state: 'expenses-2025' }, BKPER_ORIGIN);
257
+ ```
258
+
259
+ Bkper keeps the state as `appState`, next to the App's id in `app`:
260
+
261
+ ```
262
+ https://bkper.app/books/abc123/transactions?app=my-app&appState=expenses-2025
263
+ ```
264
+
265
+ Bkper ignores the message when any of these is true:
266
+
267
+ - It does not come from the App iframe currently open in the panel.
268
+ - It does not come from that iframe's own origin.
269
+ - `app` in the Book URL names another App.
270
+ - `state` is not a string of at most 128 letters (`A–Z`, `a–z`), digits, `_` or `-`.
271
+
272
+ For a valid request, Bkper replaces `appState` in the Book URL without reloading Bkper or the App and without adding a history entry, so Back stays the Book's. An empty `state` removes it. Bkper does not reply.
273
+
274
+ The App reads its state back through the [`${app.state}`](#available-expressions) expression of its menu URL:
275
+
276
+ ```yaml
277
+ menuUrl: https://my-app.bkper.app?bookId=${book.id}&state=${app.state}
278
+ ```
279
+
280
+ - **Opening a Book URL that names the App and its state**, such as from a link, Back, or a reload, opens the App with that state in its URL. When the App is already open, it receives the new URL in [`bkper:app-url-changed`](#live-context-updates) instead.
281
+ - **After a valid `bkper:app-state` that changes the App's URL**, such as a new state with `${app.state}` in its menu URL, the App receives `bkper:app-url-changed` with the state it just sent. Treat it as its own state, not a new place.
282
+ - **Opening the App from the menu, opening another App, or closing the App** removes `appState`.
283
+
284
+ The state is opaque to Bkper and visible in the Book's URL:
285
+
286
+ - Keep it a short reference, such as an id, not data.
287
+ - Anyone can write a link with any `appState`. Validate it, and treat a state the App does not recognize as no state.
288
+ - Older Bkper versions leave `${app.state}` in the URL unreplaced. Treat it, an empty value, or a missing one as no state.
289
+
290
+ ### Files in Bkper Agent
291
+
292
+ Bkper Agent shows the HTML files it delivers, such as a report an App's API returns for the agent, beside the conversation. Each file runs in a sandboxed frame:
293
+
294
+ - **An `<iframe sandbox="allow-scripts">` with the file as its `srcdoc`.** The frame's origin is opaque (`null`), so the file cannot reach Bkper, the Agent, or their sessions.
295
+ - **A Content Security Policy ahead of the file's own content**: `default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src data: blob:; font-src data:; media-src data: blob:; form-action 'none'; base-uri 'none'`. Scripts and styles must be inline, and images, fonts, and media `data:` or `blob:` URLs. The file reaches no network.
296
+ - **Up to 1 MB.** Larger HTML files only download.
297
+
298
+ A file can use one request of the Bkper page around the Agent: `bkper:navigate`, such as for an **Open in** link that replaces the Agent with an App in the same panel and Book.
299
+
300
+ #### File host support
301
+
302
+ Each time the file's frame finishes loading, while the Agent is open in a Bkper panel that accepts navigation, the Agent tells the file:
303
+
304
+ ```js
305
+ {
306
+ type: 'bkper:host-ready',
307
+ supports: ['navigate'],
308
+ origin: 'https://bkper.app',
309
+ }
310
+ ```
311
+
312
+ - `origin` is the Bkper origin to link to. The message's `event.origin` is the Agent's, such as `https://agent.bkper.app`, because the Agent hosts the file, not Bkper.
313
+ - When Bkper starts accepting navigation after the file loaded, the Agent tells the file again.
314
+ - When the Agent is not in a Bkper panel that accepts navigation, such as the Agent opened on its own, the Agent sends nothing. Keep links as plain links that open a new tab.
315
+
316
+ #### Requesting navigation from a file
317
+
318
+ Post the Bkper URL to the Agent, at the `event.origin` of its `bkper:host-ready`:
319
+
320
+ ```js
321
+ window.parent.postMessage(
322
+ {
323
+ type: 'bkper:navigate',
324
+ url: 'https://bkper.app/books/abc123/transactions?app=my-app&appState=expenses-2025',
325
+ },
326
+ agentOrigin
327
+ );
328
+ ```
329
+
330
+ The Agent ignores the message silently unless all of these are true:
331
+
332
+ - It comes from the file's own frame.
333
+ - That frame has focus: the user is interacting with the file, such as by clicking in it.
334
+ - `url` is an absolute Bkper URL with no username or password, as for a link in the agent's replies.
335
+ - The Agent is open in a Bkper panel that accepts navigation.
336
+
337
+ Then the Agent asks Bkper to navigate, as when the user clicks a link in the conversation:
338
+
339
+ - **A Book page that names an App and its state** (`app` and `appState`): Bkper opens that App with that state, if the App is installed in that Book. When the Agent is open in a Book, the App replaces it in the same panel, without reloading Bkper.
340
+ - **A Book page without `app`**: Bkper navigates to it and the Agent stays open.
341
+ - **Other Bkper pages**: Bkper loads the page as a normal navigation.
342
+
343
+ Neither the Agent nor Bkper replies.
344
+
345
+ Send `bkper:navigate` only in response to a user action, such as a click. The focus rule keeps a file from navigating as it loads, but the frame keeps focus after a click, so the Agent cannot tell a click from a later request.
346
+
347
+ #### File example
348
+
349
+ Keep the link a real link to the App that opens in a new tab, so it works wherever navigation is not available:
350
+
351
+ ```html
352
+ <a id="open-in-app" href="https://my-app.bkper.app?bookId=abc123&state=expenses-2025" target="_blank">
353
+ Open in My App
354
+ </a>
355
+ ```
356
+
357
+ Then turn a plain click into a navigation request once the Agent supports it:
358
+
359
+ ```js
360
+ let host; // The Bkper origin to link to, and the Agent's origin to post to.
361
+
362
+ window.addEventListener('message', event => {
363
+ // Only the window around the file, the Agent, tells it what it may ask.
364
+ if (event.source !== window.parent) return;
365
+
366
+ const message = event.data;
367
+ if (message?.type !== 'bkper:host-ready' || !Array.isArray(message.supports)) return;
368
+ host =
369
+ message.supports.includes('navigate') && typeof message.origin === 'string'
370
+ ? { bkper: message.origin, agent: event.origin }
371
+ : undefined;
372
+ });
373
+
374
+ document.getElementById('open-in-app').addEventListener('click', event => {
375
+ // Keep modified and non-primary clicks as normal links, such as opening a new tab.
376
+ if (!host || event.button !== 0) return;
377
+ if (event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return;
378
+
379
+ event.preventDefault();
380
+ const url = new URL('/books/abc123/transactions', host.bkper);
381
+ url.searchParams.set('app', 'my-app');
382
+ url.searchParams.set('appState', 'expenses-2025');
383
+ window.parent.postMessage({ type: 'bkper:navigate', url: url.href }, host.agent);
384
+ });
385
+ ```
386
+
387
+ The file cannot verify the Bkper origin itself. It posts only to the window that sent `bkper:host-ready`, and the Agent checks the URL again.
388
+
250
389
  ### Available expressions
251
390
 
252
391
  The menu URL supports these dynamic expressions:
@@ -259,5 +398,6 @@ The menu URL supports these dynamic expressions:
259
398
  | `${account.name}` | The selected account name |
260
399
  | `${group.id}` | The selected group ID |
261
400
  | `${group.name}` | The selected group name |
401
+ | `${app.state}` | The App's state in the Book URL, URL-encoded; empty without one. See [Keeping state in the Book URL](#keeping-state-in-the-book-url). |
262
402
 
263
403
  For the full list of accepted expressions, see the [Menu URL variables](https://bkper.com/docs/platform/apps/configuration.md#menu-url-variables) reference.
@@ -115,6 +115,33 @@ bkper app build
115
115
  4. Trigger events in Bkper and inspect handler responses in the activity stream.
116
116
  5. Run `npm run check` before considering the change complete.
117
117
 
118
+ ## Develop with Bkper Agent
119
+
120
+ [Bkper Agent](https://bkper.com/docs/ai/bkper-agent/build-apps.md) can build and change your app in its cloud workspace, and show it live beside the conversation. There, `bkper app dev` runs without `bkper auth login`: the workspace adds the person's credentials to the app's calls to Bkper.
121
+
122
+ To show live, an app needs:
123
+
124
+ - **Bkper CLI 5.8.0 or later** in its lockfile.
125
+ - **The template's current Vite config**, which accepts the live host the agent sets in `BKPER_LIVE_HOST`:
126
+
127
+ ```ts
128
+ // client/vite.config.ts
129
+ export default defineConfig(() => {
130
+ const liveHost = process.env.BKPER_LIVE_HOST;
131
+ return {
132
+ // ...
133
+ server: {
134
+ // ...
135
+ ...(liveHost
136
+ ? { allowedHosts: [liveHost] }
137
+ : { hmr: { host: 'localhost', port: 5173, clientPort: 5173 } }),
138
+ },
139
+ };
140
+ });
141
+ ```
142
+
143
+ The events tunnel does not run in the agent's workspace, and only the person's browser reaches the live app. Test event handlers and integrations on a preview with `bkper app deploy --preview`.
144
+
118
145
  ## Debugging
119
146
 
120
147
  - **Server errors** — Check the terminal output from `bkper app dev`. Worker runtime errors appear here.
@@ -21,7 +21,7 @@ The same Worker can expose app-defined `/api/*` routes. Treat those routes as th
21
21
  Apps call Bkper AI models through the AI gateway, with no provider accounts or keys:
22
22
 
23
23
  - **Language models** — multi-provider models over the Open Responses protocol, for text and structured output.
24
- - **Decision models** — typed answers with calibrated confidence: yes or no, one of your options, or a level on a scale.
24
+ - **System One models** — typed answers with calibrated confidence: judgments, such as yes or no, one of your options, or a level on a scale; values read from documents, such as an invoice total; and estimates of uncertain numbers. Your code decides what to do with them.
25
25
 
26
26
  Usage counts against the user's included Bkper AI allowance. An authenticated app API route or event establishes the user and app identity, and the platform adds authorization and usage attribution to the Worker's requests. For inference used only by the UI, the client can also call Bkper AI directly with the signed-in user's token.
27
27
 
@@ -64,7 +64,7 @@ Start every client with this structure, so it grows by adding pieces instead of
64
64
  - **Components render and report intent.** A component watches only the stores it shows and changes them only through their actions, in response to the person, never while rendering. Only its own presentation, such as an open menu or hover, stays in the component. Each component owns its CSS.
65
65
  - **Stores ask the interface through events.** When a store needs the interface to act, such as focusing an input or scrolling to new content, it fires an event the component listens to. Stores never call components.
66
66
  - **One module wires the stores.** It creates them and gives each the stores it depends on. Dependencies point one way. A store changes another store only through that store's actions, and reactions that span stores live in this module. Components get only the stores and actions they use; services stay inside this module.
67
- - **One module owns the URL.** Only it reads or writes the URL's path, query, and `history`, mapping the URL to state. Put in the URL what a person would reload or share, such as the selected item. Standalone, add a history entry for each place the person goes, so Back works; when a place becomes another, such as a new item once saved, replace its entry. Embedded in a Book, replace the URL so Back stays the Book's. Pass it the window so it can be tested.
67
+ - **One module owns the URL.** Only it reads or writes the URL's path, query, and `history`, mapping the URL to state. Put in the URL what a person would reload or share, such as the selected item. Standalone, add a history entry for each place the person goes, so Back works; when a place becomes another, such as a new item once saved, replace its entry. Embedded in a Book, replace the URL so Back stays the Book's, and keep what a person would reload or share in the Book's URL with [`bkper:app-state`](https://bkper.com/docs/platform/apps/context-menu.md#keeping-state-in-the-book-url). Pass it the window so it can be tested.
68
68
  - **Split by concern, not by screen region.** Split a store or component when its parts change for different reasons.
69
69
 
70
70
  ## Security
@@ -129,7 +129,7 @@ Bkper maintains a continuous ledger with no concept of closing periods — the s
129
129
 
130
130
  ## Custom Properties
131
131
 
132
- **Custom Properties** are key-value pairs attachable to any entity — Books, Accounts, Groups, Transactions, Collections, and Files. They add context, metadata, and meaning beyond core financial data.
132
+ **Custom Properties** are key-value pairs attachable to any entity — Books, Accounts, Groups, Transactions, and Files. They add context, metadata, and meaning beyond core financial data.
133
133
 
134
134
  By attaching properties like `invoice: inv123456` or `exc_code: BRL`, entities become rich with information that can drive automation and reporting — without changing the core model.
135
135
 
package/lib/docs/index.md CHANGED
@@ -8,9 +8,9 @@ For Bkper app implementation, refactoring, or code review, always read `apps/qua
8
8
  - `cli/app-usage.md` — Using Bkper apps to do work on a Book instead of rebuilding what they do: list a Book's installed apps and the app catalog, read descriptions, readmes, and property schemas, match them to the Book's properties, read an app's OpenAPI spec and call its API as the user, install apps.
9
9
  - `cli/app-management.md` — CLI reference for building and deploying Bkper apps: init/git clone/credential helpers, dev/build/deploy workflow, app install/uninstall, secrets management, app logs, bkper.yaml configuration reference (identity, branding, events, menu integration, deployment).
10
10
  - `apps/overview.md` — Platform evaluation and capability overview: use when comparing managed Bkper hosting with self-managed infrastructure or clarifying platform responsibilities; use the task-specific app references for implementation.
11
- - `apps/ai.md` — Bkper AI in apps, scripts, and tools: ask the Jev decision model with TypeSafe's SDK or language models with AI SDK Open Responses, authenticate through app `/api/*` routes or a Bkper token outside the platform, handle errors, and keep Book writes under deterministic application control.
12
- - `ai/decision-models.md` — Designing software around decision models: when to use one, the three kinds of question, a step-by-step workflow from facts to thresholds and human review, and a worked bank-line example. The request, answers, errors, and caching are in `api/ai-gateway.md`.
13
- - `api/ai-gateway.md` — Bkper AI Gateway API guide: call Bkper AI language and decision models from your own client, script, or server — authentication, model IDs, requests, decision request rules and answer guarantees, streaming, errors, caching, and links to each operation's page.
11
+ - `apps/ai.md` — Bkper AI in apps, scripts, and tools: ask System One models such as Jev or Clairic, with TypeSafe's SDK for decision questions or `fetch` for any question type, or language models with AI SDK Open Responses, authenticate through app `/api/*` routes or a Bkper token outside the platform, handle errors, and keep Book writes under deterministic application control.
12
+ - `ai/system-one-models.md` — Designing software around System One models: decision questions (Jev, Clef) for yes/no, choice, and score judgments, and extraction questions (Clairic, preview) for values read from documents, with spans, nulls, and estimates. Covers when to use each, the rule that models read and judge while code calculates and decides, a workflow that sorts each condition into code facts and one-judgment questions and combines them in code with thresholds and human review, and worked bank-line and supplier-email examples. The request, answers, errors, and caching are in `api/ai-gateway.md`.
13
+ - `api/ai-gateway.md` — Bkper AI Gateway API guide: call Bkper AI language and System One models from your own client, script, or server — authentication, model IDs, requests, System One request rules and answer guarantees, streaming, errors, caching, and links to each operation's page.
14
14
  - `api/managed-agent.md` — Bkper Managed Agent API guide: build apps, chat bots, and scripts on the agent behind Bkper Agent — sessions, instructions, inputs and idempotency, Book context, streams, files, a Slack bot example, limits, errors, and links to each operation's page.
15
15
  - `apps/first-app.md` — First-app walkthrough: scaffold, install, run locally, trigger an event, customize the listing, establish shared source, check, and deploy.
16
16
  - `apps/architecture.md` — App and template architecture: npm workspace structure, Lit/Vite client, Hono Worker, typed `/api/*` contracts, authentication, `/events`, static assets, and supported app shapes.
@@ -21,7 +21,7 @@ For Bkper app implementation, refactoring, or code review, always read `apps/qua
21
21
  - `apps/event-handlers.md` — Event handler behavior: `/events` routing, responses, replay, loop prevention, platform and self-hosted authentication, event payloads, and event types.
22
22
  - `apps/deploying.md` — Build, sync, and explicit deploy workflow; production and preview environments, secrets, KV, deployment status, and book installation.
23
23
  - `apps/shared-app-source.md` — Bkper-managed private Git source: developer access, first sync, clone workflow, source/deployment separation, safety checks, external remotes, and monorepos.
24
- - `apps/context-menu.md` — Book context-menu integration: production/development URLs, open modes, and dynamic Book, query, Account, and Group expressions.
24
+ - `apps/context-menu.md` — Book context-menu integration: production/development URLs, open modes, dynamic Book, query, Account, Group, and App-state expressions, live context updates, keeping App state in the Book URL, and HTML files shown in Bkper Agent (sandbox, size limit, navigation requests).
25
25
  - `apps/app-listing.md` — App listing metadata, visibility, publication review, end-user README guidance, and public listing locations.
26
26
  - `apps/self-hosted.md` — Self-hosted event-handler alternatives: Cloud Functions, generic webhooks, direct authentication responsibilities, scaling, responses, and retries.
27
27
  - `reporting/financial-statements.md` — Deterministic reporting principles and Bkper query semantics for balance sheet and P&L: trusted routes, root reporting groups, permanent vs period date rules, and provisional query patterns.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bkper",
3
- "version": "5.8.0",
3
+ "version": "5.8.2",
4
4
  "description": "Official Bkper CLI for accounting data, automation, apps, and AI agents",
5
5
  "bin": {
6
6
  "bkper": "lib/cli.js"
@@ -1,158 +0,0 @@
1
- # Decision Models
2
-
3
- A decision model judges; your code decides. It reads the facts your code gives it, such as a bank line, and answers narrow questions in a shape you set in advance: how likely something is true, which of your options fits, or where it sits on your scale. It writes no text, and it reports how sure it is as a number your code can compare.
4
-
5
- Why that suits accounting is covered in [AI Fundamentals](https://bkper.com/docs/ai/fundamentals.md#decision-models). This page is about designing with decision models. [Jev](#jev-by-typesafe), by TypeSafe, is Bkper's first.
6
-
7
- ## When to use one
8
-
9
- | Your software needs | Use |
10
- | ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
11
- | A yes or no, one of known options, or a level on a scale | A decision model |
12
- | Text, explanations, code, tool calls, or a custom JSON object | A [language model](https://bkper.com/docs/ai/models.md) |
13
- | A conversation that works on Books, computes, and delivers files | An agent: [Bkper Agent](https://bkper.com/docs/ai/bkper-agent.md), or the [Managed Agent API](https://bkper.com/docs/api/managed-agent.md) in your app |
14
-
15
- ## Where you use them
16
-
17
- - **In [Bkper CLI Agent](https://bkper.com/docs/ai/bkper-cli-agent.md#what-it-can-do)**, with no setup. Describe the outcome, such as "suggest Accounts for these bank lines and show me only the unsure ones", and the agent asks the decision model for you.
18
- - **In apps and scripts**, with TypeSafe's SDK. See [Add Bkper AI to an App](https://bkper.com/docs/platform/apps/ai.md#ask-a-decision-model). The open-source [Merge Duplicates app](https://github.com/bkper/bkper-apps/tree/main/merge-duplicates) uses one to suggest duplicate pairs for a person to review.
19
-
20
- ## Three kinds of question
21
-
22
- Each question gets one typed answer:
23
-
24
- | Ask | Example | You get |
25
- | ---------------------------------- | --------------------------------------------- | ---------------------------------------------------- |
26
- | **Is this true?** (`noul`) | Is this bank line already recorded? | The probability of yes, from 0 to 1 |
27
- | **Which one of these?** (`choice`) | Which Account should receive this payment? | One of your options, with a confidence from 0 to 1 |
28
- | **Where on this scale?** (`score`) | How urgently should someone review this line? | A position on your levels, with a confidence |
29
-
30
- Confidence is high when the model's probability concentrates on one answer. For _Is this true?_, the probability itself is the signal. Ask several questions about the same facts in one request; the model answers each one independently.
31
-
32
- ## Design a decision workflow
33
-
34
- 1. **Find the judgment.**
35
-
36
- Look for the step where a person glances and decides: which Account, is this a duplicate, does this need a second look. A good question is a snap judgment that a knowledgeable person makes in seconds.
37
-
38
- 2. **Let code gather the facts.**
39
-
40
- Code fetches the item and the context a person would need, such as nearby Transactions, how an Account is usually described, or Book and Account properties. Pass them as named fields, such as `bank_line` and `existing_transaction`. Facts can also be images, such as a receipt photo. Convert PDFs and other files to text or images first.
41
-
42
- 3. **Ask narrow questions.**
43
-
44
- Ask one judgment per question. Split bigger judgments into several questions and combine the answers in code. Write each question in full: the model sees your instructions and the facts, never the name your code gives the question.
45
-
46
- 4. **Keep calculation in code.**
47
-
48
- Match amounts, compute date windows, and check balances in code, then ask the model only the part that needs judgment. For example, find Transactions with the same amount inside a date window, then ask only whether their descriptions describe the same movement.
49
-
50
- 5. **Set thresholds by risk.**
51
-
52
- Decide how sure the model must be before code acts. A missed suggestion costs a person a few seconds; a duplicate posting misstates a Book. Keep thresholds in one reviewable place.
53
-
54
- 6. **Act when confident; send the rest to a person.**
55
-
56
- Code acts on answers above the threshold and routes the rest to review. This is TypeSafe's [confidence-gated routing](https://docs.typesafe.ai/patterns/confidence-routing) pattern.
57
-
58
- 7. **Keep Book writes in code.**
59
-
60
- An answer is a judgment, not permission to change a Book. When code posts, it records a normal Transaction, so the Book stays zero-sum whatever the model answered. Store the model revision and the confidence as Transaction properties for the audit trail.
61
-
62
- 8. **Measure and adjust.**
63
-
64
- Start with conservative thresholds and test them against your own records. Re-check them when the model's revision changes.
65
-
66
- ## Putting it all together
67
-
68
- A bank line arrives: `AMAZON MKTPL*2K4LM`, 89.90 out of Checking. Code finds a manual entry from the day before with the same amount, "Printer toner, Amazon order 114-2K4LM", and asks three questions at once. Jev answered:
69
-
70
- | Question | Answer |
71
- | --------------------------------------------------------------------------------------------------------- | ------------------------------ |
72
- | Which Account should receive the money? Cloud Hosting, Software Subscriptions, Office Supplies, or Travel | Office Supplies, confidence 1 |
73
- | Does the existing entry already record this movement? | Yes, with probability 0.89 |
74
- | How urgently should a bookkeeper review it? Routine, Check, or Urgent | 0.09, Routine; confidence 0.86 |
75
-
76
- Code then decides:
77
-
78
- ```ts
79
- // Keep questions and thresholds in one reviewable place.
80
- const DUPLICATE_THRESHOLD = 0.8;
81
- const REVIEW_SCORE_THRESHOLD = 1.5;
82
- const AUTO_POST_CONFIDENCE = 0.9;
83
-
84
- interface BankLineAnswers {
85
- account: { type: 'choice'; choice: string; confidence: number };
86
- already_recorded: { type: 'noul'; noul: number };
87
- review_priority: { type: 'score'; score: number; confidence: number };
88
- }
89
-
90
- type BankLineDecision =
91
- | { action: 'check-duplicate' }
92
- | { action: 'review'; suggestedAccount: string }
93
- | { action: 'post'; toAccount: string; confidence: number };
94
-
95
- export function decideBankLine(answers: BankLineAnswers): BankLineDecision {
96
- if (answers.already_recorded.noul >= DUPLICATE_THRESHOLD) {
97
- return { action: 'check-duplicate' };
98
- }
99
- if (
100
- answers.review_priority.score >= REVIEW_SCORE_THRESHOLD ||
101
- answers.account.confidence < AUTO_POST_CONFIDENCE
102
- ) {
103
- return { action: 'review', suggestedAccount: answers.account.choice };
104
- }
105
- return {
106
- action: 'post',
107
- toAccount: answers.account.choice,
108
- confidence: answers.account.confidence,
109
- };
110
- }
111
- ```
112
-
113
- These answers return `check-duplicate`: the movement is probably already recorded, so code posts nothing. When code does post, it records a Transaction from Checking to the chosen Account. The risks to control are a wrong Account and a duplicate movement, which is why those checks come first.
114
-
115
- The exact request and response are in the [AI Gateway API guide](https://bkper.com/docs/api/ai-gateway.md#decision-models).
116
-
117
- ### Context changes confidence
118
-
119
- Ask about the same bank line without the manual entry, and the answer changes:
120
-
121
- | Facts given | Which Account? |
122
- | ----------------------------------- | --------------------------------------------------------------------- |
123
- | The bank line and the manual entry | Office Supplies, confidence 1 |
124
- | The bank line alone | Office Supplies, confidence 0.75, with 0.14 on Software Subscriptions |
125
-
126
- The top option is the same, but the model reports that it is less sure, so `decideBankLine` sends the line to review. Give the model the context a person would need.
127
-
128
- For more designs, see TypeSafe's [Patterns](https://docs.typesafe.ai/patterns) and [Cookbooks](https://docs.typesafe.ai/cookbooks).
129
-
130
- ## Common mistakes
131
-
132
- - **Asking for analysis.** Ask one snap judgment per question and combine the answers in code.
133
- - **Asking the model to calculate.** Match amounts, compute date windows, and check balances in code.
134
- - **Putting the question in its name.** The model never sees question IDs. Write the full question in its instructions.
135
- - **Treating answers as verdicts.** A probability of yes is not a boolean, and a score can fall between levels. Compare both with thresholds.
136
- - **Expecting an explanation.** Decision models return no text. Use a [language model](https://bkper.com/docs/ai/models.md) when you need one.
137
- - **Sending a language-model request.** A decision request carries only the model, the facts, and the questions. See the [request rules](https://bkper.com/docs/api/ai-gateway.md#decision-request).
138
-
139
- ## Jev by TypeSafe
140
-
141
- [Jev](https://docs.typesafe.ai/introduction) is TypeSafe's flagship model and the first System One model. Its Bkper model ID is `jev`.
142
-
143
- - **Versions.** `jev-latest` and versioned IDs are accepted but always select the current Jev; you cannot pin a version. Log the revision each answer reports, and re-check tuned thresholds when it changes.
144
- - **Input.** Text and images. English is Jev's primary training language; other languages work with lower accuracy.
145
- - **Images.** An experimental TypeSafe feature, so accuracy and limits can change. Send PNG or JPEG images between 280 and 1568 pixels per side as base64 `assets` in a JSON request; TypeSafe's SDKs upload images in a form Bkper AI does not accept. Image tokens count as input. See TypeSafe's [Images](https://docs.typesafe.ai/images) guide.
146
- - **Known weak spots.** Literal reading, arithmetic, date comparison, and large states full of irrelevant detail. See [Jev 1.13 jaggedness](https://docs.typesafe.ai/model-jaggedness/jev-1.13).
147
-
148
- Requests count against your Bkper AI allowance at Jev's [usage rates](https://bkper.com/docs/ai/models.md#usage-rates).
149
-
150
- ## Build it
151
-
152
- - [Add Bkper AI to an App](https://bkper.com/docs/platform/apps/ai.md#ask-a-decision-model) — ask a decision model from an app Worker, a script, or a browser with TypeSafe's SDK.
153
- - [AI Gateway API: decision models](https://bkper.com/docs/api/ai-gateway.md#decision-models) — the request, answer guarantees, errors, caching, and compatibility with TypeSafe.
154
- - [`createDecision` reference](https://bkper.com/docs/api/ai-gateway/operations/createdecision.md) — every field.
155
- - [Models and Usage](https://bkper.com/docs/ai/models.md) — usage rates, the allowance, and privacy.
156
- - Building with a coding agent? Point it to this page for design, and to `https://bkper.com/docs/api/ai-gateway.md` for the endpoint, authentication, and errors. TypeSafe's [agent skill](https://docs.typesafe.ai/agent-skill) adds questions and patterns.
157
- - TypeSafe: [System One](https://docs.typesafe.ai/concepts/system-one), [How to build with System One](https://docs.typesafe.ai/concepts/how-to-build-with-system-one), [AI primer](https://docs.typesafe.ai/introduction/machine-learning-primer), [Primitives](https://docs.typesafe.ai/primitives), [State](https://docs.typesafe.ai/concepts/state), [Confidence](https://docs.typesafe.ai/confidence), and [Patterns](https://docs.typesafe.ai/patterns).
158
- - [Back to AI overview](https://bkper.com/docs/ai.md).