@tanstack/ai-client 0.29.0 → 0.29.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -26,6 +26,9 @@ export declare class NoOpChatDevtoolsBridge {
26
26
  resolveStreamId(): string;
27
27
  observeChunk(_chunk: StreamChunk): void;
28
28
  recordMemoryState(_value: unknown): void;
29
+ recordCompactionEvent(_eventType: string, _value: unknown): void;
30
+ recordCompactionState(_value: unknown): void;
31
+ recordSkillsState(_value: unknown): void;
29
32
  beginRun(_runId: string, _threadId: string): void;
30
33
  getCurrentRunEventContext(): ChatClientRunEventContext | undefined;
31
34
  getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined;
@@ -31,6 +31,9 @@ var NoOpChatDevtoolsBridge = class {
31
31
  }
32
32
  observeChunk(_chunk) {}
33
33
  recordMemoryState(_value) {}
34
+ recordCompactionEvent(_eventType, _value) {}
35
+ recordCompactionState(_value) {}
36
+ recordSkillsState(_value) {}
34
37
  beginRun(_runId, _threadId) {}
35
38
  getCurrentRunEventContext() {}
36
39
  getCurrentOrLastRunEventContext() {}
@@ -1 +1 @@
1
- {"version":3,"file":"devtools-noop.js","names":[],"sources":["../../src/devtools-noop.ts"],"sourcesContent":["// No-op devtools bridge implementations + factories. The chat / generation /\n// video clients import the real bridge classes as types only and accept a\n// factory in options; when no factory is supplied they fall back to the\n// no-op factories here, which never touch `aiEventClient` or any of the\n// heavy preview/fixture machinery in `./devtools`. This keeps `./devtools`\n// outside the main-entry import graph — consumers opt into functional\n// devtools via `@tanstack/ai-client/devtools` (see `package.json#exports`).\nimport { ChatClientEventEmitter } from './events'\nimport type {\n AIDevtoolsToolFixture,\n ChatDevtoolsBridge,\n ChatDevtoolsBridgeOptions,\n GenerationDevtoolsBridge,\n GenerationDevtoolsBridgeOptions,\n VideoDevtoolsBridge,\n VideoDevtoolsBridgeOptions,\n} from './devtools'\nimport type { StreamChunk } from '@tanstack/ai/client'\nimport type {\n ChatClientEventContext,\n ChatClientRunEventContext,\n} from './events'\n\nexport type ChatDevtoolsBridgeFactory = (\n options: ChatDevtoolsBridgeOptions,\n) => ChatDevtoolsBridge\n\nexport type GenerationDevtoolsBridgeFactory = <TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n) => GenerationDevtoolsBridge<TOutput>\n\nexport type VideoDevtoolsBridgeFactory = <TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n) => VideoDevtoolsBridge<TOutput>\n\n// ===========================================================================\n// No-op event emitter — extends the abstract base so it satisfies the type\n// without dragging in any of the event-bus runtime cost.\n// ===========================================================================\n\nclass NoOpChatClientEventEmitter extends ChatClientEventEmitter {\n protected emitEvent(): void {\n // intentionally empty\n }\n}\n\n// ===========================================================================\n// No-op bridges. Methods exist to satisfy the structural shape of the real\n// classes; every emit/record call short-circuits.\n// ===========================================================================\n\nexport class NoOpChatDevtoolsBridge {\n readonly events: ChatClientEventEmitter\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n this.events = new NoOpChatClientEventEmitter(options.clientId)\n }\n\n // base bridge surface\n emitRegistered(): void {}\n emitUpdated(): void {}\n emitSnapshot(): void {}\n emitToolsRegistered(): void {}\n emitRunLifecycle(\n _eventType: unknown,\n _runId: string,\n _status: unknown,\n _options?: { error?: string },\n ): void {}\n deactivate(): void {}\n supersede(): void {}\n dispose(): void {}\n\n // chat-specific surface\n mountWithTools(_initialMessageCount: number): void {}\n notifyToolsChanged(): void {}\n setCurrentStreamId(_streamId: string | null): void {}\n recordStreamId(_streamId: string): void {}\n getCurrentStreamId(): string | null {\n return null\n }\n getLastStreamId(): string | null {\n return null\n }\n resolveStreamId(): string {\n return ''\n }\n observeChunk(_chunk: StreamChunk): void {}\n recordMemoryState(_value: unknown): void {}\n beginRun(_runId: string, _threadId: string): void {}\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n return undefined\n }\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return undefined\n }\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n return { toolCallId }\n }\n async applyFixture(_fixture: AIDevtoolsToolFixture): Promise<void> {\n // intentionally empty\n }\n}\n\nexport class NoOpGenerationDevtoolsBridge<TOutput> {\n constructor(_options: GenerationDevtoolsBridgeOptions<TOutput>) {}\n\n // base bridge surface\n emitRegistered(): void {}\n emitUpdated(): void {}\n emitSnapshot(): void {}\n emitToolsRegistered(): void {}\n emitRunLifecycle(): void {}\n deactivate(): void {}\n supersede(): void {}\n dispose(): void {}\n\n // generation-specific surface\n beginRun(_input: unknown): string {\n // Real factories supply a stable id; the no-op still returns a\n // unique value because the generation client passes this run id to\n // the adapter's RunAgentInputContext.\n return `noop-run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n }\n ensureRunStarted(_runId: string): void {}\n finishRun(\n _runId: string,\n _eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n _status: 'completed' | 'errored' | 'cancelled',\n _error?: string,\n ): void {}\n getActiveRunId(): string | null {\n return null\n }\n resetRuns(): void {}\n recordResultChange(): void {}\n recordLoadingChange(): void {}\n recordErrorChange(_error: Error | undefined): void {}\n recordStatusChange(): void {}\n recordProgressChange(): void {}\n emitState(): void {}\n}\n\nexport class NoOpVideoDevtoolsBridge<\n TOutput,\n> extends NoOpGenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {}\n recordVideoStatusChange(): void {}\n}\n\n// Compile-time parity checks. If a public method is added to the real\n// bridge class without a matching stub on the no-op, the corresponding\n// `Exclude<...>` resolves to a non-`never` union, which violates the\n// `extends never` constraint below and fails the build — surfacing the\n// drift at build time instead of as a runtime TypeError later.\ntype AssertBridgeParity<TMissing extends never> = TMissing\ntype _ChatBridgeMissing = Exclude<\n keyof ChatDevtoolsBridge,\n keyof NoOpChatDevtoolsBridge\n>\ntype _GenerationBridgeMissing = Exclude<\n keyof GenerationDevtoolsBridge<unknown>,\n keyof NoOpGenerationDevtoolsBridge<unknown>\n>\ntype _VideoBridgeMissing = Exclude<\n keyof VideoDevtoolsBridge<unknown>,\n keyof NoOpVideoDevtoolsBridge<unknown>\n>\nconst _bridgeParity:\n | [\n AssertBridgeParity<_ChatBridgeMissing>,\n AssertBridgeParity<_GenerationBridgeMissing>,\n AssertBridgeParity<_VideoBridgeMissing>,\n ]\n | undefined = undefined\nvoid _bridgeParity\n\n// ===========================================================================\n// Factories — these are what the clients call when no real factory was\n// supplied in options.\n// ===========================================================================\n\n// Casts use `unknown` because the no-op classes don't `extend` the real bridge\n// (that would pull the real implementation into the main-entry import graph).\n// Structural parity is enforced by the `_*BridgeMissing` checks above.\n\nexport const createNoOpChatDevtoolsBridge: ChatDevtoolsBridgeFactory = (\n options,\n) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpChatDevtoolsBridge(options) as unknown as ChatDevtoolsBridge\n\nexport const createNoOpGenerationDevtoolsBridge: GenerationDevtoolsBridgeFactory =\n <TOutput>(options: GenerationDevtoolsBridgeOptions<TOutput>) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpGenerationDevtoolsBridge<TOutput>(\n options,\n ) as unknown as GenerationDevtoolsBridge<TOutput>\n\nexport const createNoOpVideoDevtoolsBridge: VideoDevtoolsBridgeFactory = <\n TOutput,\n>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpVideoDevtoolsBridge<TOutput>(\n options,\n ) as unknown as VideoDevtoolsBridge<TOutput>\n"],"mappings":";;AAwCA,IAAM,6BAAN,cAAyC,uBAAuB;CAC9D,YAA4B,CAE5B;AACF;AAOA,IAAa,yBAAb,MAAoC;CAClC;CAEA,YAAY,SAAoC;EAC9C,KAAK,SAAS,IAAI,2BAA2B,QAAQ,QAAQ;CAC/D;CAGA,iBAAuB,CAAC;CACxB,cAAoB,CAAC;CACrB,eAAqB,CAAC;CACtB,sBAA4B,CAAC;CAC7B,iBACE,YACA,QACA,SACA,UACM,CAAC;CACT,aAAmB,CAAC;CACpB,YAAkB,CAAC;CACnB,UAAgB,CAAC;CAGjB,eAAe,sBAAoC,CAAC;CACpD,qBAA2B,CAAC;CAC5B,mBAAmB,WAAgC,CAAC;CACpD,eAAe,WAAyB,CAAC;CACzC,qBAAoC;EAClC,OAAO;CACT;CACA,kBAAiC;EAC/B,OAAO;CACT;CACA,kBAA0B;EACxB,OAAO;CACT;CACA,aAAa,QAA2B,CAAC;CACzC,kBAAkB,QAAuB,CAAC;CAC1C,SAAS,QAAgB,WAAyB,CAAC;CACnD,4BAAmE,CAEnE;CACA,kCAAyE,CAEzE;CACA,oBAAoB,YAA4C;EAC9D,OAAO,EAAE,WAAW;CACtB;CACA,MAAM,aAAa,UAAgD,CAEnE;AACF;AAEA,IAAa,+BAAb,MAAmD;CACjD,YAAY,UAAoD,CAAC;CAGjE,iBAAuB,CAAC;CACxB,cAAoB,CAAC;CACrB,eAAqB,CAAC;CACtB,sBAA4B,CAAC;CAC7B,mBAAyB,CAAC;CAC1B,aAAmB,CAAC;CACpB,YAAkB,CAAC;CACnB,UAAgB,CAAC;CAGjB,SAAS,QAAyB;EAIhC,OAAO,YAAY,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CACxE;CACA,iBAAiB,QAAsB,CAAC;CACxC,UACE,QACA,YACA,SACA,QACM,CAAC;CACT,iBAAgC;EAC9B,OAAO;CACT;CACA,YAAkB,CAAC;CACnB,qBAA2B,CAAC;CAC5B,sBAA4B,CAAC;CAC7B,kBAAkB,QAAiC,CAAC;CACpD,qBAA2B,CAAC;CAC5B,uBAA6B,CAAC;CAC9B,YAAkB,CAAC;AACrB;AAEA,IAAa,0BAAb,cAEU,6BAAsC;CAC9C,YAAY,SAA8C;EACxD,MAAM,OAAO;CACf;CAEA,oBAA0B,CAAC;CAC3B,0BAAgC,CAAC;AACnC;AAsCA,IAAa,gCACX,YAGA,IAAI,uBAAuB,OAAO;AAEpC,IAAa,sCACD,YAER,IAAI,6BACF,OACF;AAEJ,IAAa,iCAGX,YAGA,IAAI,wBACF,OACF"}
1
+ {"version":3,"file":"devtools-noop.js","names":[],"sources":["../../src/devtools-noop.ts"],"sourcesContent":["// No-op devtools bridge implementations + factories. The chat / generation /\n// video clients import the real bridge classes as types only and accept a\n// factory in options; when no factory is supplied they fall back to the\n// no-op factories here, which never touch `aiEventClient` or any of the\n// heavy preview/fixture machinery in `./devtools`. This keeps `./devtools`\n// outside the main-entry import graph — consumers opt into functional\n// devtools via `@tanstack/ai-client/devtools` (see `package.json#exports`).\nimport { ChatClientEventEmitter } from './events'\nimport type {\n AIDevtoolsToolFixture,\n ChatDevtoolsBridge,\n ChatDevtoolsBridgeOptions,\n GenerationDevtoolsBridge,\n GenerationDevtoolsBridgeOptions,\n VideoDevtoolsBridge,\n VideoDevtoolsBridgeOptions,\n} from './devtools'\nimport type { StreamChunk } from '@tanstack/ai/client'\nimport type {\n ChatClientEventContext,\n ChatClientRunEventContext,\n} from './events'\n\nexport type ChatDevtoolsBridgeFactory = (\n options: ChatDevtoolsBridgeOptions,\n) => ChatDevtoolsBridge\n\nexport type GenerationDevtoolsBridgeFactory = <TOutput>(\n options: GenerationDevtoolsBridgeOptions<TOutput>,\n) => GenerationDevtoolsBridge<TOutput>\n\nexport type VideoDevtoolsBridgeFactory = <TOutput>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n) => VideoDevtoolsBridge<TOutput>\n\n// ===========================================================================\n// No-op event emitter — extends the abstract base so it satisfies the type\n// without dragging in any of the event-bus runtime cost.\n// ===========================================================================\n\nclass NoOpChatClientEventEmitter extends ChatClientEventEmitter {\n protected emitEvent(): void {\n // intentionally empty\n }\n}\n\n// ===========================================================================\n// No-op bridges. Methods exist to satisfy the structural shape of the real\n// classes; every emit/record call short-circuits.\n// ===========================================================================\n\nexport class NoOpChatDevtoolsBridge {\n readonly events: ChatClientEventEmitter\n\n constructor(options: ChatDevtoolsBridgeOptions) {\n this.events = new NoOpChatClientEventEmitter(options.clientId)\n }\n\n // base bridge surface\n emitRegistered(): void {}\n emitUpdated(): void {}\n emitSnapshot(): void {}\n emitToolsRegistered(): void {}\n emitRunLifecycle(\n _eventType: unknown,\n _runId: string,\n _status: unknown,\n _options?: { error?: string },\n ): void {}\n deactivate(): void {}\n supersede(): void {}\n dispose(): void {}\n\n // chat-specific surface\n mountWithTools(_initialMessageCount: number): void {}\n notifyToolsChanged(): void {}\n setCurrentStreamId(_streamId: string | null): void {}\n recordStreamId(_streamId: string): void {}\n getCurrentStreamId(): string | null {\n return null\n }\n getLastStreamId(): string | null {\n return null\n }\n resolveStreamId(): string {\n return ''\n }\n observeChunk(_chunk: StreamChunk): void {}\n recordMemoryState(_value: unknown): void {}\n recordCompactionEvent(_eventType: string, _value: unknown): void {}\n recordCompactionState(_value: unknown): void {}\n recordSkillsState(_value: unknown): void {}\n beginRun(_runId: string, _threadId: string): void {}\n getCurrentRunEventContext(): ChatClientRunEventContext | undefined {\n return undefined\n }\n getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined {\n return undefined\n }\n findToolCallContext(toolCallId: string): ChatClientEventContext {\n return { toolCallId }\n }\n async applyFixture(_fixture: AIDevtoolsToolFixture): Promise<void> {\n // intentionally empty\n }\n}\n\nexport class NoOpGenerationDevtoolsBridge<TOutput> {\n constructor(_options: GenerationDevtoolsBridgeOptions<TOutput>) {}\n\n // base bridge surface\n emitRegistered(): void {}\n emitUpdated(): void {}\n emitSnapshot(): void {}\n emitToolsRegistered(): void {}\n emitRunLifecycle(): void {}\n deactivate(): void {}\n supersede(): void {}\n dispose(): void {}\n\n // generation-specific surface\n beginRun(_input: unknown): string {\n // Real factories supply a stable id; the no-op still returns a\n // unique value because the generation client passes this run id to\n // the adapter's RunAgentInputContext.\n return `noop-run-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n }\n ensureRunStarted(_runId: string): void {}\n finishRun(\n _runId: string,\n _eventType: 'run:completed' | 'run:errored' | 'run:cancelled',\n _status: 'completed' | 'errored' | 'cancelled',\n _error?: string,\n ): void {}\n getActiveRunId(): string | null {\n return null\n }\n resetRuns(): void {}\n recordResultChange(): void {}\n recordLoadingChange(): void {}\n recordErrorChange(_error: Error | undefined): void {}\n recordStatusChange(): void {}\n recordProgressChange(): void {}\n emitState(): void {}\n}\n\nexport class NoOpVideoDevtoolsBridge<\n TOutput,\n> extends NoOpGenerationDevtoolsBridge<TOutput> {\n constructor(options: VideoDevtoolsBridgeOptions<TOutput>) {\n super(options)\n }\n\n recordJobIdChange(): void {}\n recordVideoStatusChange(): void {}\n}\n\n// Compile-time parity checks. If a public method is added to the real\n// bridge class without a matching stub on the no-op, the corresponding\n// `Exclude<...>` resolves to a non-`never` union, which violates the\n// `extends never` constraint below and fails the build — surfacing the\n// drift at build time instead of as a runtime TypeError later.\ntype AssertBridgeParity<TMissing extends never> = TMissing\ntype _ChatBridgeMissing = Exclude<\n keyof ChatDevtoolsBridge,\n keyof NoOpChatDevtoolsBridge\n>\ntype _GenerationBridgeMissing = Exclude<\n keyof GenerationDevtoolsBridge<unknown>,\n keyof NoOpGenerationDevtoolsBridge<unknown>\n>\ntype _VideoBridgeMissing = Exclude<\n keyof VideoDevtoolsBridge<unknown>,\n keyof NoOpVideoDevtoolsBridge<unknown>\n>\nconst _bridgeParity:\n | [\n AssertBridgeParity<_ChatBridgeMissing>,\n AssertBridgeParity<_GenerationBridgeMissing>,\n AssertBridgeParity<_VideoBridgeMissing>,\n ]\n | undefined = undefined\nvoid _bridgeParity\n\n// ===========================================================================\n// Factories — these are what the clients call when no real factory was\n// supplied in options.\n// ===========================================================================\n\n// Casts use `unknown` because the no-op classes don't `extend` the real bridge\n// (that would pull the real implementation into the main-entry import graph).\n// Structural parity is enforced by the `_*BridgeMissing` checks above.\n\nexport const createNoOpChatDevtoolsBridge: ChatDevtoolsBridgeFactory = (\n options,\n) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpChatDevtoolsBridge(options) as unknown as ChatDevtoolsBridge\n\nexport const createNoOpGenerationDevtoolsBridge: GenerationDevtoolsBridgeFactory =\n <TOutput>(options: GenerationDevtoolsBridgeOptions<TOutput>) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpGenerationDevtoolsBridge<TOutput>(\n options,\n ) as unknown as GenerationDevtoolsBridge<TOutput>\n\nexport const createNoOpVideoDevtoolsBridge: VideoDevtoolsBridgeFactory = <\n TOutput,\n>(\n options: VideoDevtoolsBridgeOptions<TOutput>,\n) =>\n // oxlint-disable-next-line eslint-js/no-restricted-syntax -- see comment above\n new NoOpVideoDevtoolsBridge<TOutput>(\n options,\n ) as unknown as VideoDevtoolsBridge<TOutput>\n"],"mappings":";;AAwCA,IAAM,6BAAN,cAAyC,uBAAuB;CAC9D,YAA4B,CAE5B;AACF;AAOA,IAAa,yBAAb,MAAoC;CAClC;CAEA,YAAY,SAAoC;EAC9C,KAAK,SAAS,IAAI,2BAA2B,QAAQ,QAAQ;CAC/D;CAGA,iBAAuB,CAAC;CACxB,cAAoB,CAAC;CACrB,eAAqB,CAAC;CACtB,sBAA4B,CAAC;CAC7B,iBACE,YACA,QACA,SACA,UACM,CAAC;CACT,aAAmB,CAAC;CACpB,YAAkB,CAAC;CACnB,UAAgB,CAAC;CAGjB,eAAe,sBAAoC,CAAC;CACpD,qBAA2B,CAAC;CAC5B,mBAAmB,WAAgC,CAAC;CACpD,eAAe,WAAyB,CAAC;CACzC,qBAAoC;EAClC,OAAO;CACT;CACA,kBAAiC;EAC/B,OAAO;CACT;CACA,kBAA0B;EACxB,OAAO;CACT;CACA,aAAa,QAA2B,CAAC;CACzC,kBAAkB,QAAuB,CAAC;CAC1C,sBAAsB,YAAoB,QAAuB,CAAC;CAClE,sBAAsB,QAAuB,CAAC;CAC9C,kBAAkB,QAAuB,CAAC;CAC1C,SAAS,QAAgB,WAAyB,CAAC;CACnD,4BAAmE,CAEnE;CACA,kCAAyE,CAEzE;CACA,oBAAoB,YAA4C;EAC9D,OAAO,EAAE,WAAW;CACtB;CACA,MAAM,aAAa,UAAgD,CAEnE;AACF;AAEA,IAAa,+BAAb,MAAmD;CACjD,YAAY,UAAoD,CAAC;CAGjE,iBAAuB,CAAC;CACxB,cAAoB,CAAC;CACrB,eAAqB,CAAC;CACtB,sBAA4B,CAAC;CAC7B,mBAAyB,CAAC;CAC1B,aAAmB,CAAC;CACpB,YAAkB,CAAC;CACnB,UAAgB,CAAC;CAGjB,SAAS,QAAyB;EAIhC,OAAO,YAAY,KAAK,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;CACxE;CACA,iBAAiB,QAAsB,CAAC;CACxC,UACE,QACA,YACA,SACA,QACM,CAAC;CACT,iBAAgC;EAC9B,OAAO;CACT;CACA,YAAkB,CAAC;CACnB,qBAA2B,CAAC;CAC5B,sBAA4B,CAAC;CAC7B,kBAAkB,QAAiC,CAAC;CACpD,qBAA2B,CAAC;CAC5B,uBAA6B,CAAC;CAC9B,YAAkB,CAAC;AACrB;AAEA,IAAa,0BAAb,cAEU,6BAAsC;CAC9C,YAAY,SAA8C;EACxD,MAAM,OAAO;CACf;CAEA,oBAA0B,CAAC;CAC3B,0BAAgC,CAAC;AACnC;AAsCA,IAAa,gCACX,YAGA,IAAI,uBAAuB,OAAO;AAEpC,IAAa,sCACD,YAER,IAAI,6BACF,OACF;AAEJ,IAAa,iCAGX,YAGA,IAAI,wBACF,OACF"}
@@ -139,7 +139,7 @@ export declare class ClientDevtoolsBridge<TSnapshot extends object> {
139
139
  protected onReplayState(): void;
140
140
  private handleToolFixtureApply;
141
141
  private matchesFixtureTarget;
142
- protected createEnvelope(eventType: 'hook:registered' | 'hook:updated' | 'hook:unregistered' | 'hook:state-snapshot' | 'tools:registered' | 'memory:retrieve:started' | 'memory:retrieve:completed' | 'memory:snapshot' | AIDevtoolsRunEventType, visibility?: AIDevtoolsEventVisibility, context?: {
142
+ protected createEnvelope(eventType: 'hook:registered' | 'hook:updated' | 'hook:unregistered' | 'hook:state-snapshot' | 'tools:registered' | 'memory:retrieve:started' | 'memory:retrieve:completed' | 'memory:snapshot' | 'compaction:started' | 'compaction:state' | 'compaction:ended' | 'skills:snapshot' | AIDevtoolsRunEventType, visibility?: AIDevtoolsEventVisibility, context?: {
143
143
  runId?: string;
144
144
  }): import('@tanstack/ai-event-client').AIDevtoolsEventEnvelope;
145
145
  private createMetadataPayload;
@@ -160,6 +160,10 @@ export declare class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsC
160
160
  private lastRunEventContext;
161
161
  /** Last transported `memory:state` value, replayed when a panel opens. */
162
162
  private lastMemoryStateValue;
163
+ /** Transported compaction CUSTOM events, replayed when a panel opens. */
164
+ private readonly lastCompactionEvents;
165
+ /** Last transported `skills:state` value, replayed when a panel opens. */
166
+ private lastSkillsStateValue;
163
167
  constructor(options: ChatDevtoolsBridgeOptions);
164
168
  setCurrentStreamId(streamId: string | null): void;
165
169
  /**
@@ -185,6 +189,7 @@ export declare class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsC
185
189
  * `recordResultChange` / `recordProgressChange`.
186
190
  */
187
191
  recordMemoryState(rawValue: unknown): void;
192
+ recordSkillsState(rawValue: unknown): void;
188
193
  /**
189
194
  * Re-emit the browser-side `memory:*` events from a transported
190
195
  * `memory:state` value. The devtools store consumes these to render the
@@ -193,6 +198,15 @@ export declare class ChatDevtoolsBridge extends ClientDevtoolsBridge<AIDevtoolsC
193
198
  * adapter supports introspection.
194
199
  */
195
200
  private emitMemoryState;
201
+ /**
202
+ * Record a transported compaction CUSTOM event. Called from the chat
203
+ * client's `onCustomEvent` handler so server-side compaction reaches the
204
+ * browser DevTools panel.
205
+ */
206
+ recordCompactionEvent(eventType: string, rawValue: unknown): void;
207
+ recordCompactionState(rawValue: unknown): void;
208
+ private emitCompactionEvent;
209
+ private emitSkillsState;
196
210
  protected onReplayState(): void;
197
211
  getCurrentRunEventContext(): ChatClientRunEventContext | undefined;
198
212
  getCurrentOrLastRunEventContext(): ChatClientRunEventContext | undefined;
@@ -2,6 +2,55 @@ import { DefaultChatClientEventEmitter } from "./events.js";
2
2
  import { convertSchemaToJsonSchema } from "@tanstack/ai/client";
3
3
  import { aiEventClient, createAIDevtoolsEventEnvelope, emitAIDevtoolsEvent } from "@tanstack/ai-event-client";
4
4
  //#region src/devtools.ts
5
+ function readCompactionBoundaryValue(rawValue) {
6
+ if (!rawValue || typeof rawValue !== "object") return {};
7
+ return {
8
+ ..."before" in rawValue && typeof rawValue.before === "number" ? { before: rawValue.before } : {},
9
+ ..."after" in rawValue && typeof rawValue.after === "number" ? { after: rawValue.after } : {},
10
+ ..."messagesBefore" in rawValue && typeof rawValue.messagesBefore === "number" ? { messagesBefore: rawValue.messagesBefore } : {},
11
+ ..."messagesAfter" in rawValue && typeof rawValue.messagesAfter === "number" ? { messagesAfter: rawValue.messagesAfter } : {},
12
+ ..."reusedCheckpoint" in rawValue && typeof rawValue.reusedCheckpoint === "boolean" ? { reusedCheckpoint: rawValue.reusedCheckpoint } : {},
13
+ ..."maxTokens" in rawValue && typeof rawValue.maxTokens === "number" ? { maxTokens: rawValue.maxTokens } : {},
14
+ ..."strategyKey" in rawValue && typeof rawValue.strategyKey === "string" ? { strategyKey: rawValue.strategyKey } : {},
15
+ ..."durationMs" in rawValue && typeof rawValue.durationMs === "number" ? { durationMs: rawValue.durationMs } : {}
16
+ };
17
+ }
18
+ function readPreviewList(value) {
19
+ if (!Array.isArray(value)) return void 0;
20
+ const previews = [];
21
+ for (const item of value) {
22
+ if (!item || typeof item !== "object") continue;
23
+ if (!("role" in item) || !("tokens" in item) || !("text" in item)) continue;
24
+ if (typeof item.role !== "string" || typeof item.tokens !== "number" || typeof item.text !== "string") continue;
25
+ previews.push({
26
+ role: item.role,
27
+ tokens: item.tokens,
28
+ text: item.text
29
+ });
30
+ }
31
+ return previews;
32
+ }
33
+ function readCompactionStateValue(rawValue) {
34
+ if (!rawValue || typeof rawValue !== "object") return null;
35
+ if (!("before" in rawValue) || !("after" in rawValue) || !("messagesBefore" in rawValue) || !("messagesAfter" in rawValue)) return null;
36
+ if (typeof rawValue.before !== "number" || typeof rawValue.after !== "number" || typeof rawValue.messagesBefore !== "number" || typeof rawValue.messagesAfter !== "number") return null;
37
+ const reusedCheckpoint = "reusedCheckpoint" in rawValue && rawValue.reusedCheckpoint === true;
38
+ const maxTokens = "maxTokens" in rawValue && typeof rawValue.maxTokens === "number" ? rawValue.maxTokens : void 0;
39
+ const strategyKey = "strategyKey" in rawValue && typeof rawValue.strategyKey === "string" ? rawValue.strategyKey : void 0;
40
+ const dropped = "dropped" in rawValue ? readPreviewList(rawValue.dropped) : void 0;
41
+ const result = "result" in rawValue ? readPreviewList(rawValue.result) : void 0;
42
+ return {
43
+ before: rawValue.before,
44
+ after: rawValue.after,
45
+ messagesBefore: rawValue.messagesBefore,
46
+ messagesAfter: rawValue.messagesAfter,
47
+ reusedCheckpoint,
48
+ ...maxTokens !== void 0 ? { maxTokens } : {},
49
+ ...strategyKey ? { strategyKey } : {},
50
+ ...dropped ? { dropped } : {},
51
+ ...result ? { result } : {}
52
+ };
53
+ }
5
54
  function createAIDevtoolsGenerationPreview(input) {
6
55
  if (input.outputKind === "image") return imagePreviewFromResult(input.result);
7
56
  if (input.outputKind === "audio") return audioPreviewFromResult(input.result);
@@ -136,6 +185,28 @@ function getActiveBridgeRegistry() {
136
185
  global[activeBridgeRegistryKey] = registry;
137
186
  return registry;
138
187
  }
188
+ /**
189
+ * `{...options}` turns `get hookId()` into a data property. Chat/generation
190
+ * clients mint `threadId` after construct (`ensureThreadId` on mount), so a
191
+ * spread would freeze `hookId: ''` and DevTools could never select the hook.
192
+ */
193
+ function withLiveClientIdentity(identity, rest) {
194
+ return {
195
+ get hookId() {
196
+ return identity.hookId;
197
+ },
198
+ get clientId() {
199
+ return identity.clientId;
200
+ },
201
+ get threadId() {
202
+ return identity.threadId;
203
+ },
204
+ metadata: identity.metadata,
205
+ getSnapshot: rest.getSnapshot,
206
+ ...rest.getTools || identity.getTools ? { getTools: rest.getTools ?? identity.getTools } : {},
207
+ ...rest.applyToolFixture || identity.applyToolFixture ? { applyToolFixture: rest.applyToolFixture ?? identity.applyToolFixture } : {}
208
+ };
209
+ }
139
210
  var ClientDevtoolsBridge = class {
140
211
  options;
141
212
  unsubscribers = [];
@@ -314,13 +385,17 @@ var ChatDevtoolsBridge = class extends ClientDevtoolsBridge {
314
385
  lastRunEventContext;
315
386
  /** Last transported `memory:state` value, replayed when a panel opens. */
316
387
  lastMemoryStateValue = null;
388
+ /** Transported compaction CUSTOM events, replayed when a panel opens. */
389
+ lastCompactionEvents = [];
390
+ /** Last transported `skills:state` value, replayed when a panel opens. */
391
+ lastSkillsStateValue = null;
317
392
  constructor(options) {
318
- super({
319
- ...options,
393
+ super(withLiveClientIdentity(options, {
394
+ getSnapshot: options.getSnapshot,
320
395
  applyToolFixture: (fixture) => this.applyFixture(fixture)
321
- });
396
+ }));
322
397
  this.chatOptions = options;
323
- this.events = new ChatDevtoolsAwareEventEmitter(options.clientId, this);
398
+ this.events = new ChatDevtoolsAwareEventEmitter(() => options.clientId, this);
324
399
  }
325
400
  setCurrentStreamId(streamId) {
326
401
  this.currentStreamId = streamId;
@@ -389,6 +464,10 @@ var ChatDevtoolsBridge = class extends ClientDevtoolsBridge {
389
464
  this.lastMemoryStateValue = rawValue;
390
465
  this.emitMemoryState(rawValue);
391
466
  }
467
+ recordSkillsState(rawValue) {
468
+ this.lastSkillsStateValue = rawValue;
469
+ this.emitSkillsState(rawValue);
470
+ }
392
471
  /**
393
472
  * Re-emit the browser-side `memory:*` events from a transported
394
473
  * `memory:state` value. The devtools store consumes these to render the
@@ -427,8 +506,65 @@ var ChatDevtoolsBridge = class extends ClientDevtoolsBridge {
427
506
  facts: value.snapshot.facts ?? []
428
507
  });
429
508
  }
509
+ /**
510
+ * Record a transported compaction CUSTOM event. Called from the chat
511
+ * client's `onCustomEvent` handler so server-side compaction reaches the
512
+ * browser DevTools panel.
513
+ */
514
+ recordCompactionEvent(eventType, rawValue) {
515
+ this.lastCompactionEvents.push({
516
+ eventType,
517
+ value: rawValue
518
+ });
519
+ if (this.lastCompactionEvents.length > 60) this.lastCompactionEvents.splice(0, this.lastCompactionEvents.length - 60);
520
+ this.emitCompactionEvent(eventType, rawValue);
521
+ }
522
+ recordCompactionState(rawValue) {
523
+ this.recordCompactionEvent("compaction:state", rawValue);
524
+ }
525
+ emitCompactionEvent(eventType, rawValue) {
526
+ const runContext = this.currentRunId ? { runId: this.currentRunId } : {};
527
+ if (eventType === "compaction:started") {
528
+ const value = readCompactionBoundaryValue(rawValue);
529
+ emitAIDevtoolsEvent("compaction:started", {
530
+ ...this.createEnvelope("compaction:started", "client-state", runContext),
531
+ ...value
532
+ });
533
+ return;
534
+ }
535
+ if (eventType === "compaction:ended") {
536
+ const value = readCompactionBoundaryValue(rawValue);
537
+ emitAIDevtoolsEvent("compaction:ended", {
538
+ ...this.createEnvelope("compaction:ended", "client-state", runContext),
539
+ ...value
540
+ });
541
+ return;
542
+ }
543
+ if (eventType === "compaction:state") {
544
+ const value = readCompactionStateValue(rawValue);
545
+ if (!value) return;
546
+ emitAIDevtoolsEvent("compaction:state", {
547
+ ...this.createEnvelope("compaction:state", "client-state", runContext),
548
+ ...value
549
+ });
550
+ }
551
+ }
552
+ emitSkillsState(rawValue) {
553
+ if (!rawValue || typeof rawValue !== "object") return;
554
+ const value = rawValue;
555
+ const catalog = Array.isArray(value.catalog) ? value.catalog : [];
556
+ const activated = Array.isArray(value.activated) ? value.activated : [];
557
+ const runContext = this.currentRunId ? { runId: this.currentRunId } : {};
558
+ emitAIDevtoolsEvent("skills:snapshot", {
559
+ ...this.createEnvelope("skills:snapshot", "client-state", runContext),
560
+ catalog,
561
+ activated
562
+ });
563
+ }
430
564
  onReplayState() {
431
565
  if (this.lastMemoryStateValue != null) this.emitMemoryState(this.lastMemoryStateValue);
566
+ for (const event of this.lastCompactionEvents) this.emitCompactionEvent(event.eventType, event.value);
567
+ if (this.lastSkillsStateValue != null) this.emitSkillsState(this.lastSkillsStateValue);
432
568
  }
433
569
  getCurrentRunEventContext() {
434
570
  if (!this.currentRunId) return void 0;
@@ -709,10 +845,7 @@ var GenerationDevtoolsBridge = class extends ClientDevtoolsBridge {
709
845
  maxRuns;
710
846
  getCoreState;
711
847
  constructor(options) {
712
- super({
713
- ...options,
714
- getSnapshot: () => this.buildSnapshot()
715
- });
848
+ super(withLiveClientIdentity(options, { getSnapshot: () => this.buildSnapshot() }));
716
849
  this.maxRuns = options.maxRuns ?? 20;
717
850
  this.getCoreState = options.getCoreState;
718
851
  }
@@ -936,11 +1069,17 @@ var VideoDevtoolsBridge = class extends GenerationDevtoolsBridge {
936
1069
  }
937
1070
  };
938
1071
  var ChatDevtoolsAwareEventEmitter = class extends DefaultChatClientEventEmitter {
1072
+ getClientId;
939
1073
  helper;
940
- constructor(clientId, helper) {
941
- super(clientId);
1074
+ constructor(getClientId, helper) {
1075
+ super(getClientId());
1076
+ this.getClientId = getClientId;
942
1077
  this.helper = helper;
943
1078
  }
1079
+ emitEvent(eventName, data) {
1080
+ this.clientId = this.getClientId();
1081
+ super.emitEvent(eventName, data);
1082
+ }
944
1083
  afterEmit(streamId) {
945
1084
  if (streamId) this.helper.recordStreamId(streamId);
946
1085
  this.helper.emitSnapshot();