@bubblebrain-ai/bubble 0.0.53 → 0.0.55

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 (34) hide show
  1. package/README.md +43 -0
  2. package/dist/agent/input-controller.d.ts +3 -0
  3. package/dist/agent/input-controller.js +13 -0
  4. package/dist/agent.js +7 -1
  5. package/dist/model-catalog.js +7 -2
  6. package/dist/model-pricing.d.ts +1 -5
  7. package/dist/model-pricing.js +0 -0
  8. package/dist/provider-ai-sdk.js +5 -0
  9. package/dist/provider-registry.js +34 -10
  10. package/dist/sdk/index.d.ts +97 -6
  11. package/dist/sdk/index.js +445 -34
  12. package/dist/sdk/replay-event-log.d.ts +19 -0
  13. package/dist/sdk/replay-event-log.js +72 -0
  14. package/dist/sdk/session-turn-coordinator.d.ts +45 -0
  15. package/dist/sdk/session-turn-coordinator.js +227 -0
  16. package/dist/tui/app.js +5 -3
  17. package/dist/tui/controller/controller.js +12 -6
  18. package/dist/tui/fullscreen.js +2 -1
  19. package/dist/types.d.ts +11 -1
  20. package/dist/update/index.d.ts +1 -0
  21. package/dist/update/index.js +22 -17
  22. package/package.json +5 -3
  23. /package/{packages/pi-tui/node_modules → node_modules}/marked/LICENSE +0 -0
  24. /package/{packages/pi-tui/node_modules → node_modules}/marked/README.md +0 -0
  25. /package/{packages/pi-tui/node_modules → node_modules}/marked/bin/main.js +0 -0
  26. /package/{packages/pi-tui/node_modules → node_modules}/marked/bin/marked.js +0 -0
  27. /package/{packages/pi-tui/node_modules → node_modules}/marked/lib/marked.d.ts +0 -0
  28. /package/{packages/pi-tui/node_modules → node_modules}/marked/lib/marked.esm.js +0 -0
  29. /package/{packages/pi-tui/node_modules → node_modules}/marked/lib/marked.esm.js.map +0 -0
  30. /package/{packages/pi-tui/node_modules → node_modules}/marked/lib/marked.umd.js +0 -0
  31. /package/{packages/pi-tui/node_modules → node_modules}/marked/lib/marked.umd.js.map +0 -0
  32. /package/{packages/pi-tui/node_modules → node_modules}/marked/man/marked.1 +0 -0
  33. /package/{packages/pi-tui/node_modules → node_modules}/marked/man/marked.1.md +0 -0
  34. /package/{packages/pi-tui/node_modules → node_modules}/marked/package.json +0 -0
package/README.md CHANGED
@@ -67,6 +67,49 @@ Resume your last conversation:
67
67
  bubble --resume
68
68
  ```
69
69
 
70
+ ## Embed with the SDK
71
+
72
+ The npm package exports `BubbleSdk` from both `@bubblebrain-ai/bubble` and
73
+ `@bubblebrain-ai/bubble/sdk`. Turns are serialized FIFO within one session and
74
+ remain parallel across different sessions.
75
+
76
+ ```ts
77
+ import { BubbleSdk } from "@bubblebrain-ai/bubble/sdk";
78
+
79
+ const sdk = new BubbleSdk({ defaultCwd: process.cwd() });
80
+ const session = sdk.createSession();
81
+ const events = sdk.runTurn(session.id, { prompt: "Inspect this project" });
82
+
83
+ for await (const event of events) {
84
+ if (event.type === "text_delta") process.stdout.write(event.content);
85
+ }
86
+
87
+ const queued = sdk.enqueueTurn(session.id, { prompt: "Run the tests next" });
88
+ void (async () => {
89
+ for await (const event of queued) {
90
+ // Render the queued turn's events.
91
+ }
92
+ })();
93
+ ```
94
+
95
+ While a turn owns the session slot, `sdk.steer(session.id, text)` adds text at
96
+ the next model-call boundary and returns a receipt: `steered` (injected into
97
+ the active turn), `queued` (the session is idle or the active turn can no
98
+ longer accept input, so the text becomes the next FIFO turn automatically),
99
+ or `rejected`. Every accepted receipt includes an `outcome` promise that
100
+ settles exactly once to `input_applied`, `input_queued`, or `input_rejected` —
101
+ even if the host drops the event iterator early.
102
+
103
+ Turns are driven by the SDK itself, not by iterator consumption: a returned
104
+ iterator is a replay subscription, so dropping it never stalls or cancels the
105
+ turn. `openSession(sessionId)` returns a durable handle whose `events` iterable
106
+ replays the whole session log from sequence 1 and `eventsFrom(n)` resumes after
107
+ the last sequence the host durably processed. `stop(sessionId)` is
108
+ Claude-style: it interrupts the active turn and keeps the queue; pass
109
+ `{ cancelQueued: true }` to clear both. `clearQueue(sessionId)` cancels only
110
+ queued turns, and `deleteSession(sessionId)` awaits teardown before the JSONL
111
+ file is removed.
112
+
70
113
  ## Model providers
71
114
 
72
115
  Bubble ships with a catalog of built-in providers. Configure them inside the app — no environment variables required.
@@ -3,9 +3,12 @@ export declare class AgentRunInputQueue implements AgentInputController {
3
3
  private readonly idPrefix;
4
4
  private pending;
5
5
  private nextInputId;
6
+ private accepting;
6
7
  constructor(idPrefix?: string);
7
8
  enqueue(content: string): AgentRunInput;
9
+ tryEnqueue(content: string): AgentRunInput | undefined;
8
10
  drainPendingInputs(): AgentRunInput[];
9
11
  pendingInputCount(): number;
10
12
  clear(): AgentRunInput[];
13
+ closePendingInputs(): AgentRunInput[];
11
14
  }
@@ -2,10 +2,19 @@ export class AgentRunInputQueue {
2
2
  idPrefix;
3
3
  pending = [];
4
4
  nextInputId = 0;
5
+ accepting = true;
5
6
  constructor(idPrefix = "input") {
6
7
  this.idPrefix = idPrefix;
7
8
  }
8
9
  enqueue(content) {
10
+ const input = this.tryEnqueue(content);
11
+ if (!input)
12
+ throw new Error("Agent input queue is closed");
13
+ return input;
14
+ }
15
+ tryEnqueue(content) {
16
+ if (!this.accepting)
17
+ return undefined;
9
18
  const input = {
10
19
  id: `${this.idPrefix}-${++this.nextInputId}`,
11
20
  content,
@@ -27,4 +36,8 @@ export class AgentRunInputQueue {
27
36
  clear() {
28
37
  return this.drainPendingInputs();
29
38
  }
39
+ closePendingInputs() {
40
+ this.accepting = false;
41
+ return this.drainPendingInputs();
42
+ }
30
43
  }
package/dist/agent.js CHANGED
@@ -644,7 +644,11 @@ export class Agent {
644
644
  return events;
645
645
  };
646
646
  const rejectPendingInputs = async (reason) => {
647
- const pendingInputs = inputController?.drainPendingInputs() ?? [];
647
+ // Seal before the first await. A host can submit in reaction to the final
648
+ // turn boundary; accepting after this drain would orphan that input.
649
+ const pendingInputs = inputController?.closePendingInputs?.()
650
+ ?? inputController?.drainPendingInputs()
651
+ ?? [];
648
652
  if (pendingInputs.length === 0)
649
653
  return [];
650
654
  const events = [];
@@ -697,6 +701,8 @@ export class Agent {
697
701
  yield emit({ type: "turn_start" });
698
702
  yield emit({ type: "text_delta", content: message });
699
703
  yield emit({ type: "turn_end", willContinue: false });
704
+ for (const event of await rejectPendingInputs("no_continuation"))
705
+ yield emit(event);
700
706
  yield emit({ type: "agent_end" });
701
707
  return;
702
708
  }
@@ -87,6 +87,9 @@ const ANTHROPIC_CHAT_LEVELS = ["off"];
87
87
  const GROK_45_LEVELS = ["low", "medium", "high"];
88
88
  const GEMINI_3_LEVELS = ["low", "medium", "high"];
89
89
  const GEMINI_3_FLASH_LEVELS = ["minimal", "low", "medium", "high"];
90
+ // Verified against the native API on 2026-09-02: Gemini 3.7/3.8 Flash reject
91
+ // thinkingLevel=minimal but accept thinkingBudget=0 plus low/medium/high.
92
+ const GEMINI_37_38_FLASH_LEVELS = ["off", "low", "medium", "high"];
90
93
  const GEMINI_25_PRO_LEVELS = ["low", "medium", "high"];
91
94
  const GEMINI_25_FLASH_LEVELS = ["off", "low", "medium", "high"];
92
95
  export const BUILTIN_MODELS = [
@@ -126,8 +129,10 @@ export const BUILTIN_MODELS = [
126
129
  { id: "deepseek-v4-pro", name: "deepseek-v4-pro", providerId: "deepseek", tier: "strong", reasoningLevels: DEEPSEEK_V4_LEVELS, defaultReasoningLevel: "high", contextWindow: 1048576 },
127
130
  // Offline/no-key fallback only: with an API key the registry replaces this
128
131
  // list via fetchGeminiModels (GET /v1beta/models, newest five). Gemini 3
129
- // exposes thinking_level (minimal/low/medium/high); 2.5 Pro cannot disable
130
- // thinking (no "off"), 2.5 Flash can (thinkingBudget 0).
132
+ // thinking support varies by release: 3.7/3.8 Flash support off/low/medium/high
133
+ // while older Flash releases expose minimal/low/medium/high.
134
+ { id: "gemini-3.8-flash", name: "Gemini 3.8 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_37_38_FLASH_LEVELS, contextWindow: 1048576 },
135
+ { id: "gemini-3.7-flash", name: "Gemini 3.7 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_37_38_FLASH_LEVELS, contextWindow: 1048576 },
131
136
  { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_3_FLASH_LEVELS, contextWindow: 1048576 },
132
137
  { id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro", providerId: "google", tier: "strong", reasoningLevels: GEMINI_3_LEVELS, defaultReasoningLevel: "high", contextWindow: 1048576 },
133
138
  { id: "gemini-3-flash-preview", name: "Gemini 3 Flash", providerId: "google", tier: "fast", reasoningLevels: GEMINI_3_FLASH_LEVELS, contextWindow: 1048576 },
@@ -35,11 +35,7 @@ export interface ModelPricing extends ModelPricingRate {
35
35
  /** Rate used before `effectiveFrom` (for historical session statistics). */
36
36
  prior?: ModelPricingRate;
37
37
  effectiveUntil?: string;
38
- original?: {
39
- inputCacheHitPerMillion: number;
40
- inputCacheMissPerMillion: number;
41
- outputPerMillion: number;
42
- };
38
+ original?: ModelPricingRate;
43
39
  }
44
40
  /**
45
41
  * Hand-maintained corrections layered over the generated models.dev snapshot.
Binary file
@@ -509,6 +509,11 @@ export function selectLatestGeminiModels(entries, limit = 5) {
509
509
  export function geminiReasoningLevels(modelId) {
510
510
  const version = Number.parseFloat(/^gemini-(\d+(?:\.\d+)?)/.exec(modelId)?.[1] ?? "0");
511
511
  const isPro = modelId.includes("-pro");
512
+ // Live probes show 3.7 and 3.8 Flash share this newer ladder. Keep the
513
+ // exception bounded to verified releases instead of guessing for 3.9+.
514
+ if (!isPro && (version === 3.7 || version === 3.8)) {
515
+ return ["off", "low", "medium", "high"];
516
+ }
512
517
  if (version >= 3) {
513
518
  return isPro ? ["low", "medium", "high"] : ["minimal", "low", "medium", "high"];
514
519
  }
@@ -11,7 +11,7 @@ import { getBubbleHome } from "./bubble-home.js";
11
11
  import { BUILTIN_PROVIDERS as CATALOG_PROVIDERS, clearDynamicModelMetadata, getBuiltinModel, getBuiltinProvider, inferGrokModelMetadata, listBuiltinModels, replaceDynamicModelMetadata, } from "./model-catalog.js";
12
12
  import { ModelConfig } from "./model-config.js";
13
13
  import { AuthStorage } from "./oauth/index.js";
14
- import { fetchGeminiModels } from "./provider-ai-sdk.js";
14
+ import { fetchGeminiModels, geminiReasoningLevels } from "./provider-ai-sdk.js";
15
15
  import { extractChatGptAccountId, fetchOpenAICodexModelCatalog } from "./provider-openai-codex.js";
16
16
  import { fetchGrokSubscriptionModels } from "./provider-grok.js";
17
17
  import { refreshOpenAICodex } from "./oauth/openai-codex.js";
@@ -169,18 +169,23 @@ export class ProviderRegistry {
169
169
  continue;
170
170
  if (!entry.result || !Array.isArray(entry.result.models))
171
171
  continue;
172
+ const provider = { id: entry.providerId ?? "", authType: entry.authType, protocol: entry.protocol };
173
+ // Capability fields may have been derived by an older Bubble build.
174
+ // Recompute them with the current code while retaining cached remote
175
+ // membership, display names and context windows.
176
+ const result = normalizeProviderDiscoveryMetadata(provider, entry.result);
172
177
  this.modelDiscoveryCache.set(key, {
173
- result: entry.result,
178
+ result,
174
179
  expiresAt: entry.expiresAt,
175
180
  identityKey: entry.identityKey ?? "unknown",
176
- providerId: entry.providerId ?? "",
181
+ providerId: provider.id,
177
182
  authType: entry.authType,
178
183
  protocol: entry.protocol,
179
184
  });
180
185
  // Rebuild the dynamic overlay so context window / reasoning levels
181
186
  // resolve from the cached catalog at startup, not only on /model open.
182
187
  if (entry.providerId) {
183
- this.applyDynamicDiscoveryMetadata({ id: entry.providerId, authType: entry.authType, protocol: entry.protocol }, entry.result);
188
+ this.applyDynamicDiscoveryMetadata(provider, result);
184
189
  }
185
190
  }
186
191
  }
@@ -513,6 +518,8 @@ export class ProviderRegistry {
513
518
  if (!options.forceRefresh) {
514
519
  const cached = this.modelDiscoveryCache.get(key);
515
520
  if (cached && cached.expiresAt > now) {
521
+ const cachedResult = normalizeProviderDiscoveryMetadata(provider, cached.result);
522
+ cached.result = cachedResult;
516
523
  // A disk cache can outlive the application version that wrote it. Keep
517
524
  // the current curated catalog authoritative over stale cached metadata,
518
525
  // then retain cached remote-only ids for non-authoritative union results.
@@ -520,12 +527,12 @@ export class ProviderRegistry {
520
527
  // without waiting up to 24 hours or requiring a manual Ctrl+R refresh.
521
528
  const local = this.localModelsForProvider(provider);
522
529
  const localIds = new Set(local.map((model) => model.id));
523
- const models = cached.result.source === "static"
530
+ const models = cachedResult.source === "static"
524
531
  ? local
525
- : cached.result.authoritative
526
- ? cached.result.models
527
- : [...local, ...cached.result.models.filter((model) => !localIds.has(model.id))];
528
- const result = { ...cached.result, models, source: "cache" };
532
+ : cachedResult.authoritative
533
+ ? cachedResult.models
534
+ : [...local, ...cachedResult.models.filter((model) => !localIds.has(model.id))];
535
+ const result = { ...cachedResult, models, source: "cache" };
529
536
  const current = this.getConfigured().find((item) => item.id === provider.id);
530
537
  if (!current || this.modelDiscoveryKey(current) === key) {
531
538
  this.applyDynamicDiscoveryMetadata(provider, result);
@@ -544,7 +551,8 @@ export class ProviderRegistry {
544
551
  const generation = (this.modelDiscoveryGeneration.get(provider.id) ?? 0) + 1;
545
552
  this.modelDiscoveryGeneration.set(provider.id, generation);
546
553
  let pending;
547
- pending = this.performModelDiscovery(provider).then((result) => {
554
+ pending = this.performModelDiscovery(provider).then((rawResult) => {
555
+ const result = normalizeProviderDiscoveryMetadata(provider, rawResult);
548
556
  if (!this.isCurrentModelDiscovery(provider, key, generation)) {
549
557
  return {
550
558
  models: this.localModelsForProvider(this.getConfigured().find((item) => item.id === provider.id) ?? provider),
@@ -879,6 +887,22 @@ export class ProviderRegistry {
879
887
  })));
880
888
  }
881
889
  }
890
+ /**
891
+ * Remote Gemini discovery does not expose Bubble's reasoning ladder; that
892
+ * metadata is inferred locally. Never trust a persisted inference across app
893
+ * upgrades, or a corrected capability matrix can remain stale for the cache
894
+ * TTL after restart.
895
+ */
896
+ function normalizeProviderDiscoveryMetadata(provider, result) {
897
+ if (provider.id !== "google" || provider.protocol !== "ai-sdk")
898
+ return result;
899
+ return {
900
+ ...result,
901
+ models: result.models.map((model) => model.id.startsWith("gemini-")
902
+ ? { ...model, reasoningLevels: geminiReasoningLevels(model.id) }
903
+ : model),
904
+ };
905
+ }
882
906
  function modelDiscoveryError(error) {
883
907
  if (error instanceof Error && error.message.trim())
884
908
  return error.message;
@@ -21,7 +21,7 @@ import type { ResolvedSubagentRoute } from "../agent/categories.js";
21
21
  import { type QuestionAnswer, type QuestionRequest } from "../question/controller.js";
22
22
  import { SkillRegistry } from "../skills/registry.js";
23
23
  import type { SkillSummary } from "../skills/types.js";
24
- import type { AgentEvent, ContentPart, Message, PermissionMode, Provider, ThinkingLevel } from "../types.js";
24
+ import type { AgentEvent, AgentRunInput, ContentPart, Message, PermissionMode, Provider, ThinkingLevel } from "../types.js";
25
25
  export interface BubbleSdkOptions {
26
26
  /** Fallback working directory for sessions created without an explicit cwd. */
27
27
  defaultCwd?: string;
@@ -81,6 +81,62 @@ export interface SdkSessionRef {
81
81
  id: string;
82
82
  cwd: string;
83
83
  }
84
+ export interface SdkSessionRunState {
85
+ /** A turn owns the session slot, including setup and teardown. */
86
+ active: boolean;
87
+ queuedTurns: number;
88
+ pendingSteers: number;
89
+ phase: "idle" | "reserved" | "starting" | "active" | "stopping" | "deleted";
90
+ }
91
+ export type SdkSteerOutcome = Extract<AgentEvent, {
92
+ type: "input_applied" | "input_queued" | "input_rejected";
93
+ }>;
94
+ export type SdkSteerResult = {
95
+ accepted: true;
96
+ disposition: "steered";
97
+ input: AgentRunInput;
98
+ outcome: Promise<SdkSteerOutcome>;
99
+ } | {
100
+ accepted: true;
101
+ disposition: "queued";
102
+ input: AgentRunInput;
103
+ turnId: string;
104
+ outcome: Promise<SdkSteerOutcome>;
105
+ } | {
106
+ accepted: false;
107
+ disposition: "rejected";
108
+ reason: "unknown_session" | "session_deleted" | "ownership_conflict";
109
+ };
110
+ export interface SdkSessionEvent {
111
+ sequence: number;
112
+ sessionId: string;
113
+ turnId: string;
114
+ event: AgentEvent;
115
+ /**
116
+ * Present only on the synthesized record that ends a turn abnormally.
117
+ * Replay subscribers use it to tell "turn failed" from "turn still running";
118
+ * the per-turn runTurn() iterator instead surfaces the thrown error.
119
+ */
120
+ terminal?: SdkSessionTerminal;
121
+ }
122
+ export interface SdkSessionTerminal {
123
+ kind: "failed" | "cancelled";
124
+ message: string;
125
+ }
126
+ export interface SdkStopOptions {
127
+ /** Match Claude-style interruption: queued messages survive by default. */
128
+ cancelQueued?: boolean;
129
+ }
130
+ export interface SdkSessionHandle extends SdkSessionRef {
131
+ /** Events from every turn in this session. Opening another handle reconnects from sequence 1. */
132
+ readonly events: AsyncIterable<SdkSessionEvent>;
133
+ /** Reconnect after the last sequence the host durably processed. */
134
+ eventsFrom(afterSequence: number): AsyncIterable<SdkSessionEvent>;
135
+ send(options: RunTurnOptions): AsyncGenerator<AgentEvent>;
136
+ steer(content: string): SdkSteerResult;
137
+ stop(options?: SdkStopOptions): number;
138
+ close(): void;
139
+ }
84
140
  export declare class BubbleSdk {
85
141
  readonly userConfig: UserConfig;
86
142
  readonly registry: ProviderRegistry;
@@ -88,8 +144,13 @@ export declare class BubbleSdk {
88
144
  private readonly mcpEnabled;
89
145
  private readonly cwdBySession;
90
146
  private readonly bashAllowlists;
91
- private readonly activeTurns;
147
+ private readonly turnCoordinator;
148
+ private readonly turnRuntimes;
149
+ private readonly lastTurnOptions;
92
150
  private readonly mcpToolsByCwd;
151
+ private readonly inputIdNonce;
152
+ private nextTurnInputPrefix;
153
+ private nextDetachedInputId;
93
154
  /** id -> {cwd,file} rebuilt from disk so sessions survive host restarts. */
94
155
  private sessionIndex;
95
156
  constructor(options?: BubbleSdkOptions);
@@ -98,10 +159,21 @@ export declare class BubbleSdk {
98
159
  cwd?: string;
99
160
  id?: string;
100
161
  }): SdkSessionRef;
162
+ openSession(sessionId: string): SdkSessionHandle;
101
163
  getHistory(sessionId: string): Message[];
102
- deleteSession(sessionId: string): void;
103
- /** Abort the in-flight turn of a session, if any. */
104
- stop(sessionId: string): void;
164
+ deleteSession(sessionId: string): Promise<void>;
165
+ /** Interrupt the active turn. Queued turns survive unless cancelQueued is true. */
166
+ stop(sessionId: string, options?: SdkStopOptions): number;
167
+ /** Cancel queued turns without interrupting the turn that owns the session slot. */
168
+ clearQueue(sessionId: string): number;
169
+ getSessionRunState(sessionId: string): SdkSessionRunState;
170
+ /**
171
+ * Add text to the turn that currently owns the session slot. Every accepted
172
+ * input exposes an outcome promise, independent of event-stream consumption.
173
+ */
174
+ steer(sessionId: string, content: string): SdkSteerResult;
175
+ enqueueTurn(sessionId: string, options: RunTurnOptions): AsyncGenerator<AgentEvent>;
176
+ queueTurn(sessionId: string, options: RunTurnOptions): AsyncGenerator<AgentEvent>;
105
177
  listSkills(cwd?: string): SkillSummary[];
106
178
  /** Configured providers + default model, for a host's model picker. */
107
179
  getModelConfig(): {
@@ -113,7 +185,25 @@ export declare class BubbleSdk {
113
185
  hasApiKey: boolean;
114
186
  }>;
115
187
  };
188
+ /**
189
+ * Reserve and start a session turn immediately. Execution is driven by the
190
+ * SDK's own pump, not by consumption of the returned iterator: the iterator
191
+ * is a replay subscription, so a host may drop it (or reconnect later via
192
+ * `openSession`) without stalling or cancelling the turn. Cancel with
193
+ * `stop()`, the options signal, or `deleteSession()`.
194
+ */
116
195
  runTurn(sessionId: string, options: RunTurnOptions): AsyncGenerator<AgentEvent>;
196
+ private startOwnedTurn;
197
+ private pumpTurn;
198
+ private runReservedTurn;
199
+ private runtimesForSession;
200
+ private settleSteerFromEvent;
201
+ private handleSteerEvent;
202
+ private rejectOutstandingSteers;
203
+ private queuePendingSteer;
204
+ private queueDetachedInput;
205
+ private publishSessionEvent;
206
+ private ownerForSession;
117
207
  private bashAllowlistFor;
118
208
  /**
119
209
  * Default cross-provider subagent factory over this SDK instance's own
@@ -141,6 +231,7 @@ export declare function attachTurnCost(event: AgentEvent, providerId: string, mo
141
231
  */
142
232
  export declare function rewriteSkillInvocationPrompt(prompt: string | ContentPart[], registry: SkillRegistry): string | ContentPart[];
143
233
  export { Agent, AgentAbortError, type AgentOptions, type AgentRunOptions } from "../agent.js";
234
+ export { AgentRunInputQueue } from "../agent/input-controller.js";
144
235
  export { SessionManager, getSessionsDir, type SessionSummary, type UserTurn, type RewindResult, } from "../session.js";
145
236
  export { PermissionAwareApprovalController } from "../approval/controller.js";
146
237
  export { BashAllowlist } from "../approval/session-cache.js";
@@ -164,4 +255,4 @@ export { ExternalHookController } from "../hooks/controller.js";
164
255
  export { calculateUsageCost, getModelPricing, type ModelPricing, type PricingCurrency, } from "../model-pricing.js";
165
256
  export { registry as slashCommandRegistry } from "../slash-commands/index.js";
166
257
  export type { SlashCommandContext } from "../slash-commands/types.js";
167
- export type { AgentEvent, ContentPart, Message, PermissionMode, Provider, ThinkingLevel, TokenUsage, UsageCost, ToolRegistryEntry, ToolResult, ToolUpdate, } from "../types.js";
258
+ export type { AgentEvent, AgentInputController, AgentRunInput, ContentPart, Message, PermissionMode, Provider, ThinkingLevel, TokenUsage, UsageCost, ToolRegistryEntry, ToolResult, ToolUpdate, } from "../types.js";