@oar-sh/oar 0.9.17 → 0.9.19

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 (104) hide show
  1. package/.github/extensions/web-relay/server-lifecycle/managed-server.mjs +13 -1
  2. package/.github/extensions/web-relay/skills/tool-activity.mjs +5 -4
  3. package/CHANGELOG.md +234 -0
  4. package/README.md +13 -12
  5. package/package.json +1 -1
  6. package/server/claude-api-worker/claude-api-backend.mjs +345 -0
  7. package/server/claude-api-worker/claude-api-session-worker.mjs +29 -0
  8. package/server/claude-worker/claude-cli-pinned-env.mjs +150 -0
  9. package/server/claude-worker/claude-remote-relay-tool.mjs +5 -5
  10. package/server/claude-worker/claude-sdk-adapter.mjs +35 -9
  11. package/server/claude-worker/claude-session-process.mjs +166 -21
  12. package/server/claude-worker/claude-session-worker-main.mjs +3 -0
  13. package/server/claude-worker/claude-subscription-key-check.mjs +64 -0
  14. package/server/claude-worker/claude-turn-publisher.mjs +117 -5
  15. package/server/claude-worker/claude-usage-totals.mjs +53 -0
  16. package/server/claude-worker/sdk-message-normalizer.mjs +1 -1
  17. package/server/copilot-worker/copilot-remote-relay-tool.mjs +2 -2
  18. package/server/copilot-worker/copilot-sdk-event-normalizer.mjs +1 -1
  19. package/server/copilot-worker/copilot-sdk-session-process.mjs +9 -9
  20. package/server/cursor-worker/cursor-remote-relay-tool.mjs +3 -3
  21. package/server/cursor-worker/cursor-turn-runner.mjs +4 -4
  22. package/server/cursor-worker/sdk-message-normalizer.mjs +2 -2
  23. package/server/db-schema.mjs +33 -1
  24. package/server/deepseek-worker/deepseek-claude-backend.mjs +14 -130
  25. package/server/grok-worker/acp-client.mjs +1 -1
  26. package/server/grok-worker/grok-turn-runner.mjs +4 -4
  27. package/server/grok-worker/sdk-message-normalizer.mjs +1 -1
  28. package/server/mcp/oar-mcp-server.mjs +11 -5
  29. package/server/migrations/0031-queue-provider.mjs +143 -0
  30. package/server/migrations/0032-runtime-session-billing-switch.mjs +94 -0
  31. package/server/migrations/0033-claude-api-usage-checkpoints.mjs +138 -0
  32. package/server/migrations/0034-claude-api-usage-totals.mjs +112 -0
  33. package/server/public/app/activity-replay-state.mjs +4 -3
  34. package/server/public/app/agent-sessions-settings-ui.js +1 -1
  35. package/server/public/app/agent-sessions-settings.mjs +1 -1
  36. package/server/public/app/api-client.js +52 -0
  37. package/server/public/app/bootstrap.js +153 -27
  38. package/server/public/app/claude-api-settings-ui.js +362 -0
  39. package/server/public/app/claude-billing-toggle-ui.js +224 -0
  40. package/server/public/app/claude-billing-toggle.mjs +112 -0
  41. package/server/public/app/context-tier-options.mjs +6 -2
  42. package/server/public/app/context-usage-view.mjs +1 -1
  43. package/server/public/app/conversation-provider-indicator.mjs +11 -0
  44. package/server/public/app/conversation-view.js +29 -3
  45. package/server/public/app/inbox-view.mjs +1 -1
  46. package/server/public/app/journal-view.js +127 -10
  47. package/server/public/app/model-selector-options.mjs +17 -1
  48. package/server/public/app/new-conversation-model-choice.mjs +21 -0
  49. package/server/public/app/provider-readiness.mjs +5 -2
  50. package/server/public/app/relay-error-ctas.mjs +50 -0
  51. package/server/public/app/relay-schedules-ui.js +1 -1
  52. package/server/public/app/settings-modal.js +11 -0
  53. package/server/public/app/settings-tabs.js +1 -1
  54. package/server/public/app/socket-handlers.js +18 -1
  55. package/server/public/app/tool-activity-emoji.mjs +4 -3
  56. package/server/public/app/usage-limit-ui.js +136 -5
  57. package/server/public/index.html +189 -3
  58. package/server/relay-heap-guard.mjs +338 -0
  59. package/server/relay-self-restart.mjs +33 -7
  60. package/server/relay-tools.md +6 -6
  61. package/server/repositories/conversation-group-repository.mjs +1 -1
  62. package/server/repositories/message-repository.mjs +7 -0
  63. package/server/repositories/session-repository.mjs +8 -1
  64. package/server/routes/ask-user-routes.mjs +1 -1
  65. package/server/routes/conversation-group-routes.mjs +1 -1
  66. package/server/routes/messages-routes.mjs +678 -31
  67. package/server/routes/relay-ask-routes.mjs +3 -3
  68. package/server/routes/relay-event-routes.mjs +2 -2
  69. package/server/routes/relay-schedule-routes.mjs +1 -1
  70. package/server/routes/remote-relay-routes.mjs +3 -3
  71. package/server/routes/sessions-routes.mjs +365 -53
  72. package/server/server-runtime.mjs +373 -26
  73. package/server/services/about-service.mjs +1 -0
  74. package/server/services/background-work-view.mjs +2 -1
  75. package/server/services/claude-api-settings-service.mjs +575 -0
  76. package/server/services/claude-api-usage-service.mjs +361 -0
  77. package/server/services/claude-billing-swap-service.mjs +274 -0
  78. package/server/services/claude-billing-switch-service.mjs +343 -0
  79. package/server/services/plan-usage-claude-api.mjs +445 -0
  80. package/server/services/plan-usage-service.mjs +5 -0
  81. package/server/services/provider-model-selection.mjs +3 -2
  82. package/server/services/provider-reasoning-effort.mjs +9 -0
  83. package/server/services/relay-ask-service.mjs +1 -1
  84. package/server/services/relay-event-service.mjs +3 -2
  85. package/server/services/relay-schedule-service.mjs +1 -1
  86. package/server/services/remote-relay-caller-context.mjs +7 -0
  87. package/server/services/remote-relay-dispatcher.mjs +111 -17
  88. package/server/services/remote-relay-registry-service.mjs +1 -1
  89. package/server/services/session-worker-launch-service.mjs +61 -2
  90. package/server/services/session-worker-registry-service.mjs +28 -1
  91. package/server/services/session-worker-websocket-service.mjs +17 -0
  92. package/server/services/usage-limit-pause-service.mjs +55 -4
  93. package/server/services/worker-secret-redaction.mjs +2 -0
  94. package/shared/anthropic-api.mjs +202 -0
  95. package/shared/provider-routing.mjs +5 -3
  96. package/shared/relay-asks.mjs +11 -5
  97. package/shared/relay-events.mjs +2 -2
  98. package/shared/relay-schedules.mjs +2 -2
  99. package/shared/remote-relay-contract.mjs +54 -12
  100. package/shared/remote-relay-tool-core.mjs +23 -6
  101. package/shared/steer-settle-failure.mjs +1 -0
  102. package/shared/worker-runtime/api-client.mjs +2 -2
  103. package/shared/worker-runtime/heartbeat.mjs +5 -0
  104. package/shared/worker-runtime/worker-websocket-link.mjs +6 -0
@@ -1,3 +1,5 @@
1
+ import { relayRuntimeNodeFlags, relayRuntimeNodeFlagsOrNone } from "../../../../server/relay-heap-guard.mjs";
2
+
1
3
  export function createManagedServerLifecycle({
2
4
  api,
3
5
  dbg,
@@ -16,6 +18,8 @@ export function createManagedServerLifecycle({
16
18
  relayPort = 3333,
17
19
  nodeBin,
18
20
  serverStartTimeoutMs,
21
+ // The heap limit and heap snapshot flags every relay runtime starts with.
22
+ nodeFlags = relayRuntimeNodeFlags,
19
23
  }) {
20
24
  let managedServerProc = null;
21
25
  let managedServerStdoutFd = null;
@@ -301,7 +305,15 @@ export function createManagedServerLifecycle({
301
305
  if (startupWorkspaceRoot) {
302
306
  serverEnv.COPILOT_WORKSPACE_ROOT = startupWorkspaceRoot;
303
307
  }
304
- managedServerProc = spawn(nodeBin, serverArgs, {
308
+ // The runtime runs in this process (--supervised): its Node flags go here.
309
+ const { flags } = relayRuntimeNodeFlagsOrNone(nodeFlags, {
310
+ env: serverEnv,
311
+ execArgv: [],
312
+ serverDir,
313
+ fsImpl: fs,
314
+ logger: { log: (line) => dbg(line) },
315
+ });
316
+ managedServerProc = spawn(nodeBin, [...flags, ...serverArgs], {
305
317
  cwd: serverDir,
306
318
  env: serverEnv,
307
319
  stdio: ["ignore", managedServerStdoutFd, managedServerStderrFd],
@@ -3,7 +3,7 @@ import {
3
3
  formatToolResultActivity as formatSharedToolResultActivity,
4
4
  formatVoteMemoryActivity,
5
5
  } from "../../../../shared/tool-activity.mjs";
6
- import { isRemoteRelayToolName } from "../../../../shared/remote-relay-tool-core.mjs";
6
+ import { REMOTE_RELAY_TOOL_NAME, isRemoteRelayToolName } from "../../../../shared/remote-relay-tool-core.mjs";
7
7
  import { summarizeRemoteRelayCall } from "../../../../shared/remote-relay-contract.mjs";
8
8
 
9
9
  export function normalizeActivityText(value, maxToolDetailLength = 140) {
@@ -135,10 +135,11 @@ export function formatToolActivity(request, maxToolDetailLength = 140) {
135
135
  if (lower.includes("report_intent")) {
136
136
  return detail ? `● ${detail}` : "● Working…";
137
137
  }
138
- // The OAR MCP server's tool reaches the CLI as `oar-remote_relay`: show the
139
- // same line every other engine writes for it.
138
+ // The OAR MCP server's tool reaches the CLI as `oar-relay_tool` (up to
139
+ // 0.9.17 `oar-remote_relay`): show the same line every other engine writes
140
+ // for it.
140
141
  if (isRemoteRelayToolName(rawName)) {
141
- return `Tool (remote_relay): ${summarizeRemoteRelayCall(toolArgsSnapshot(request))}`;
142
+ return `Tool (${REMOTE_RELAY_TOOL_NAME}): ${summarizeRemoteRelayCall(toolArgsSnapshot(request))}`;
142
143
  }
143
144
  return detail ? `Tool (${rawName}): ${detail}` : `Tool (${rawName})`;
144
145
  }
package/CHANGELOG.md CHANGED
@@ -3,6 +3,240 @@
3
3
  All notable changes to OAR are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow semver.
5
5
 
6
+ ## [0.9.19] — 2026-10-27
7
+
8
+ Highlights: a relay that runs out of memory is restarted instead of staying
9
+ down. Its runtime starts with a heap limit, set with `heapLimitMb` in
10
+ `config.json`, and writes one heap snapshot when it nears that limit; a
11
+ snapshot holds the relay's auth token and API keys, so never share one as it
12
+ is. Agent sessions can use the providers a relay update added without a
13
+ restart of their own, and Copilot refuses another provider's model id before
14
+ it creates anything.
15
+
16
+ ### Fixed
17
+
18
+ - **A relay that runs out of memory is restarted.** A relay runtime that ran
19
+ out of memory ended the relay for good. Its supervisor took the
20
+ out-of-memory abort for a clean stop and exited 0, which systemd does not
21
+ restart. The runtime is now relaunched like any crash. It starts with a heap
22
+ limit (60 % of RAM, 2048–8192 MB, set with `heapLimitMb` in `config.json`)
23
+ and writes one heap snapshot to `diagnostics` in the data directory when it
24
+ nears that limit. A heap snapshot holds the relay's auth token and API keys:
25
+ never share one as it is. The status log shows its memory every 10 minutes
26
+ and when the heap passes 80 % of the limit.
27
+ - **`relay_tool` takes any provider id.** Agent sessions started before a
28
+ relay update refused the providers the update added (such as `deepseek` and
29
+ `claude-api`) in `relay_tool`'s `create_session` and `send`. The tool now
30
+ takes any provider id; the relay checks it against its current list and
31
+ names that list when it refuses one.
32
+ - **Copilot refuses another provider's model id before creating anything.** A
33
+ Copilot session given another provider's model id (such as `claude-opus-5-5`
34
+ for Copilot's `claude-opus-5.5`) was created and then refused with
35
+ `CURSOR_MODEL_REQUIRES_NEW_CONVERSATION`. Copilot now refuses such an id
36
+ with `COPILOT_MODEL_UNAVAILABLE` and the close match before anything is
37
+ created, and a first prompt refused after `create_session` made the session
38
+ names that session.
39
+
40
+ ### Upgrade notes
41
+
42
+ - **Agent sessions started before 0.9.19 keep their provider list:** their
43
+ workers keep running through the update, with the `relay_tool` they
44
+ started with. That list is the one 0.9.19 has, so nothing changes now; it
45
+ lacks the providers a later update adds until the session's worker
46
+ restarts, for example after **☠️ Kill session** in the `⋯` menu.
47
+
48
+ ## [0.9.18] — 2026-10-26
49
+
50
+ Highlights: Claude chats can run on a Claude Console API key. Claude API is
51
+ a provider beside your subscription, with an optional monthly spend cap and
52
+ a card in Check Usage with the estimated spend. A Claude chat can switch
53
+ between the subscription and the key and keep its Claude Code session, also
54
+ when it is paused at the usage limit. The relay's agent tool is now called
55
+ `relay_tool`. DeepSeek and Claude API chats start with all hooks off, and a
56
+ subscription chat no longer runs on an API key that Claude Code's settings
57
+ hand it.
58
+
59
+ ### Added
60
+
61
+ - **Claude API: Claude chats on a Claude Console API key.** A provider
62
+ beside Claude (your subscription), billed to the Console organisation
63
+ the key belongs to.
64
+ - Settings → Providers → Claude API holds the key, the switch, the
65
+ default model and an optional monthly spend cap in US dollars. The key
66
+ is stored on the relay host and never shown again: the tab only says
67
+ that one is saved. Any `sk-ant-` Console key is taken; Claude login
68
+ and session tokens and Admin keys are refused when you save. A key
69
+ Anthropic itself refuses stays saved, and the tab's status line says
70
+ so until a save or Refresh models goes through. A cap the field cannot
71
+ take is named under the field.
72
+ - The relay lists the key's models from Anthropic when the key is saved,
73
+ when Claude API is switched on again, and on Refresh models. Until
74
+ then it offers the Claude tab's models.
75
+ - Commit attribution, the background command limit, the effort levels
76
+ and the compaction window stay on the Claude tab, shared by both; the
77
+ Claude API tab links there.
78
+ - New Chat offers Claude API, Select Models has a Claude API tab, and
79
+ its chats show a gold "Claude API" pill and "🔒 Session locked to
80
+ Claude API models."
81
+ - A turn that Claude API refuses or could not run ends with buttons:
82
+ Claude API settings (at the cap field when the monthly cap is
83
+ reached), Switch to subscription, Add funds, Console billing or
84
+ Console limits, as fits the reason.
85
+ - When the relay refuses to start a Claude API chat (the monthly cap, no
86
+ key, switched off), New Chat stays open with the reason, Claude API
87
+ settings, and Start on subscription, which starts the same chat on
88
+ the Claude provider; on a phone the dialog scrolls to it.
89
+ - **Switch a Claude chat between your subscription and the Claude API
90
+ key.** `POST /api/conversation/:id/billing` moves a chat between
91
+ `claude` (the subscription) and `claude-api` (the saved key). It keeps
92
+ its Claude Code session.
93
+ - In the browser, a Claude chat has a `Subscription | API key` toggle
94
+ under the lock note while Claude API is on with a saved key. It says
95
+ what a pending switch waits for, and why a side cannot be chosen; at
96
+ the monthly cap it says the chat stays on the subscription, and so
97
+ does the usage-limit banner.
98
+ - The switch applies from the next turn: a running turn finishes on the
99
+ billing it started on. Messages already queued run on the new one.
100
+ - The relay restarts the chat's Claude Code between turns. It waits
101
+ while a turn, a question, a compaction or a background task is still
102
+ running.
103
+ - The transcript notes each switch. The first turn on the key has no
104
+ prompt cache and costs more.
105
+ - The switch is refused, with the reason, when the key is missing or
106
+ Claude API is off, when the monthly cap is reached, or when the
107
+ chat's model is not on the target's model list.
108
+ - **Switch this chat to API key at the usage limit.** When a subscription
109
+ chat is paused at the Claude usage limit, the banner offers the switch
110
+ if the chat may move to the key. The paused turn then carries on on
111
+ the key at once. Nothing switches by itself.
112
+ - **Agents can switch a Claude session's billing.** `relay_tool` `send`
113
+ takes `provider` (`claude` or `claude-api`) for a Claude session. The
114
+ other billing switches the session together with the message:
115
+ - in one call, so a refused switch sends nothing and a refused message
116
+ switches nothing;
117
+ - the approval card says "Switches billing to API key";
118
+ - a relay from before this version refuses it and sends nothing.
119
+ - **A Claude API card in Check Usage.** It shows what this relay's turns
120
+ on the Claude API key are estimated to have cost today and this month,
121
+ per model, with the tokens, and the monthly cap as a bar when one is set.
122
+ - The figures are Claude Code's own estimate from its price table, so
123
+ sub-agents, compaction and web search are in them. The Console's
124
+ billing page (linked) has the real figures and the balance.
125
+ - Days and the month follow the relay's time zone, and the cap starts
126
+ over at local midnight on the 1st.
127
+ - Tokens Claude Code has no price for show as "no price known" or
128
+ "estimate incomplete", never as $0.
129
+ - Turns paid from a Max or Team plan's subscriber API credit are counted
130
+ too; OAR cannot see that credit.
131
+ - The card stays while a key is saved, also with Claude API switched
132
+ off, so the month's spend stays in view (DeepSeek's card goes with the
133
+ provider).
134
+ - **A monthly cap for Claude API.** Once this month's estimate reaches the
135
+ cap set in Settings → Providers → Claude API:
136
+ - a new turn on the key does not run: the chat gets a note with the code
137
+ `relay.claude-api-cap-reached`. A turn Claude Code starts by itself,
138
+ when a background task reports back, gets the note and that chat's
139
+ background tasks are stopped as soon as the relay hears of the turn,
140
+ since each report would start another such turn; the turn itself is
141
+ stopped when the worker takes the stop. Its first request may already
142
+ be billed, and a short turn can end before the stop arrives. The note
143
+ also mentions tasks no stop reaches, since they can keep starting such
144
+ turns and keep a switch to the subscription waiting. The note comes
145
+ once per chat until the cap clears, a Claude API setting is saved, or a
146
+ turn of that chat runs on the key again. The same stop applies when
147
+ Claude API has no key or is switched off;
148
+ - a switch to the key is refused;
149
+ - an agent's send to a session on the key and a new Claude API chat (New
150
+ Chat or an agent's `create_session`) get 409 `CLAUDE_API_CAP_REACHED`,
151
+ and nothing is queued or created.
152
+
153
+ A turn that is already running finishes. A turn's cost is booked when it
154
+ ends, so running turns can take the month past the cap. The cap counts
155
+ only the priced part of the estimate. If the spend cannot be read, the cap counts as
156
+ reached. Console spend limits still apply on top.
157
+
158
+ ### Changed
159
+
160
+ - **A send does not switch a Claude chat's billing.** A message that
161
+ names the other billing gets 409 `CLAUDE_BILLING_SWITCH_REQUIRED`
162
+ (before, a Claude API chat ignored `provider: "claude"`). A message
163
+ from a page that still showed the other billing gets 409
164
+ `CLAUDE_BILLING_CHANGED`. Its text goes into the chat's draft, so the
165
+ page, and a send replayed from the offline outbox, lose nothing. The
166
+ outbox keeps the text only, not attachments.
167
+
168
+ - **No hooks or status line run in DeepSeek chats.** In 0.9.17, Claude Code
169
+ in a DeepSeek chat ran the hooks and the `statusLine` command of
170
+ DeepSeek's settings folder, of the chat folder's `.claude/settings.json`
171
+ and `settings.local.json`, and of plugins, as the relay's user with the
172
+ DeepSeek key in their environment; a folder's `SessionStart` hook ran
173
+ before the relay had pinned the endpoint and key. Now those chats start
174
+ with all hooks off, and so do Claude API chats. The setting is on Claude
175
+ Code's command line, so it is in force from the start, and a folder's
176
+ settings can't turn it back on (`scripts/claude-cli-hooks-proof.mjs`
177
+ shows it on the bundled Claude Code). Hooks in managed settings still
178
+ run. Chats on your Claude login keep their hooks and status line. The
179
+ agent's own commands can still read the key; the relay redacts it in
180
+ what it shows.
181
+ - **The relay's agent tool is now called `relay_tool`.** It was
182
+ `remote_relay`, and it is listed under the new name on every provider
183
+ (Claude's `mcp__relay__relay_tool`), with the same actions and fields; the
184
+ docs and the agents' instructions use it too. OAR's own MCP server, which
185
+ Grok and the Copilot extension engine use, still runs a call to
186
+ `remote_relay` but no longer lists it. Tool lines written under the old
187
+ name still show as this tool.
188
+ - If your own instructions, permission rules or hooks name `remote_relay`
189
+ or `mcp__relay__remote_relay`, change them to `relay_tool` or
190
+ `mcp__relay__relay_tool`: outside OAR's MCP server the old name is
191
+ refused.
192
+ - **A subscription chat never runs on an API key.** Claude Code takes an
193
+ API key over your Claude login when one of its settings hands it one:
194
+ - `env.ANTHROPIC_API_KEY` in `~/.claude/settings.json` or the chat
195
+ folder's `.claude/settings*.json`;
196
+ - an `apiKeyHelper`;
197
+ - a Console login.
198
+
199
+ Until now such a chat ran on that key and billed the key's owner. Now
200
+ the turn stops at Claude Code's start, with a note naming the source
201
+ and the setting to remove. At most one model request, sent a moment
202
+ after that start, can go out first.
203
+
204
+ - **The docs cover Claude API.** The providers guide has a Claude API
205
+ section: the key, the models, the shared `~/.claude`, the billing switch
206
+ and when it applies, what fails closed, the monthly cap and the
207
+ subscriber API credit. The web UI, configuration, security,
208
+ agents-together and troubleshooting pages, the README, the server
209
+ README and DEVELOPING.md (the worker and its live check) cover it too,
210
+ and the feature tracker has a Claude API page. Troubleshooting has two
211
+ known gaps:
212
+ - a key that is not tied to a workspace gets HTTP 400 from Anthropic;
213
+ for now, create the key inside a workspace (naming the workspace in
214
+ OAR is planned);
215
+ - a model Claude Code has no price for (currently Claude Haiku 5.5)
216
+ shows "no price known" on the Claude API card, and its tokens are left
217
+ out of the estimate.
218
+ - **Corrections to the 0.9.17 notes:**
219
+ - DeepSeek's budget bar changes colour at 50 % and 75 % of the budget
220
+ and turns red at 90 %; the notes said amber near it and red over it.
221
+ - The composer's context chip shows DeepSeek's 1M window (1,048,576
222
+ tokens) as `1.05M`.
223
+ - The `preview` tool's hint to bind a dev server to 127.0.0.1 reaches
224
+ only sessions that have the tool (Claude, Claude API, DeepSeek, Cursor,
225
+ and Grok and Copilot's Extension engine through OAR's MCP server), not
226
+ every provider. Copilot's SDK engine, and those two when the relay runs
227
+ with `OAR_MCP_SERVER=0`, are taught the preview API without it.
228
+
229
+ ### Upgrade notes
230
+
231
+ - **Downgrading to 0.9.17:** first switch Claude chats on the Claude API
232
+ key back to Subscription. 0.9.17 does not know Claude API, so a chat
233
+ left on the key runs as a Copilot chat there. That now includes a chat
234
+ that started on the subscription and was switched to the key. 0.9.17
235
+ ignores the new database columns and tables. The two triggers on the
236
+ queue table keep stamping its new column there, which does no harm.
237
+ - **Downgrading to 0.9.17 turns hooks back on in DeepSeek chats:** they
238
+ run the hooks and status line of their settings folders again.
239
+
6
240
  ## [0.9.17] — 2026-10-25
7
241
 
8
242
  Highlights: DeepSeek is a provider of its own. Paste a DeepSeek API key and
package/README.md CHANGED
@@ -27,7 +27,7 @@ flowchart LR
27
27
  end
28
28
  subgraph host["Your computer"]
29
29
  relay["OAR relay<br/>chats, queue, history, files"]
30
- agents["Copilot · OpenAI · Claude<br/>Cursor · Grok · DeepSeek"]
30
+ agents["Copilot · OpenAI · Claude · Claude API<br/>Cursor · Grok · DeepSeek"]
31
31
  end
32
32
  cloud["☁️ Claude Cloud<br/>sandbox at Anthropic"]
33
33
  phone <--> relay
@@ -36,7 +36,7 @@ flowchart LR
36
36
  relay <--> cloud
37
37
  ```
38
38
 
39
- - **Seven runtimes, one chat**: you pick the agent per conversation, and all of them share the same chat, queue, history, file browser, and question cards ([Runtimes](#runtimes)).
39
+ - **Eight runtimes, one chat**: you pick the agent per conversation, and all of them share the same chat, queue, history, file browser, and question cards ([Runtimes](#runtimes)).
40
40
  - **Yours**: the relay runs on your hardware, answers only on this machine until you change that, and collects no telemetry ([Security notes](#security-notes)).
41
41
  - **Under active development**: expect occasional rough edges, and some provider SDK features that are missing or incomplete.
42
42
 
@@ -45,29 +45,29 @@ flowchart LR
45
45
  <table>
46
46
  <tr>
47
47
  <td width="42%" rowspan="4" valign="top">
48
- <a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-mobile.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.17" alt="OAR on a phone: a finished agent turn in a conversation, with the composer below"></picture></a>
48
+ <a href="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-mobile.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/cfmail-mobile.png?v=0.9.19" alt="OAR on a phone: a finished agent turn in a conversation, with the composer below"></picture></a>
49
49
  <br><sub>On a phone: the same conversations, installable as an app.</sub>
50
50
  </td>
51
51
  <td width="58%" valign="top">
52
- <a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-agents.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.17" alt="Background subagents running in parallel in the task panel, each with live token counts, elapsed time, and its own Stop button"></picture></a>
52
+ <a href="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-agents.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/cfmail-agents.png?v=0.9.19" alt="Background subagents running in parallel in the task panel, each with live token counts, elapsed time, and its own Stop button"></picture></a>
53
53
  <br><sub>Agents working in parallel, each with live token counts and its own Stop.</sub>
54
54
  </td>
55
55
  </tr>
56
56
  <tr>
57
57
  <td valign="top">
58
- <a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-question.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.17" alt="A question card in the middle of a turn: the agent offers several choices and a free-text reply"></picture></a>
58
+ <a href="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-question.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/cfmail-question.png?v=0.9.19" alt="A question card in the middle of a turn: the agent offers several choices and a free-text reply"></picture></a>
59
59
  <br><sub>When the agent needs a decision, it asks, and waits for your answer.</sub>
60
60
  </td>
61
61
  </tr>
62
62
  <tr>
63
63
  <td valign="top">
64
- <a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pingcf-thoughts.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.17" alt="An expanded Thoughts block showing the agent's reasoning above its reply"></picture></a>
64
+ <a href="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pingcf-thoughts.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/pingcf-thoughts.png?v=0.9.19" alt="An expanded Thoughts block showing the agent's reasoning above its reply"></picture></a>
65
65
  <br><sub>Read the reasoning, not just the answer.</sub>
66
66
  </td>
67
67
  </tr>
68
68
  <tr>
69
69
  <td valign="top">
70
- <a href="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pagewright-watching.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.17" alt="A session watching two other sessions: a finished reply arrives as a compact relay-event row, the watching 2 sessions list is open with Unsubscribe, and a request to also watch a session on a paired relay waits on an Allow / Deny card"></picture></a>
70
+ <a href="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pagewright-watching.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/pagewright-watching.png?v=0.9.19" alt="A session watching two other sessions: a finished reply arrives as a compact relay-event row, the watching 2 sessions list is open with Unsubscribe, and a request to also watch a session on a paired relay waits on an Allow / Deny card"></picture></a>
71
71
  <br><sub>Agents that watch agents: woken by events, approving nothing.</sub>
72
72
  </td>
73
73
  </tr>
@@ -102,6 +102,7 @@ The runtime (the *provider* in the UI) is chosen in **New Chat** and stays fixed
102
102
  | [**OpenAI (BYOK)**](docs/providers.md#openai-byok-and-openai-image) | Copilot's agent against OpenAI or a compatible endpoint | Your own API key |
103
103
  | [**OpenAI Image**](docs/providers.md#openai-byok-and-openai-image) | A chat whose replies are images | The same key |
104
104
  | [**Claude**](docs/providers.md#claude-agent-sdk) | Claude Code on your machine | A Claude login, made from **⚙️ Settings** |
105
+ | [**Claude API**](docs/providers.md#claude-api) | Claude Code on your machine, billed to a Claude Console API key; a Claude chat can switch between the two | A Claude Console API key |
105
106
  | [**Claude Cloud**](docs/providers.md#claude-cloud) (experimental) | Claude Code in a sandbox at Anthropic, on a GitHub repository | A claude.ai account with GitHub connected |
106
107
  | [**Cursor**](docs/providers.md#cursor-agent-sdk) | Cursor's agent | A Cursor API key |
107
108
  | [**Grok**](docs/providers.md#grok-cli-acp) | xAI's Grok CLI | A Grok sign-in, made from **⚙️ Settings** |
@@ -117,11 +118,11 @@ API keys are entered in **⚙️ Settings** and stay on the relay host. The Clau
117
118
  <table>
118
119
  <tr>
119
120
  <td width="62%" valign="top">
120
- <a href="https://oar.sh/assets/shots/cfmail-steering.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-steering.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/cfmail-steering.png?v=0.9.17" alt="A running Claude turn with a message steered into it mid-turn, the reply streaming with its tool calls, and the Steer button in the composer"></picture></a>
121
+ <a href="https://oar.sh/assets/shots/cfmail-steering.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/cfmail-steering.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/cfmail-steering.png?v=0.9.19" alt="A running Claude turn with a message steered into it mid-turn, the reply streaming with its tool calls, and the Steer button in the composer"></picture></a>
121
122
  <br><sub>Send a message while the agent works, and it steers the running turn.</sub>
122
123
  </td>
123
124
  <td width="38%" valign="top">
124
- <a href="https://oar.sh/assets/shots/usage-copilot-compact.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/usage-copilot-compact.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/usage-copilot-compact.png?v=0.9.17" alt="The GitHub Copilot card in Check Usage: premium requests and plan quota with reset dates, and the cost of the last turn"></picture></a>
125
+ <a href="https://oar.sh/assets/shots/usage-copilot-compact.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/usage-copilot-compact.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/usage-copilot-compact.png?v=0.9.19" alt="The GitHub Copilot card in Check Usage: premium requests and plan quota with reset dates, and the cost of the last turn"></picture></a>
125
126
  <br><sub>What each plan has left, in one place.</sub>
126
127
  </td>
127
128
  </tr>
@@ -133,12 +134,12 @@ API keys are entered in **⚙️ Settings** and stay on the relay host. The Clau
133
134
  - **Background work**: a task panel lists the commands and sub-agents that outlive a reply, each with its own **Stop** and its full record; a command's console shows its output live, says when it has gone quiet and counts a test run's passes and failures; the panel and its consoles come back after a relay restart, and a queued restart shows what it waits for and asks after a maximum wait ([Background tasks](docs/web-ui.md#background-tasks), [After a relay restart](docs/web-ui.md#after-a-relay-restart)).
134
135
  - **Choose how the agent works**: `ask`, `plan`, `agent` or `autopilot`, plus model and reasoning effort, per message ([Relay modes](docs/web-ui.md#relay-modes)).
135
136
  - **Files and git**: browse the workspace, preview files, review git changes in a diff viewer, and publish a dev server as a preview link ([Files, git, and previews](docs/web-ui.md#files-git-and-previews), [preview servers](docs/preview-servers.md)).
136
- - **Usage and context**: plan limits and credits of every provider, and what fills the model's context window ([Usage and context](docs/web-ui.md#usage-and-context)).
137
+ - **Usage and context**: plan limits and credits of every provider, the estimated spend of DeepSeek and Claude API keys, and what fills the model's context window ([Usage and context](docs/web-ui.md#usage-and-context)).
137
138
  - **Your conversations everywhere**: the history lives on the relay, drafts follow you from device to device, and conversations can be searched, archived, grouped and pinned ([The conversation list](docs/web-ui.md#the-conversation-list), [drafts](docs/web-ui.md#drafts-across-devices), [session groups](docs/web-ui.md#session-groups), [pins](docs/web-ui.md#pinned-messages)).
138
139
  - **Share** a conversation as a read-only link, hide single messages and the host's paths from it, and see when it was opened ([Sharing](docs/web-ui.md#sharing)).
139
140
  - **On your phone**: install OAR as an app and get push notifications ([Notifications and the app](docs/web-ui.md#notifications-and-the-app)).
140
141
 
141
- The full tour is in [Using the web UI](docs/web-ui.md); every setting and config key is in [Settings and configuration](docs/configuration.md). What changed in each release is in the [changelog](CHANGELOG.md), with [0.9.17](CHANGELOG.md#0917--2026-10-25) as the latest.
142
+ The full tour is in [Using the web UI](docs/web-ui.md); every setting and config key is in [Settings and configuration](docs/configuration.md). What changed in each release is in the [changelog](CHANGELOG.md), with [0.9.19](CHANGELOG.md#0919--2026-10-27) as the latest.
142
143
 
143
144
  ## Remote access
144
145
 
@@ -189,7 +190,7 @@ flowchart LR
189
190
 
190
191
  You stay in charge: per paired relay you decide whether agents may only read, also prompt, or do everything, and in the `ask` and `plan` modes every write asks you first. A subscription only notifies; it approves nothing.
191
192
 
192
- <p><a href="https://oar.sh/assets/shots/pagewright-cross-relay.png?v=0.9.17"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pagewright-cross-relay.light.png?v=0.9.17"><img src="https://oar.sh/assets/shots/pagewright-cross-relay.png?v=0.9.17" alt="A session watching two sessions on a paired relay: a reply arrives as a relay-event row, and after a short outage the events the other relay kept arrive as one replayed row" width="720"></picture></a></p>
193
+ <p><a href="https://oar.sh/assets/shots/pagewright-cross-relay.png?v=0.9.19"><picture><source media="(prefers-color-scheme: light)" srcset="https://oar.sh/assets/shots/pagewright-cross-relay.light.png?v=0.9.19"><img src="https://oar.sh/assets/shots/pagewright-cross-relay.png?v=0.9.19" alt="A session watching two sessions on a paired relay: a reply arrives as a relay-event row, and after a short outage the events the other relay kept arrive as one replayed row" width="720"></picture></a></p>
193
194
 
194
195
  How pairing, permissions and limits work is in [Agents working together](docs/agents-together.md).
195
196
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oar-sh/oar",
3
- "version": "0.9.17",
3
+ "version": "0.9.19",
4
4
  "type": "module",
5
5
  "description": "OAR — Open Agent Relay: drive your local coding agents from any browser",
6
6
  "license": "MIT",