@theoremjs/web 0.3.4-next.755.g88665bd → 0.3.4-next.759.g46e0e27

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 CHANGED
@@ -147,7 +147,7 @@ for await (const event of session.events()) {
147
147
  }
148
148
  ```
149
149
 
150
- - `prepareLiveOpen` returns validated history, slots, context, native state, and absence duration. It removes system-role history.
150
+ - `prepareLiveOpen` returns validated history, options, context, native state, and absence duration. It removes system-role history.
151
151
  - Its second argument supplies server context. Browser context stays under `client`.
152
152
  - Save checkpoint ownership before you send the event. If storage fails, close the session without advertising that checkpoint.
153
153
  - The boundary refuses native resumption while a saved operation is ready, running, or uncertain. It does not repeat the operation.
@@ -203,8 +203,8 @@ await chat.submit();
203
203
 
204
204
  - `getState()` returns a `ChatState`. It is a new object after each change, and the same object between changes. So you can compare it by reference, as React's `useSyncExternalStore` does.
205
205
  - `subscribe(listener)` calls the listener once for each group of changes, after the code that made them has run. It returns the function that unsubscribes. Until the first subscribe or send, the chat asks nothing of the host. Then it reads a resumed conversation that came without its `conversationView`, and answers a restored page gate as unanswered.
206
- - `update(options)` gives the controller your latest options, such as a new `context`, `slots`, or `pageTools`. Each turn reads the options as they are when it is sent. `conversation`, `conversationView`, `initialText`, `initialFiles`, `initialVoice`, and `initialPending` are read only when the controller is created.
207
- - A live call takes `stated` in its options, and `setStated(stated)` changes it during the call. As with `setSlots`, the call is taken up again with the prompt lines the new value chooses.
206
+ - `update(options)` gives the controller your latest options, such as a new `context`, `options`, or `pageTools`. Each turn reads the options as they are when it is sent. `conversation`, `conversationView`, `initialText`, `initialFiles`, `initialVoice`, and `initialPending` are read only when the controller is created.
207
+ - A live call takes `stated` in its options, and `setStated(stated)` changes it during the call. As with `setOptions`, the call is taken up again with the prompt lines the new value chooses.
208
208
  - Each method is bound to the controller. Pass it as a callback as it is.
209
209
 
210
210
  `state.phase` is `'idle'`, `'streaming'`, or `'gated'`. The methods for the composer depend on it:
@@ -273,7 +273,7 @@ const transport = withPageToolDispatch(
273
273
  | `notifier`, `notifyRetryMs` | Tell an open page that a background call ended, and how long the page waits to reopen a cut stream. Unset, the page reads the end on its next turn or reload. See [the background section](#share-session-authority). |
274
274
  | `credentialStore` | Where tool credentials are kept, by session. Default: process memory. |
275
275
  | `authorizationUrl` | Returns the sign-in URL for an OAuth gate. Without it, an OAuth gate has no URL. |
276
- | `gateTtlMs` | How long a gate waits for an answer. A later answer fails with `session.gate_expired`. Unset, a gate waits until it is answered. |
276
+ | `gateTtlMs` | How long a gate waits for an answer. A later answer fails with `session.gate_expired`, and the next message cancels the call. Unset, a gate waits until it is answered. |
277
277
  | `maxRequestBytes` | The largest browser request body, in bytes. Unset, a body of any size is read. |
278
278
  | `pageToolTimeoutMs` | How long the page has to answer a tool call it runs. A call it has not answered by then settles as timed out. Unset, the call waits until the page answers or the turn stops. The browser clients answer every call they get, so only a page function that never returns holds a turn. |
279
279
  | `operationRetentionMs` | How long a settled tool result is kept. Default: 24 hours. |
package/client/chat.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type ProfileOptions } from '@theoremjs/agents';
1
2
  import { type AttachmentValidationIssue, type ComposerMenuAction, type ComposerPendingMessage, type ComposerProfileInterface, type ComposerRunPhase, type InterfaceTurnSession, type TranscriptBlock } from '@theoremjs/agents/interface';
2
3
  import { type ClientFailure } from './failure.ts';
3
4
  import { type PageTools } from './live/live-page-tool.ts';
@@ -37,15 +38,15 @@ export type ChatOptions = {
37
38
  */
38
39
  onConversationChange?: (ref: string | undefined) => void;
39
40
  /**
40
- * The value chosen for each of the profile's `inputs.slots`. Sent with every turn. A slot you
41
+ * The value chosen for each of the profile's `inputs.options`. Sent with every turn. An option you
41
42
  * name here is fixed to that value; one you leave out is the visitor's to pick (the chat's
42
- * `pickSlot`), starting at its first allowed value.
43
+ * `pickOption`), starting at its first allowed value.
43
44
  */
44
- slots?: Record<string, string>;
45
+ options?: Record<string, string>;
45
46
  /** Which prompt lines each turn gets, for a host that lets its page choose (`pageStatesTurn`). */
46
47
  stated?: StatedTurn;
47
- /** Told each time the visitor picks a slot, with every slot's value. */
48
- onSlotsChange?: (slots: Record<string, string>) => void;
48
+ /** Told each time the visitor picks an option, with every option's value. */
49
+ onOptionsChange?: (options: Record<string, string>) => void;
49
50
  /** What the page wants the agent to know: any JSON. The latest value goes with every turn. */
50
51
  context?: unknown;
51
52
  /** The page's tools, by name: each answers a tool the profile declares with `answeredBy: 'page'`. */
@@ -61,17 +62,9 @@ export type ChatOptions = {
61
62
  * (`sent`), reached the model (`delivered`), answered (`read`).
62
63
  */
63
64
  export type MessageDelivery = 'sending' | 'sent' | 'delivered' | 'read';
64
- /** One declared slot as the composer shows it (group label + choices with optional blurbs). */
65
- export type ChatSlotDecl = {
66
- label?: string;
67
- choices: readonly {
68
- value: string;
69
- description?: string;
70
- }[];
71
- };
72
- /** The slots the profile declares, and the value of each: the page's, else the picked one, else the first allowed. */
73
- export type ChatSlots = {
74
- declared: Record<string, ChatSlotDecl>;
65
+ /** The options the profile declares, and the value of each: the page's, else the picked one, else the first allowed. */
66
+ export type ChatOptionPicks = {
67
+ declared: ProfileOptions;
75
68
  values: Record<string, string>;
76
69
  };
77
70
  /** Everything a chat shows. A new object on each change, the same one between changes. */
@@ -97,8 +90,8 @@ export type ChatState = {
97
90
  /** The latest message's delivery; `null` before the first and once its turn failed. */
98
91
  delivery: MessageDelivery | null;
99
92
  streaming: boolean;
100
- /** `undefined` when the profile declares no slots. */
101
- slots: ChatSlots | undefined;
93
+ /** `undefined` when the profile declares no options. */
94
+ options: ChatOptionPicks | undefined;
102
95
  };
103
96
  /** What `sendText` hands back: the blocks the turn added, its user message, and the reply. */
104
97
  export type SentTurn = {
@@ -170,7 +163,7 @@ export type ChatController = {
170
163
  modelId: string;
171
164
  effort?: string;
172
165
  }): void;
173
- pickSlot(name: string, value: string): void;
166
+ pickOption(name: string, value: string): void;
174
167
  /**
175
168
  * Sends `text`, and what `options` adds, as the composer would, and resolves once the reply is
176
169
  * done; `null` when it can't go now (a reply is streaming, or waits on a gate).
package/client/chat.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TheoremError } from '@theoremjs/agents';
1
+ import { TheoremError, } from '@theoremjs/agents';
2
2
  import { branchInterfaceTurnSession, consumeNextComposerQueue, convertSteersToFrontQueued, createComposerPendingMessage, defaultInterfaceEffort, emptyInterfaceTurnSession, moveComposerPendingWithinKind, orderComposerPendingMessages, promoteComposerPendingKind, removeComposerPendingMessage, removeLandedSteers, userDraftHasPayload, userDraftToSteerInject, } from '@theoremjs/agents/interface';
3
3
  import { composerHasPayload } from "./composer-primary.js";
4
4
  import { composerFieldsFromDraft } from "./decode-composer-draft.js";
@@ -45,8 +45,8 @@ function withTurnError(blocks, error) {
45
45
  return blocks;
46
46
  return [...blocks, { id: crypto.randomUUID(), kind: 'error', message: error }];
47
47
  }
48
- function slotsOf(iface, fixed, picked) {
49
- const declared = iface?.inputs.slots ?? {};
48
+ function picksOf(iface, fixed, picked) {
49
+ const declared = iface?.inputs.options ?? {};
50
50
  const values = { ...fixed };
51
51
  for (const [name, decl] of Object.entries(declared)) {
52
52
  const first = decl.choices[0]?.value;
@@ -57,10 +57,10 @@ function slotsOf(iface, fixed, picked) {
57
57
  const chosen = Object.keys(declared).length > 0;
58
58
  return {
59
59
  values: chosen || fixed ? values : undefined,
60
- slots: chosen ? { declared, values } : undefined,
60
+ options: chosen ? { declared, values } : undefined,
61
61
  };
62
62
  }
63
- function sameSlots(a, b) {
63
+ function samePicks(a, b) {
64
64
  if (a === undefined || b === undefined)
65
65
  return a === b;
66
66
  const keys = Object.keys(a.values);
@@ -136,7 +136,7 @@ class Chat {
136
136
  session: emptyInterfaceTurnSession(),
137
137
  delivery: null,
138
138
  streaming: false,
139
- slots: slotsOf(options.iface, options.slots, {}).slots,
139
+ options: picksOf(options.iface, options.options, {}).options,
140
140
  };
141
141
  this.#notified = this.#state;
142
142
  this.#warnPageTools();
@@ -241,12 +241,12 @@ class Chat {
241
241
  update = (options) => {
242
242
  this.#options = options;
243
243
  this.#warnPageTools();
244
- const { slots } = slotsOf(options.iface, options.slots, this.#picked);
244
+ const { options: picks } = picksOf(options.iface, options.options, this.#picked);
245
245
  const patch = {};
246
246
  if (options.iface !== this.#state.iface)
247
247
  patch.iface = options.iface;
248
- if (!sameSlots(slots, this.#state.slots))
249
- patch.slots = slots;
248
+ if (!samePicks(picks, this.#state.options))
249
+ patch.options = picks;
250
250
  if (Object.keys(patch).length > 0)
251
251
  this.#set(patch);
252
252
  };
@@ -425,11 +425,13 @@ class Chat {
425
425
  session: { ...this.#state.session, selectedModel: next.modelId, selectedEffort: effort },
426
426
  });
427
427
  };
428
- pickSlot = (name, value) => {
429
- const before = slotsOf(this.#options.iface, this.#options.slots, this.#picked).values;
428
+ pickOption = (name, value) => {
429
+ const before = picksOf(this.#options.iface, this.#options.options, this.#picked).values;
430
430
  this.#picked = { ...this.#picked, [name]: value };
431
- this.#set({ slots: slotsOf(this.#options.iface, this.#options.slots, this.#picked).slots });
432
- this.#options.onSlotsChange?.({ ...before, [name]: value });
431
+ this.#set({
432
+ options: picksOf(this.#options.iface, this.#options.options, this.#picked).options,
433
+ });
434
+ this.#options.onOptionsChange?.({ ...before, [name]: value });
433
435
  };
434
436
  sendText = async (text, options = {}) => {
435
437
  if (!this.#options.iface || this.#state.phase !== 'idle')
@@ -755,7 +757,7 @@ class Chat {
755
757
  }
756
758
  /**
757
759
  * The transport each run uses: the page's tools answer their calls, each turn carries the
758
- * page's slots and context as they are when it is sent, and each line lands the steers it
760
+ * page's options and context as they are when it is sent, and each line lands the steers it
759
761
  * reports, moves the message's delivery on, and hands the chat the conversation's new ref
760
762
  * (so a page that reloads mid-reply keeps the posted message).
761
763
  */
@@ -773,16 +775,16 @@ class Chat {
773
775
  };
774
776
  }
775
777
  #withValues(request) {
776
- const { iface, slots: fixed, context, stated } = this.#options;
777
- const slots = slotsOf(iface, fixed, this.#picked).values;
778
- if (slots === undefined && context === undefined && stated === undefined)
778
+ const { iface, options: fixed, context, stated } = this.#options;
779
+ const options = picksOf(iface, fixed, this.#picked).values;
780
+ if (options === undefined && context === undefined && stated === undefined)
779
781
  return request;
780
782
  return {
781
783
  ...request,
782
784
  ...(stated === undefined ? {} : { stated }),
783
785
  input: {
784
786
  ...request.input,
785
- ...(slots === undefined ? {} : { slots }),
787
+ ...(options === undefined ? {} : { options }),
786
788
  ...(context === undefined ? {} : { context }),
787
789
  },
788
790
  };
package/client/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export { float32Rms, float32RmsToLevel, INPUT_LEVEL_GAIN, timeDomainBytesToLevel, } from './audio-level.ts';
2
- export { type ChatController, type ChatOptions, type ChatSlotDecl, type ChatSlots, type ChatState, type ChatUpdate, createChatController, type MessageDelivery, type SendTextOptions, type SentTurn, } from './chat.ts';
2
+ export { type ChatController, type ChatOptionPicks, type ChatOptions, type ChatState, type ChatUpdate, createChatController, type MessageDelivery, type SendTextOptions, type SentTurn, } from './chat.ts';
3
3
  export { type ComposerDrawerKind, type ComposerDrawerSummary, composerDrawerSummary, } from './composer-drawer.ts';
4
4
  export { type ComposerHint, isStashShortcut, resolveComposerHint, STASH_SHORTCUT, } from './composer-hints.ts';
5
5
  export { type ComposerActionState, composerActionState, composerHasPayload, } from './composer-primary.ts';
@@ -15,8 +15,8 @@ export type PageTool = (args: Record<string, unknown>, call: {
15
15
  export type PageTools = Record<string, PageTool>;
16
16
  /** What a host gives a live call. */
17
17
  export type LiveCallOptions = {
18
- /** The value chosen for each of the profile's `inputs.slots`, read as the call starts. */
19
- slots?: Record<string, string>;
18
+ /** The value chosen for each of the profile's `inputs.options`, read as the call starts. */
19
+ options?: Record<string, string>;
20
20
  /** Which prompt lines the call gets, for a host that lets its page choose (`pageStatesTurn`). */
21
21
  stated?: StatedTurn;
22
22
  /** The model picked for the call, read as the call starts, when the profile allows it. */
@@ -22,8 +22,8 @@ export interface LiveClientOptions {
22
22
  profile?: string;
23
23
  /** The host's own JSON for its relay, sent as the open message's `host`. */
24
24
  openMessage?: Record<string, unknown>;
25
- /** The value chosen for each of the profile's `inputs.slots`, fixed for the call. */
26
- slots?: Record<string, string>;
25
+ /** The value chosen for each of the profile's `inputs.options`, fixed for the call. */
26
+ options?: Record<string, string>;
27
27
  /** Which prompt lines the call gets, for a host that lets its page choose (`pageStatesTurn`). */
28
28
  stated?: StatedTurn;
29
29
  /** The model picked for the call, when the profile allows it. */
@@ -183,11 +183,11 @@ export declare class LiveSessionClient {
183
183
  toggleMute(): boolean;
184
184
  sendText(text: string): void;
185
185
  /**
186
- * The call's slot values. An open call is taken up again with them when the provider gave a
186
+ * The call's option values. An open call is taken up again with them when the provider gave a
187
187
  * handle; with none, the next call has them.
188
188
  */
189
- setSlots(slots: Record<string, string> | undefined): void;
190
- /** The call's prompt lines, as `setSlots` takes its slots. */
189
+ setOptions(options: Record<string, string> | undefined): void;
190
+ /** The call's prompt lines, as `setOptions` takes its options. */
191
191
  setStated(stated: StatedTurn | undefined): void;
192
192
  private takeUpAgain;
193
193
  /**
@@ -228,11 +228,11 @@ export class LiveSessionClient {
228
228
  }
229
229
  /** The first message: the call's values, and the handle and time away when it takes a dropped call up again. */
230
230
  openMessage() {
231
- const { slots, stated, model, effort, openMessage: host } = this.options;
231
+ const { options, stated, model, effort, openMessage: host } = this.options;
232
232
  return {
233
233
  type: 'open',
234
234
  ...(this.history.length ? { history: structuredClone(this.history) } : {}),
235
- ...(slots ? { slots } : {}),
235
+ ...(options ? { options } : {}),
236
236
  ...(stated ? { stated } : {}),
237
237
  ...(model ? { model } : {}),
238
238
  ...(effort ? { effort } : {}),
@@ -767,16 +767,16 @@ export class LiveSessionClient {
767
767
  }
768
768
  }
769
769
  /**
770
- * The call's slot values. An open call is taken up again with them when the provider gave a
770
+ * The call's option values. An open call is taken up again with them when the provider gave a
771
771
  * handle; with none, the next call has them.
772
772
  */
773
- setSlots(slots) {
774
- if (JSON.stringify(slots) === JSON.stringify(this.options.slots))
773
+ setOptions(options) {
774
+ if (JSON.stringify(options) === JSON.stringify(this.options.options))
775
775
  return;
776
- this.options = { ...this.options, slots };
776
+ this.options = { ...this.options, options };
777
777
  this.takeUpAgain();
778
778
  }
779
- /** The call's prompt lines, as `setSlots` takes its slots. */
779
+ /** The call's prompt lines, as `setOptions` takes its options. */
780
780
  setStated(stated) {
781
781
  if (JSON.stringify(stated) === JSON.stringify(this.options.stated))
782
782
  return;
@@ -16,8 +16,8 @@ import { type MalformedEvent, type UnsupportedEvent } from './wire-line.ts';
16
16
  export type LiveOpenMessage = {
17
17
  type: 'open';
18
18
  history?: TurnHistoryMessage[];
19
- /** The value chosen for each of the profile's `inputs.slots`. */
20
- slots?: Record<string, string>;
19
+ /** The value chosen for each of the profile's `inputs.options`. */
20
+ options?: Record<string, string>;
21
21
  /** What the page tells the agent as the call opens: the client's context package. */
22
22
  context?: unknown;
23
23
  /** Which prompt lines the call gets, for a host that lets its page choose (`pageStatesTurn`). */
@@ -12,7 +12,7 @@ import { readWireLine, readWireValue, } from "./wire-line.js";
12
12
  const liveOpenMessage = z.object({
13
13
  type: z.literal('open'),
14
14
  history: z.array(turnHistoryMessageSchema).optional(),
15
- slots: z.record(z.string(), z.string()).optional(),
15
+ options: z.record(z.string(), z.string()).optional(),
16
16
  context: z.unknown().optional(),
17
17
  stated: statedTurnSchema.optional(),
18
18
  model: z.string().optional(),
@@ -27,8 +27,8 @@ export type TheoremTurnInput = {
27
27
  text?: string;
28
28
  attachments?: EncodedBlob[];
29
29
  voice?: EncodedBlob[];
30
- /** The value chosen for each of the profile's `inputs.slots`. */
31
- slots?: Record<string, string>;
30
+ /** The value chosen for each of the profile's `inputs.options`. */
31
+ options?: Record<string, string>;
32
32
  /** What the page wants the agent to know: any JSON. The host reads it as untrusted. */
33
33
  context?: unknown;
34
34
  };
@@ -49,10 +49,10 @@ export type TheoremReplay = {
49
49
  };
50
50
  /** For a host that reads the studio's client-held state. */
51
51
  export declare const theoremReplaySchema: z.ZodType<TheoremReplay>;
52
- /** Which prompt lines a turn gets: the path it says it came by, and its `identity.conditions`. */
52
+ /** Which prompt lines a turn gets: the path it says it came by, and its `identity.options`. */
53
53
  export type StatedTurn = {
54
54
  path?: string;
55
- conditions?: Record<string, string>;
55
+ options?: Record<string, string>;
56
56
  };
57
57
  /** A stated turn off the wire. */
58
58
  export declare const statedTurnSchema: z.ZodType<StatedTurn>;
@@ -17,7 +17,7 @@ import { checkWire, parseWireJson, readWireLine, } from "./wire-line.js";
17
17
  const encodedBlob = z.object({ name: z.string(), mimeType: z.string(), data: z.string() });
18
18
  true;
19
19
  const theoremTurnInput = z.object({
20
- slots: z.record(z.string(), z.string()).optional(),
20
+ options: z.record(z.string(), z.string()).optional(),
21
21
  context: z.unknown().optional(),
22
22
  text: z.string().optional(),
23
23
  attachments: z.array(encodedBlob).optional(),
@@ -41,7 +41,7 @@ export const theoremReplaySchema = theoremReplay;
41
41
  const clientId = z.string().trim().min(1);
42
42
  const statedTurn = z.object({
43
43
  path: z.string().optional(),
44
- conditions: z.record(z.string(), z.string()).optional(),
44
+ options: z.record(z.string(), z.string()).optional(),
45
45
  });
46
46
  true;
47
47
  /** A stated turn off the wire. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theoremjs/web",
3
- "version": "0.3.4-next.755.g88665bd",
3
+ "version": "0.3.4-next.759.g46e0e27",
4
4
  "description": "Theorem on the web platform, with no UI framework: Web-standard server handlers that serve a profile, and the browser client that talks to them.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,6 +25,6 @@
25
25
  },
26
26
  "peerDependencies": {
27
27
  "zod": "^4.6.5",
28
- "@theoremjs/agents": "^0.3.4-next.755.g88665bd"
28
+ "@theoremjs/agents": "^0.3.4-next.759.g46e0e27"
29
29
  }
30
30
  }
@@ -146,7 +146,7 @@ export type PostedMessage = {
146
146
  /** The message's blocks (`prepareUserTurn`), with their media inline. */
147
147
  blocks: TranscriptBlock[];
148
148
  media: UserTurnHistoryMedia;
149
- /** The kernel input without history: the message's text as the transcript shows it, its media, slots, and context. */
149
+ /** The kernel input without history: the message's text as the transcript shows it, its media, options, and context. */
150
150
  input: TurnInput;
151
151
  };
152
152
  /**
@@ -107,8 +107,8 @@ export type TheoremHandlerOptions = {
107
107
  conversationStore?: TheoremConversationStore;
108
108
  /**
109
109
  * How long a gate (permission, confirmation, sign-in) waits for its answer, in
110
- * milliseconds. An answer after that is refused with `session.gate_expired`.
111
- * Unset, a gate waits until it is answered.
110
+ * milliseconds. An answer after that is refused with `session.gate_expired`,
111
+ * and the next message cancels the call. Unset, a gate waits until it is answered.
112
112
  */
113
113
  gateTtlMs?: number;
114
114
  /** Retain settled tool results in milliseconds. Default: 24 hours. */
package/server/handler.js CHANGED
@@ -331,10 +331,16 @@ function answerPendingGate(state, request, profileId) {
331
331
  state.permissions = answer.sessionPermissions;
332
332
  return { callId: request.callId, pending, answer };
333
333
  }
334
- function walkedCallOf(state, reference, profileId) {
334
+ function walkedCallOf(state, reference, profileId, paused) {
335
335
  const settled = Object.hasOwn(state.operations, reference.operationId)
336
336
  ? state.operations[reference.operationId]
337
337
  : undefined;
338
+ // why: A gate that lapsed is gone from the session while the reply still waits on its call. The call is only ever cancelled here, so the next message is never refused for it.
339
+ if (!settled && !Object.hasOwn(state.gates, reference.operationId)) {
340
+ const lapsed = pendingGatesFrom(paused, { profileId, turnInput: {} }).find(({ callId }) => callId === reference.callId);
341
+ if (lapsed)
342
+ state.gates[reference.operationId] = lapsed.gate;
343
+ }
338
344
  return settled?.status === 'settled' &&
339
345
  settled.callId === reference.callId &&
340
346
  settled.profileId === profileId
@@ -346,11 +352,12 @@ function walkedCallOf(state, reference, profileId) {
346
352
  * answered `abandon`: every one of them, or none when one is neither waiting
347
353
  * nor settled. Each comes back with the run that settles it.
348
354
  */
349
- async function takeWalkedAway(ctx, request, session, abandon) {
355
+ async function takeWalkedAway(ctx, request, session, abandon, conversation) {
356
+ const paused = conversation.paused?.events ?? [];
350
357
  // why: A throw leaves the session unsaved, so no call is taken unless all are.
351
358
  const calls = await ctx.sessions.mutate(session.id, (state) => abandon.map((reference) => ({
352
359
  reference,
353
- call: walkedCallOf(state, reference, ctx.profile.id),
360
+ call: walkedCallOf(state, reference, ctx.profile.id, paused),
354
361
  })));
355
362
  return calls.map(({ reference, call }) => ({
356
363
  ...reference,
@@ -530,7 +537,7 @@ async function turn(ctx, chat, request, session) {
530
537
  });
531
538
  // why: Take the walked-away calls before streaming, so a stale one is a reply status, not a stream error.
532
539
  const walkAway = body.abandon
533
- ? await takeWalkedAway(ctx, request, session, body.abandon)
540
+ ? await takeWalkedAway(ctx, request, session, body.abandon, opened.conversation)
534
541
  : undefined;
535
542
  return eventStream(ctx, request, () => messageReply({ host, opened, message, ...(walkAway ? { walkAway } : {}), runner }));
536
543
  }
@@ -664,7 +671,7 @@ async function rewind(ctx, request, session) {
664
671
  const opened = await openConversation(host, body.conversation, { kind: 'rewind', at: body.at });
665
672
  const waiting = waitingCalls(opened.conversation);
666
673
  const walkAway = waiting.length
667
- ? await takeWalkedAway(ctx, request, session, waiting)
674
+ ? await takeWalkedAway(ctx, request, session, waiting, opened.conversation)
668
675
  : undefined;
669
676
  const next = await rewindConversation({
670
677
  host,
@@ -14,7 +14,7 @@ export interface SessionBoundaryOptions {
14
14
  /** How long the page has to answer a tool call it runs, in milliseconds. Unset, it waits. */
15
15
  pageToolTimeoutMs?: number;
16
16
  }
17
- export type PreparedLiveOpen = Pick<SessionRequest, 'history' | 'slots' | 'context' | 'providerState' | 'awayMs' | 'path' | 'conditions'>;
17
+ export type PreparedLiveOpen = Pick<SessionRequest, 'history' | 'inputOptions' | 'context' | 'providerState' | 'awayMs' | 'path' | 'options'>;
18
18
  export interface TheoremSessionBoundary {
19
19
  sessionId: string;
20
20
  setCookie?: string;
@@ -28,7 +28,7 @@ const blobSchema = z.strictObject({
28
28
  const inputSchema = z.strictObject({
29
29
  text: z.string().optional(),
30
30
  role: z.string().optional(),
31
- slots: z.record(z.string(), z.string()).optional(),
31
+ options: z.record(z.string(), z.string()).optional(),
32
32
  context: z
33
33
  .strictObject({ client: jsonValueSchema.optional(), server: jsonValueSchema.optional() })
34
34
  .optional(),
@@ -7,4 +7,4 @@ export declare function kernelTurnInput(input: TheoremTurnInput, server?: unknow
7
7
  * What a live call's first message asks of the session, as `runSession` takes
8
8
  * it: the page's context is the client's, and `server` is the host's own.
9
9
  */
10
- export declare function liveSessionOpen(open: LiveOpenMessage, server?: unknown): Pick<SessionRequest, 'slots' | 'context' | 'providerState' | 'awayMs' | 'history' | 'path' | 'conditions' | 'model' | 'effort'>;
10
+ export declare function liveSessionOpen(open: LiveOpenMessage, server?: unknown): Pick<SessionRequest, 'inputOptions' | 'context' | 'providerState' | 'awayMs' | 'history' | 'path' | 'options' | 'model' | 'effort'>;
@@ -20,7 +20,7 @@ export function liveSessionOpen(open, server) {
20
20
  const context = turnContext(open.context, server);
21
21
  return {
22
22
  ...(open.history ? { history: open.history } : {}),
23
- ...(open.slots ? { slots: open.slots } : {}),
23
+ ...(open.options ? { inputOptions: open.options } : {}),
24
24
  ...(context ? { context } : {}),
25
25
  ...open.stated,
26
26
  ...(open.model ? { model: open.model } : {}),