@workerdeck/core 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.d.mts CHANGED
@@ -242,6 +242,26 @@ interface Runner {
242
242
  /** Resolve a pending permission request. Returns false if the id is unknown (e.g. timed out). */
243
243
  resolvePermission(requestId: string, decision: PermissionDecision): boolean;
244
244
  interrupt(): Promise<void>;
245
+ /**
246
+ * Reset the conversation in place: the session keeps its id, its watermarks
247
+ * and its place in the list, and the engine starts over with an empty
248
+ * context. Announced with a `conversation_reset` event, whose replay rules
249
+ * (see `transcriptContent` in `@workerdeck/protocol`) are what stop an
250
+ * attaching client from resurrecting the cleared rows.
251
+ *
252
+ * Optional, like every member added after `Runner` became public API: an
253
+ * out-of-tree runner that declines it declines the `clear_context` command
254
+ * with it, which is exactly what `EngineCapabilities.clearContext: false`
255
+ * tells clients to expect.
256
+ *
257
+ * **Queues behind in-flight work rather than racing it** — resolving when the
258
+ * clear has actually happened, not when it was accepted. A clear that landed
259
+ * in the middle of the turn it was clearing would be neither, and the engines
260
+ * differ in how they wait (claude hands `/clear` to a CLI that queues its own
261
+ * streamed input; codex and the provider put it on their turn chain), so the
262
+ * one thing callers may rely on is the resolution, not the mechanism.
263
+ */
264
+ clearContext?(): Promise<void>;
245
265
  setPermissionMode(mode: PermissionMode): Promise<void>;
246
266
  /** Switch the model for subsequent responses; undefined = back to the default. */
247
267
  setModel(model?: string): Promise<void>;
@@ -357,6 +377,25 @@ declare class SessionRunner implements Runner {
357
377
  /** Resolve a pending permission request. Returns false if the id is unknown (e.g. timed out). */
358
378
  resolvePermission(requestId: string, decision: PermissionDecision): boolean;
359
379
  interrupt(): Promise<void>;
380
+ /**
381
+ * Reset the conversation by sending the `/clear` the CLI already honors.
382
+ *
383
+ * Deliberately not a second mechanism: this engine's reset arrives *from the
384
+ * SDK*, and `normalizeSdkMessage` turns the CLI's report of it into the
385
+ * `conversation_reset` event (adopting the new conversation id and re-polling
386
+ * context usage on the way through). Reimplementing the clear here would give
387
+ * one engine two ways to reach the same state, and only one of them would get
388
+ * the id adoption right. So the command and the composer's `/clear` are one
389
+ * behaviour, and this method is the thin end of it.
390
+ *
391
+ * The one place it differs from the other two engines: this resolves when the
392
+ * `/clear` has been **handed to the CLI**, not when the reset has happened —
393
+ * the CLI queues its own streamed input, so waiting is its job, and there is
394
+ * no chain here to ride. The observable contract is the same (a clear sent
395
+ * mid-turn queues rather than cutting the turn short); only the moment the
396
+ * promise settles is weaker, and no caller depends on it.
397
+ */
398
+ clearContext(): Promise<void>;
360
399
  setPermissionMode(mode: PermissionMode): Promise<void>;
361
400
  /** Switch the model for subsequent responses; undefined = back to the default. */
362
401
  setModel(model?: string): Promise<void>;
@@ -399,8 +438,12 @@ declare class SessionRunner implements Runner {
399
438
  * 1. `afterSeq` — the caller already holds everything at or below it.
400
439
  * 2. `resetSeq` — transcript *content* strictly below the latest
401
440
  * `conversation_reset` is skipped, so a re-attach cannot resurrect a cleared
402
- * conversation while state events still replay. Claude's alone; the other
403
- * engines pass 0.
441
+ * conversation while state events still replay. **Every engine that can emit
442
+ * a reset must track it and pass it** — this was Claude's alone only for as
443
+ * long as Claude's was the only engine that could produce the event, and the
444
+ * failure when a runner forgets is quiet: the end state is right for a
445
+ * current reducer, so nothing looks broken while every attach re-sends the
446
+ * whole cleared conversation for the process's lifetime.
404
447
  * 3. `coalesceReplay` — last-write-wins state readings superseded later in the
405
448
  * same replay (`staleReplaySeqs`), plus everything `replayRetains` says the
406
449
  * reducer reads and discards. Opt-in, and only sound for a consumer whose
@@ -627,6 +670,20 @@ declare class AiSdkRunner implements Runner {
627
670
  * its tokens are never lost from the turn's accounting.
628
671
  */
629
672
  generateDigest(prompt: string): Promise<string>;
673
+ /**
674
+ * Reset the conversation: drop the message array the next turn would have
675
+ * been built from. There is no engine round trip — this runner *is* where the
676
+ * transcript lives, so clearing it is the whole operation.
677
+ *
678
+ * Two things ride along, both already written elsewhere and both load-bearing
679
+ * here. `#emit`'s `conversation_reset` arm retires `#contextUsage` (the
680
+ * reading described a conversation that no longer exists), and the same arm
681
+ * in `restore` keeps a parked session that comes back after a clear from
682
+ * resurrecting it. Pending tool calls are NOT swept: a parked call is work a
683
+ * backend still owes an answer for, and a clear is not an interrupt — the
684
+ * refusal below is what keeps the two apart.
685
+ */
686
+ clearContext(): Promise<void>;
630
687
  interrupt(): Promise<void>;
631
688
  setPermissionMode(mode: PermissionMode): Promise<void>;
632
689
  setModel(model?: string): Promise<void>;
@@ -1645,7 +1702,15 @@ declare const codexAdapter: EngineAdapter;
1645
1702
  * const c=JSON.parse(d.slice(s,i));
1646
1703
  * for(const m of c.models) console.log(m.slug, m.display_name,
1647
1704
  * m.visibility, m.supported_reasoning_levels.map(l=>l.effort).join(","))'\
1648
- * "$(node -p 'require.resolve("@openai/codex-darwin-arm64/package.json").replace("package.json","vendor/aarch64-apple-darwin/bin/codex")')"
1705
+ * "$(node -p 'const{createRequire}=require("module");
1706
+ * const w=require.resolve("@openai/codex/package.json");
1707
+ * createRequire(w).resolve("@openai/codex-darwin-arm64/package.json")
1708
+ * .replace("package.json","vendor/aarch64-apple-darwin/bin/codex")')"
1709
+ *
1710
+ * The two-hop resolve is NOT optional: under pnpm's strict layout the platform
1711
+ * package is a dependency of `@openai/codex`, so it resolves only from that
1712
+ * wrapper's location, never from the repo root. Resolving it directly throws
1713
+ * MODULE_NOT_FOUND — the same two hops `resolveBundledCodexExecutable` makes.
1649
1714
  *
1650
1715
  * Mapping decisions:
1651
1716
  * - the internal `codex-auto-review` row is dropped (the codex analogue of
@@ -1709,6 +1774,36 @@ declare class CodexRunner implements Runner {
1709
1774
  * timed out, or already settled by codex itself). */
1710
1775
  resolvePermission(requestId: string, decision: PermissionDecision): boolean;
1711
1776
  interrupt(): Promise<void>;
1777
+ /**
1778
+ * Reset the conversation: a **fresh thread on the same session**.
1779
+ *
1780
+ * Codex has no clear/reset RPC — `thread/compact/start` summarises and
1781
+ * continues, `thread/fork` makes a second thread, and neither is "same
1782
+ * session, empty context". So the analog is to stop resuming the old thread
1783
+ * and start a new one, which is the path a dead child already takes minus the
1784
+ * resume. The old thread is NOT deleted: it stays in CODEX_HOME and stays
1785
+ * resumable from `GET /sdk-sessions`.
1786
+ *
1787
+ * Two things it does on the way through, both mirroring the Claude engine's
1788
+ * SDK-driven reset (`engines/claude/runner.ts`):
1789
+ *
1790
+ * 1. **The new thread id is adopted before `conversation_reset` is emitted**,
1791
+ * whenever a child is already up — the eager `thread/start` costs no
1792
+ * tokens and no model call, and it is what keeps the dormant record from
1793
+ * ever naming the conversation that was just cleared. With no child there
1794
+ * is nothing to start against and the id is simply dropped; the parking
1795
+ * service treats a resumable session with no engine session id as one with
1796
+ * nothing to come back to, and forgets the stale record.
1797
+ * 2. **The context reading is retired**, in `#emit`'s `conversation_reset`
1798
+ * arm. Codex cannot re-poll it the way Claude does — the only source is
1799
+ * `thread/tokenUsage/updated`, which arrives *during* a turn — so there is
1800
+ * no reading at all until the next turn runs, and the protocol's rule
1801
+ * applies: render nothing rather than a stale ring or a 0%.
1802
+ *
1803
+ * The turn counter stays monotonic across this, on purpose (it is an unread
1804
+ * cursor, not an item count), and so does `activityCount` — `#emit` owns both.
1805
+ */
1806
+ clearContext(): Promise<void>;
1712
1807
  setPermissionMode(mode: PermissionMode): Promise<void>;
1713
1808
  setModel(model?: string): Promise<void>;
1714
1809
  fail(message: string): void;