@creature-ai/sdk 0.1.1 → 0.1.3

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.
@@ -9328,8 +9328,11 @@ var Subscribable = class {
9328
9328
  }
9329
9329
  };
9330
9330
 
9331
- // src/core/McpHostClient.ts
9332
- var McpHostClient = class extends Subscribable {
9331
+ // src/core/McpAppHostClient.ts
9332
+ var McpAppHostClient = class extends Subscribable {
9333
+ // ============================================================================
9334
+ // Private Properties
9335
+ // ============================================================================
9333
9336
  state = {
9334
9337
  isReady: false,
9335
9338
  environment: "mcp-apps",
@@ -9338,18 +9341,22 @@ var McpHostClient = class extends Subscribable {
9338
9341
  config;
9339
9342
  app = null;
9340
9343
  connected = false;
9344
+ // ============================================================================
9345
+ // Constructor
9346
+ // ============================================================================
9341
9347
  constructor(config) {
9342
9348
  super();
9343
9349
  this.config = config;
9344
9350
  }
9351
+ // ============================================================================
9352
+ // Public API
9353
+ // ============================================================================
9354
+ /**
9355
+ * Get the current client state.
9356
+ */
9345
9357
  getState() {
9346
9358
  return this.state;
9347
9359
  }
9348
- setState(partial) {
9349
- const prev = this.state;
9350
- this.state = { ...this.state, ...partial };
9351
- this.notifyStateChange(this.state, prev);
9352
- }
9353
9360
  /**
9354
9361
  * Connect to the MCP Apps host.
9355
9362
  *
@@ -9371,90 +9378,6 @@ var McpHostClient = class extends Subscribable {
9371
9378
  this.setupHandlers();
9372
9379
  this.initiateConnection();
9373
9380
  }
9374
- /**
9375
- * Set up notification handlers on the App instance.
9376
- *
9377
- * Maps the official SDK's callback pattern to our event emitter pattern,
9378
- * allowing consumers to use `.on("tool-result", ...)` etc.
9379
- */
9380
- setupHandlers() {
9381
- if (!this.app) return;
9382
- this.app.ontoolinput = (params) => {
9383
- console.debug(`[${this.config.name}] Received tool-input`, { args: params.arguments });
9384
- this.emit("tool-input", params.arguments || {});
9385
- };
9386
- this.app.ontoolresult = (params) => {
9387
- console.log(`[McpHostClient] ontoolresult called`, {
9388
- isError: params.isError,
9389
- source: params.source,
9390
- hasContent: !!params.content,
9391
- hasStructuredContent: !!params.structuredContent,
9392
- structuredContent: params.structuredContent
9393
- });
9394
- const textContent = params.content?.filter((item) => item.type === "text").map((item) => ({ type: item.type, text: item.text }));
9395
- const result = {
9396
- content: textContent,
9397
- structuredContent: params.structuredContent,
9398
- isError: params.isError,
9399
- source: params.source
9400
- };
9401
- console.log(`[McpHostClient] Emitting tool-result event`, result);
9402
- this.emit("tool-result", result);
9403
- };
9404
- this.app.onhostcontextchanged = (params) => {
9405
- console.debug(`[${this.config.name}] Host context changed`, { theme: params.theme });
9406
- if (params.theme) {
9407
- YU(params.theme);
9408
- this.emit("theme-change", params.theme);
9409
- }
9410
- if (params.styles?.variables) {
9411
- QU(params.styles.variables);
9412
- }
9413
- if (params.styles?.css?.fonts) {
9414
- qU(params.styles.css.fonts);
9415
- }
9416
- };
9417
- this.app.onteardown = async (_params, _extra) => {
9418
- console.debug(`[${this.config.name}] Teardown requested`);
9419
- await this.emit("teardown");
9420
- return {};
9421
- };
9422
- }
9423
- /**
9424
- * Initiate connection using PostMessageTransport.
9425
- *
9426
- * The SDK's App.connect() handles the protocol handshake correctly:
9427
- * the guest (App) sends `ui/initialize` to the host.
9428
- */
9429
- async initiateConnection() {
9430
- if (!this.app) {
9431
- return;
9432
- }
9433
- try {
9434
- const transport = new Yn(window.parent, window.parent);
9435
- await this.app.connect(transport);
9436
- const hostContext = this.app.getHostContext();
9437
- console.debug(`[${this.config.name}] Connected to host`, { theme: hostContext?.theme });
9438
- if (hostContext?.theme) {
9439
- YU(hostContext.theme);
9440
- this.emit("theme-change", hostContext.theme);
9441
- }
9442
- if (hostContext?.styles?.variables) {
9443
- QU(hostContext.styles.variables);
9444
- }
9445
- if (hostContext?.styles?.css?.fonts) {
9446
- qU(hostContext.styles.css.fonts);
9447
- }
9448
- const widgetState = hostContext?.widgetState;
9449
- if (widgetState) {
9450
- this.setState({ widgetState });
9451
- this.emit("widget-state-change", widgetState);
9452
- }
9453
- this.setState({ isReady: true });
9454
- } catch (error) {
9455
- console.error(`[${this.config.name}] Connection failed`, { error });
9456
- }
9457
- }
9458
9381
  /**
9459
9382
  * Disconnect from the host.
9460
9383
  *
@@ -9487,9 +9410,8 @@ var McpHostClient = class extends Subscribable {
9487
9410
  name: toolName,
9488
9411
  arguments: args
9489
9412
  });
9490
- const textContent = sdkResult.content?.filter((item) => item.type === "text").map((item) => ({ type: item.type, text: item.text }));
9491
9413
  const result = {
9492
- content: textContent,
9414
+ content: this.extractTextContent(sdkResult.content),
9493
9415
  structuredContent: sdkResult.structuredContent,
9494
9416
  isError: sdkResult.isError
9495
9417
  };
@@ -9530,6 +9452,13 @@ var McpHostClient = class extends Subscribable {
9530
9452
  widgetState: state
9531
9453
  });
9532
9454
  }
9455
+ async requestDisplayMode(params) {
9456
+ if (!this.app) {
9457
+ return { mode: params.mode };
9458
+ }
9459
+ const result = await this.app.requestDisplayMode({ mode: params.mode });
9460
+ return { mode: result.mode };
9461
+ }
9533
9462
  /**
9534
9463
  * Send a log message to the host's DevConsole.
9535
9464
  *
@@ -9537,8 +9466,6 @@ var McpHostClient = class extends Subscribable {
9537
9466
  * to the host. Logs appear in the unified DevConsole alongside server logs,
9538
9467
  * with appropriate color coding based on level.
9539
9468
  *
9540
- * The logger name is automatically set to the app name from config.
9541
- *
9542
9469
  * @param level - Log severity level (debug, info, notice, warning, error)
9543
9470
  * @param message - Log message
9544
9471
  * @param data - Optional structured data to include with the log
@@ -9555,10 +9482,113 @@ var McpHostClient = class extends Subscribable {
9555
9482
  data: data ? { message, ...data } : message
9556
9483
  });
9557
9484
  }
9485
+ // ============================================================================
9486
+ // Private Methods
9487
+ // ============================================================================
9488
+ /**
9489
+ * Update internal state and notify listeners.
9490
+ */
9491
+ setState(partial) {
9492
+ const prev = this.state;
9493
+ this.state = { ...this.state, ...partial };
9494
+ this.notifyStateChange(this.state, prev);
9495
+ }
9496
+ /**
9497
+ * Set up notification handlers on the App instance.
9498
+ *
9499
+ * Maps the official SDK's callback pattern to our event emitter pattern,
9500
+ * allowing consumers to use `.on("tool-result", ...)` etc.
9501
+ */
9502
+ setupHandlers() {
9503
+ if (!this.app) return;
9504
+ this.app.ontoolinput = (params) => {
9505
+ console.debug(`[${this.config.name}] Received tool-input`, { args: params.arguments });
9506
+ this.emit("tool-input", params.arguments || {});
9507
+ };
9508
+ this.app.ontoolresult = (params) => {
9509
+ console.log(`[McpAppHostClient] ontoolresult called`, {
9510
+ isError: params.isError,
9511
+ source: params.source,
9512
+ hasContent: !!params.content,
9513
+ hasStructuredContent: !!params.structuredContent,
9514
+ structuredContent: params.structuredContent
9515
+ });
9516
+ const result = {
9517
+ content: this.extractTextContent(params.content),
9518
+ structuredContent: params.structuredContent,
9519
+ isError: params.isError,
9520
+ source: params.source
9521
+ };
9522
+ console.log(`[McpAppHostClient] Emitting tool-result event`, result);
9523
+ this.emit("tool-result", result);
9524
+ };
9525
+ this.app.onhostcontextchanged = (params) => {
9526
+ console.debug(`[${this.config.name}] Host context changed`, { theme: params.theme });
9527
+ this.applyHostContext(params);
9528
+ };
9529
+ this.app.onteardown = async (_params, _extra) => {
9530
+ console.debug(`[${this.config.name}] Teardown requested`);
9531
+ await this.emit("teardown");
9532
+ return {};
9533
+ };
9534
+ }
9535
+ /**
9536
+ * Initiate connection using PostMessageTransport.
9537
+ *
9538
+ * The SDK's App.connect() handles the protocol handshake correctly:
9539
+ * the guest (App) sends `ui/initialize` to the host.
9540
+ */
9541
+ async initiateConnection() {
9542
+ if (!this.app) {
9543
+ return;
9544
+ }
9545
+ try {
9546
+ const transport = new Yn(window.parent, window.parent);
9547
+ await this.app.connect(transport);
9548
+ const hostContext = this.app.getHostContext();
9549
+ console.debug(`[${this.config.name}] Connected to host`, { theme: hostContext?.theme });
9550
+ if (hostContext) {
9551
+ this.applyHostContext(hostContext);
9552
+ const widgetState = hostContext.widgetState;
9553
+ if (widgetState) {
9554
+ this.setState({ widgetState });
9555
+ this.emit("widget-state-change", widgetState);
9556
+ }
9557
+ }
9558
+ this.setState({ isReady: true });
9559
+ } catch (error) {
9560
+ console.error(`[${this.config.name}] Connection failed`, { error });
9561
+ }
9562
+ }
9563
+ /**
9564
+ * Apply theme, styles, and fonts from host context.
9565
+ */
9566
+ applyHostContext(context) {
9567
+ if (context.theme) {
9568
+ YU(context.theme);
9569
+ this.emit("theme-change", context.theme);
9570
+ }
9571
+ if (context.styles?.variables) {
9572
+ QU(context.styles.variables);
9573
+ }
9574
+ if (context.styles?.css?.fonts) {
9575
+ qU(context.styles.css.fonts);
9576
+ }
9577
+ }
9578
+ /**
9579
+ * Extract text content from SDK result content array.
9580
+ * Filters to only include text items since our ToolResult type expects text.
9581
+ */
9582
+ extractTextContent(content) {
9583
+ return content?.filter((item) => item.type === "text").map((item) => ({ type: item.type, text: item.text }));
9584
+ }
9558
9585
  };
9559
9586
 
9560
- // src/core/ChatGPTHostClient.ts
9561
- var ChatGPTHostClient = class extends Subscribable {
9587
+ // src/core/ChatGptAppHostClient.ts
9588
+ var ChatGptAppHostClient = class extends Subscribable {
9589
+ // ============================================================================
9590
+ // Private Properties
9591
+ // ============================================================================
9562
9592
  state = {
9563
9593
  isReady: false,
9564
9594
  environment: "chatgpt",
@@ -9568,24 +9598,39 @@ var ChatGPTHostClient = class extends Subscribable {
9568
9598
  connected = false;
9569
9599
  hasProcessedInitialData = false;
9570
9600
  globalsHandler = null;
9601
+ // ============================================================================
9602
+ // Constructor
9603
+ // ============================================================================
9571
9604
  constructor(config) {
9572
9605
  super();
9573
9606
  this.config = config;
9574
9607
  }
9608
+ // ============================================================================
9609
+ // Public API
9610
+ // ============================================================================
9611
+ /**
9612
+ * Get the current client state.
9613
+ */
9575
9614
  getState() {
9576
9615
  return this.state;
9577
9616
  }
9578
- setState(partial) {
9579
- const prev = this.state;
9580
- this.state = { ...this.state, ...partial };
9581
- this.notifyStateChange(this.state, prev);
9582
- }
9617
+ /**
9618
+ * Connect to the ChatGPT host.
9619
+ *
9620
+ * Processes initial data from `window.openai` and sets up a listener
9621
+ * for subsequent `openai:set_globals` events.
9622
+ */
9583
9623
  connect() {
9584
9624
  if (this.connected) return;
9585
9625
  this.connected = true;
9586
9626
  this.processInitialData();
9587
9627
  this.setupGlobalsListener();
9588
9628
  }
9629
+ /**
9630
+ * Disconnect from the host.
9631
+ *
9632
+ * Removes the globals event listener.
9633
+ */
9589
9634
  disconnect() {
9590
9635
  if (!this.connected) return;
9591
9636
  this.connected = false;
@@ -9594,39 +9639,13 @@ var ChatGPTHostClient = class extends Subscribable {
9594
9639
  this.globalsHandler = null;
9595
9640
  }
9596
9641
  }
9597
- processInitialData() {
9598
- if (this.hasProcessedInitialData) return;
9599
- const openai = window.openai;
9600
- if (!openai) {
9601
- console.warn("[SDK] window.openai not available");
9602
- return;
9603
- }
9604
- this.hasProcessedInitialData = true;
9605
- this.setState({ isReady: true });
9606
- if (openai.toolOutput) {
9607
- this.emit("tool-input", openai.toolOutput);
9608
- this.emit("tool-result", { structuredContent: openai.toolOutput });
9609
- }
9610
- if (openai.widgetState) {
9611
- this.setState({ widgetState: openai.widgetState });
9612
- this.emit("widget-state-change", openai.widgetState);
9613
- }
9614
- }
9615
- setupGlobalsListener() {
9616
- this.globalsHandler = (event) => {
9617
- const customEvent = event;
9618
- const globals = customEvent.detail?.globals;
9619
- if (globals?.toolOutput) {
9620
- this.emit("tool-input", globals.toolOutput);
9621
- this.emit("tool-result", { structuredContent: globals.toolOutput });
9622
- }
9623
- if (globals?.widgetState !== void 0) {
9624
- this.setState({ widgetState: globals.widgetState });
9625
- this.emit("widget-state-change", globals.widgetState);
9626
- }
9627
- };
9628
- window.addEventListener("openai:set_globals", this.globalsHandler, { passive: true });
9629
- }
9642
+ /**
9643
+ * Call a tool on the MCP server via the ChatGPT bridge.
9644
+ *
9645
+ * @param toolName - Name of the tool to call
9646
+ * @param args - Arguments to pass to the tool
9647
+ * @returns Tool result with content and structuredContent
9648
+ */
9630
9649
  async callTool(toolName, args) {
9631
9650
  const openai = window.openai;
9632
9651
  if (!openai?.callTool) {
@@ -9644,8 +9663,18 @@ var ChatGPTHostClient = class extends Subscribable {
9644
9663
  this.emit("tool-result", result);
9645
9664
  return result;
9646
9665
  }
9666
+ /**
9667
+ * Send a notification to the host.
9668
+ *
9669
+ * No-op on ChatGPT — notifications are not supported.
9670
+ */
9647
9671
  sendNotification(_method, _params) {
9648
9672
  }
9673
+ /**
9674
+ * Set widget state and sync with the ChatGPT host.
9675
+ *
9676
+ * @param state - New widget state (or null to clear)
9677
+ */
9649
9678
  setWidgetState(state) {
9650
9679
  this.setState({ widgetState: state });
9651
9680
  if (window.openai?.setWidgetState) {
@@ -9657,7 +9686,7 @@ var ChatGPTHostClient = class extends Subscribable {
9657
9686
  * Log a message to the console.
9658
9687
  *
9659
9688
  * ChatGPT doesn't have a DevConsole, so logs go to browser console only.
9660
- * This provides API parity with McpHostClient.
9689
+ * This provides API parity with McpAppHostClient.
9661
9690
  *
9662
9691
  * @param level - Log severity level
9663
9692
  * @param message - Log message
@@ -9667,6 +9696,76 @@ var ChatGPTHostClient = class extends Subscribable {
9667
9696
  const consoleMethod = level === "error" ? "error" : level === "warning" ? "warn" : "log";
9668
9697
  console[consoleMethod](`[${this.config.name}]`, message, data ?? "");
9669
9698
  }
9699
+ // ============================================================================
9700
+ // Private Methods
9701
+ // ============================================================================
9702
+ /**
9703
+ * Update internal state and notify listeners.
9704
+ */
9705
+ setState(partial) {
9706
+ const prev = this.state;
9707
+ this.state = { ...this.state, ...partial };
9708
+ this.notifyStateChange(this.state, prev);
9709
+ }
9710
+ /**
9711
+ * Process initial data from `window.openai`.
9712
+ *
9713
+ * Called once on connect to handle any tool output or widget state
9714
+ * that was set before the client connected.
9715
+ */
9716
+ processInitialData() {
9717
+ if (this.hasProcessedInitialData) return;
9718
+ const openai = window.openai;
9719
+ if (!openai) {
9720
+ console.warn("[SDK] window.openai not available");
9721
+ return;
9722
+ }
9723
+ this.hasProcessedInitialData = true;
9724
+ this.setState({ isReady: true });
9725
+ if (openai.toolOutput) {
9726
+ this.emit("tool-input", openai.toolOutput);
9727
+ this.emit("tool-result", { structuredContent: openai.toolOutput });
9728
+ }
9729
+ if (openai.widgetState) {
9730
+ this.setState({ widgetState: openai.widgetState });
9731
+ this.emit("widget-state-change", openai.widgetState);
9732
+ }
9733
+ }
9734
+ /**
9735
+ * Set up listener for `openai:set_globals` events.
9736
+ *
9737
+ * ChatGPT dispatches this event when tool output or widget state
9738
+ * changes after initial load.
9739
+ */
9740
+ setupGlobalsListener() {
9741
+ this.globalsHandler = (event) => {
9742
+ const customEvent = event;
9743
+ const globals = customEvent.detail?.globals;
9744
+ if (globals?.toolOutput) {
9745
+ this.emit("tool-input", globals.toolOutput);
9746
+ this.emit("tool-result", { structuredContent: globals.toolOutput });
9747
+ }
9748
+ if (globals?.widgetState !== void 0) {
9749
+ this.setState({ widgetState: globals.widgetState });
9750
+ this.emit("widget-state-change", globals.widgetState);
9751
+ }
9752
+ };
9753
+ window.addEventListener("openai:set_globals", this.globalsHandler, { passive: true });
9754
+ }
9755
+ /**
9756
+ * Request a display mode change from the ChatGPT host.
9757
+ *
9758
+ * @param params - Display mode to request
9759
+ * @returns The resulting display mode
9760
+ */
9761
+ async requestDisplayMode(params) {
9762
+ const openai = window.openai;
9763
+ if (openai?.requestDisplayMode) {
9764
+ const result = await openai.requestDisplayMode({ mode: params.mode });
9765
+ return { mode: result.mode };
9766
+ }
9767
+ return { mode: params.mode };
9768
+ }
9670
9769
  };
9671
9770
 
9672
9771
  // src/core/utils.ts
@@ -9683,123 +9782,8 @@ function detectEnvironment() {
9683
9782
  return "standalone";
9684
9783
  }
9685
9784
 
9686
- // src/core/AppSession.ts
9687
- var AppSession = class {
9688
- id;
9689
- _state;
9690
- listeners = /* @__PURE__ */ new Set();
9691
- hostClient = null;
9692
- hostUnsubscribe = null;
9693
- constructor(initialState = {}, options = {}) {
9694
- this.id = options.id ?? this.generateId();
9695
- this._state = {
9696
- internal: initialState.internal ?? {},
9697
- backend: initialState.backend ?? {},
9698
- ui: initialState.ui ?? null
9699
- };
9700
- }
9701
- generateId() {
9702
- return `session_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
9703
- }
9704
- get state() {
9705
- return this._state;
9706
- }
9707
- get internal() {
9708
- return this._state.internal;
9709
- }
9710
- get backend() {
9711
- return this._state.backend;
9712
- }
9713
- get ui() {
9714
- return this._state.ui;
9715
- }
9716
- subscribe(listener) {
9717
- this.listeners.add(listener);
9718
- return () => {
9719
- this.listeners.delete(listener);
9720
- };
9721
- }
9722
- notify(prevState) {
9723
- this.listeners.forEach((listener) => listener(this._state, prevState));
9724
- }
9725
- setState(partial) {
9726
- const prev = this._state;
9727
- this._state = {
9728
- internal: partial.internal !== void 0 ? { ...prev.internal, ...partial.internal } : prev.internal,
9729
- backend: partial.backend !== void 0 ? { ...prev.backend, ...partial.backend } : prev.backend,
9730
- ui: partial.ui !== void 0 ? partial.ui : prev.ui
9731
- };
9732
- this.notify(prev);
9733
- }
9734
- setInternal(internal) {
9735
- const prev = this._state;
9736
- this._state = {
9737
- ...prev,
9738
- internal: { ...prev.internal, ...internal }
9739
- };
9740
- this.notify(prev);
9741
- }
9742
- setBackend(backend) {
9743
- const prev = this._state;
9744
- this._state = {
9745
- ...prev,
9746
- backend: { ...prev.backend, ...backend }
9747
- };
9748
- this.notify(prev);
9749
- }
9750
- setUi(ui2) {
9751
- console.log(`[AppSession:${this.id}] setUi`, ui2);
9752
- const prev = this._state;
9753
- this._state = { ...prev, ui: ui2 };
9754
- this.notify(prev);
9755
- if (this.hostClient) {
9756
- this.hostClient.setWidgetState(ui2);
9757
- }
9758
- }
9759
- updateUi(partial) {
9760
- const prev = this._state;
9761
- const newUi = prev.ui !== null ? { ...prev.ui, ...partial } : partial;
9762
- this._state = { ...prev, ui: newUi };
9763
- this.notify(prev);
9764
- if (this.hostClient) {
9765
- this.hostClient.setWidgetState(newUi);
9766
- }
9767
- }
9768
- bindHost(host) {
9769
- this.hostClient = host;
9770
- console.log(`[AppSession:${this.id}] Binding to host`);
9771
- const currentHostState = host.getState();
9772
- if (currentHostState.widgetState !== null && currentHostState.widgetState !== void 0) {
9773
- console.log(`[AppSession:${this.id}] Restoring UI state from host`, currentHostState.widgetState);
9774
- const prev = this._state;
9775
- this._state = { ...prev, ui: currentHostState.widgetState };
9776
- this.notify(prev);
9777
- }
9778
- this.hostUnsubscribe = host.on("widget-state-change", (widgetState) => {
9779
- console.log(`[AppSession:${this.id}] Host widget state changed`, widgetState);
9780
- const prev = this._state;
9781
- this._state = { ...prev, ui: widgetState };
9782
- this.notify(prev);
9783
- });
9784
- return () => {
9785
- this.unbindHost();
9786
- };
9787
- }
9788
- unbindHost() {
9789
- console.log(`[AppSession:${this.id}] Unbinding from host`);
9790
- if (this.hostUnsubscribe) {
9791
- this.hostUnsubscribe();
9792
- this.hostUnsubscribe = null;
9793
- }
9794
- this.hostClient = null;
9795
- }
9796
- injectAppSessionId(data) {
9797
- return { ...data, appSessionId: this.id };
9798
- }
9799
- };
9800
-
9801
- // src/core/channel.ts
9802
- function createChannel(url, config = {}) {
9785
+ // src/core/websocket.ts
9786
+ function createWebSocket(url, config = {}) {
9803
9787
  const {
9804
9788
  onMessage,
9805
9789
  onStatusChange,
@@ -9819,36 +9803,36 @@ function createChannel(url, config = {}) {
9819
9803
  };
9820
9804
  const connect = () => {
9821
9805
  if (ws?.readyState === WebSocket.OPEN || ws?.readyState === WebSocket.CONNECTING) {
9822
- console.log("[Channel] Already connected/connecting to:", url);
9806
+ console.log("[WebSocket] Already connected/connecting to:", url);
9823
9807
  return;
9824
9808
  }
9825
9809
  intentionalClose = false;
9826
9810
  setStatus("connecting");
9827
- console.log("[Channel] Connecting to:", url);
9811
+ console.log("[WebSocket] Connecting to:", url);
9828
9812
  try {
9829
9813
  ws = new WebSocket(url);
9830
9814
  } catch (e2) {
9831
- console.error("[Channel] Failed to create WebSocket:", e2);
9815
+ console.error("[WebSocket] Failed to create WebSocket:", e2);
9832
9816
  setStatus("error", "Failed to create WebSocket");
9833
9817
  scheduleReconnect();
9834
9818
  return;
9835
9819
  }
9836
9820
  ws.onopen = () => {
9837
- console.log("[Channel] Connected to:", url);
9821
+ console.log("[WebSocket] Connected to:", url);
9838
9822
  reconnectAttempts = 0;
9839
9823
  setStatus("connected");
9840
9824
  };
9841
9825
  ws.onmessage = (event) => {
9842
9826
  try {
9843
9827
  const message = JSON.parse(event.data);
9844
- console.log("[Channel] Received message:", message);
9828
+ console.log("[WebSocket] Received message:", message);
9845
9829
  onMessage?.(message);
9846
9830
  } catch (e2) {
9847
- console.error("[Channel] Failed to parse message:", e2);
9831
+ console.error("[WebSocket] Failed to parse message:", e2);
9848
9832
  }
9849
9833
  };
9850
9834
  ws.onerror = (e2) => {
9851
- console.error("[Channel] WebSocket error:", e2);
9835
+ console.error("[WebSocket] Error:", e2);
9852
9836
  setStatus("error", "Connection error");
9853
9837
  };
9854
9838
  ws.onclose = (event) => {
@@ -9858,7 +9842,7 @@ function createChannel(url, config = {}) {
9858
9842
  return;
9859
9843
  }
9860
9844
  if (event.code === 4004) {
9861
- setStatus("error", "AppSession channel not found");
9845
+ setStatus("error", "Instance WebSocket not found");
9862
9846
  return;
9863
9847
  }
9864
9848
  scheduleReconnect();
@@ -9906,9 +9890,9 @@ function createChannel(url, config = {}) {
9906
9890
  function createHost(config) {
9907
9891
  const environment = detectEnvironment();
9908
9892
  if (environment === "chatgpt") {
9909
- return new ChatGPTHostClient(config);
9893
+ return new ChatGptAppHostClient(config);
9910
9894
  }
9911
- return new McpHostClient(config);
9895
+ return new McpAppHostClient(config);
9912
9896
  }
9913
9897
 
9914
9898
  // src/react/useHost.ts
@@ -9943,7 +9927,8 @@ function useHost(config) {
9943
9927
  () => ({
9944
9928
  callTool: client.callTool.bind(client),
9945
9929
  sendNotification: client.sendNotification.bind(client),
9946
- setWidgetState: client.setWidgetState.bind(client)
9930
+ setWidgetState: client.setWidgetState.bind(client),
9931
+ requestDisplayMode: client.requestDisplayMode.bind(client)
9947
9932
  }),
9948
9933
  [client]
9949
9934
  );
@@ -10001,6 +9986,7 @@ function useHost(config) {
10001
9986
  callTool: boundMethods.callTool,
10002
9987
  sendNotification: boundMethods.sendNotification,
10003
9988
  setWidgetState: boundMethods.setWidgetState,
9989
+ requestDisplayMode: boundMethods.requestDisplayMode,
10004
9990
  log
10005
9991
  };
10006
9992
  }
@@ -10009,17 +9995,21 @@ function useHost(config) {
10009
9995
  import { useState, useCallback } from "react";
10010
9996
  function useToolResult() {
10011
9997
  const [data, setData] = useState(null);
9998
+ const [instanceId, setInstanceId] = useState(null);
10012
9999
  const [title, setTitle] = useState(null);
10013
10000
  const [isError, setIsError] = useState(false);
10014
10001
  const [text, setText] = useState(null);
10015
10002
  const onToolResult = useCallback((result) => {
10016
10003
  const structured = result.structuredContent;
10017
10004
  if (structured) {
10018
- const { title: resultTitle, ...rest } = structured;
10005
+ const { title: resultTitle, instanceId: resultInstanceId, ...rest } = structured;
10019
10006
  setData(rest);
10020
10007
  if (resultTitle) {
10021
10008
  setTitle(resultTitle);
10022
10009
  }
10010
+ if (resultInstanceId) {
10011
+ setInstanceId(resultInstanceId);
10012
+ }
10023
10013
  }
10024
10014
  setIsError(result.isError || false);
10025
10015
  if (result.content?.[0]?.text) {
@@ -10028,12 +10018,14 @@ function useToolResult() {
10028
10018
  }, []);
10029
10019
  const reset = useCallback(() => {
10030
10020
  setData(null);
10021
+ setInstanceId(null);
10031
10022
  setTitle(null);
10032
10023
  setIsError(false);
10033
10024
  setText(null);
10034
10025
  }, []);
10035
10026
  return {
10036
10027
  data,
10028
+ instanceId,
10037
10029
  title,
10038
10030
  isError,
10039
10031
  text,
@@ -10074,9 +10066,9 @@ function useWidgetState(initialState) {
10074
10066
  return [localState, setState];
10075
10067
  }
10076
10068
 
10077
- // src/react/useChannel.ts
10069
+ // src/react/useWebSocket.ts
10078
10070
  import { useEffect as useEffect3, useRef as useRef2, useMemo as useMemo2, useCallback as useCallback3, useSyncExternalStore as useSyncExternalStore2 } from "react";
10079
- function useChannel(url, config = {}) {
10071
+ function useWebSocket(url, config = {}) {
10080
10072
  const { onMessage, enabled = true } = config;
10081
10073
  const onMessageRef = useRef2(onMessage);
10082
10074
  onMessageRef.current = onMessage;
@@ -10101,7 +10093,7 @@ function useChannel(url, config = {}) {
10101
10093
  }
10102
10094
  return;
10103
10095
  }
10104
- const client = createChannel(url, {
10096
+ const client = createWebSocket(url, {
10105
10097
  onMessage: (msg) => onMessageRef.current?.(msg),
10106
10098
  onStatusChange: (status, error) => {
10107
10099
  stateRef.current = { status, error };
@@ -10127,56 +10119,115 @@ function useChannel(url, config = {}) {
10127
10119
  };
10128
10120
  }
10129
10121
 
10130
- // src/react/useAppSession.ts
10131
- import { useRef as useRef3, useEffect as useEffect4, useSyncExternalStore as useSyncExternalStore3, useCallback as useCallback4 } from "react";
10132
- function useAppSession(config = {}) {
10133
- const { hostClient, initialState, id } = config;
10134
- const sessionRef = useRef3(null);
10135
- if (!sessionRef.current) {
10136
- sessionRef.current = new AppSession(initialState, { id });
10137
- }
10138
- const session = sessionRef.current;
10122
+ // src/react/CreatureIcon.tsx
10123
+ import { useState as useState3, useEffect as useEffect4, useRef as useRef3 } from "react";
10124
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
10125
+ function CreatureIcon({
10126
+ isDarkMode,
10127
+ showEyes = true,
10128
+ enableBlink = false,
10129
+ width = 26,
10130
+ height = 26,
10131
+ className = ""
10132
+ }) {
10133
+ const fillColor = isDarkMode ? "#F8F7F6" : "#0D0D0C";
10134
+ const [isBlinking, setIsBlinking] = useState3(false);
10135
+ const timeoutRef = useRef3(null);
10139
10136
  useEffect4(() => {
10140
- if (hostClient) {
10141
- const unbind = session.bindHost(hostClient);
10142
- return unbind;
10143
- }
10144
- }, [session, hostClient]);
10145
- const subscribe = useCallback4(
10146
- (onStoreChange) => session.subscribe(onStoreChange),
10147
- [session]
10148
- );
10149
- const getSnapshot = useCallback4(() => session.state, [session]);
10150
- const state = useSyncExternalStore3(subscribe, getSnapshot, getSnapshot);
10151
- const setUi = useCallback4((ui2) => session.setUi(ui2), [session]);
10152
- const updateUi = useCallback4(
10153
- (partial) => session.updateUi(partial),
10154
- [session]
10137
+ if (!enableBlink || !showEyes) {
10138
+ return;
10139
+ }
10140
+ const scheduleNextBlink = () => {
10141
+ const nextBlinkDelay = Math.random() * 4e3 + 2e3;
10142
+ timeoutRef.current = setTimeout(() => {
10143
+ setIsBlinking(true);
10144
+ setTimeout(() => {
10145
+ setIsBlinking(false);
10146
+ scheduleNextBlink();
10147
+ }, 150);
10148
+ }, nextBlinkDelay);
10149
+ };
10150
+ scheduleNextBlink();
10151
+ return () => {
10152
+ if (timeoutRef.current) {
10153
+ clearTimeout(timeoutRef.current);
10154
+ }
10155
+ };
10156
+ }, [enableBlink, showEyes]);
10157
+ return /* @__PURE__ */ jsxs(
10158
+ "svg",
10159
+ {
10160
+ width,
10161
+ height,
10162
+ viewBox: "0 0 110 111",
10163
+ fill: "none",
10164
+ xmlns: "http://www.w3.org/2000/svg",
10165
+ className,
10166
+ children: [
10167
+ /* @__PURE__ */ jsx(
10168
+ "path",
10169
+ {
10170
+ fillRule: "evenodd",
10171
+ clipRule: "evenodd",
10172
+ d: "M76.7407 18.0698L69.6709 0L47.7099 28.6693L11.7829 31.4596L8.12513 55.4302L15.3684 62.8469L21.6574 63.9457L0 88.9139C11.8118 94.2343 23.6381 99.5546 35.4499 104.861L54.2013 93.3813L62.7746 105.265L71.5215 110.889L87.5115 105.439L85.0537 85.1115L100.971 91.1693L109.053 74.5286L106.812 62.0084L94.7692 52.4953L101.608 26.3995L98.0532 1.81982L78.3892 18.2808L76.7407 18.0698ZM76.5816 94.1909L71.2034 65.0011L95.6366 73.5166L101.318 63.1072L80.9622 47.0159C84.5477 35.4354 88.191 23.826 91.5452 12.1877L77.1744 24.5698L69.6709 23.4566L68.3264 8.84802L49.9797 32.7897L15.5563 35.4643L13.113 51.4544L36.621 53.2616L7.08419 87.338L24.6212 95.2318L48.1147 77.5069L64.2348 99.8582L76.6105 94.1764L76.5816 94.1909Z",
10173
+ fill: fillColor
10174
+ }
10175
+ ),
10176
+ showEyes && /* @__PURE__ */ jsxs(Fragment, { children: [
10177
+ /* @__PURE__ */ jsx(
10178
+ "g",
10179
+ {
10180
+ style: {
10181
+ transformOrigin: "64px 33.65px",
10182
+ transform: isBlinking ? "scaleY(0.1)" : "scaleY(1)",
10183
+ transition: "transform 0.1s ease-out"
10184
+ },
10185
+ children: /* @__PURE__ */ jsx(
10186
+ "path",
10187
+ {
10188
+ d: "M65.6051 34.48C66.4951 32.97 66.6051 31.3799 65.8451 30.9299C65.0851 30.4899 63.7451 31.3499 62.8551 32.8699C61.9651 34.3799 61.8551 35.97 62.6151 36.42C63.3751 36.86 64.7151 36 65.6051 34.48Z",
10189
+ fill: fillColor
10190
+ }
10191
+ )
10192
+ }
10193
+ ),
10194
+ /* @__PURE__ */ jsx(
10195
+ "g",
10196
+ {
10197
+ style: {
10198
+ transformOrigin: "70px 36.265px",
10199
+ transform: isBlinking ? "scaleY(0.1)" : "scaleY(1)",
10200
+ transition: "transform 0.1s ease-out"
10201
+ },
10202
+ children: /* @__PURE__ */ jsx(
10203
+ "path",
10204
+ {
10205
+ d: "M71.7651 37.0999C72.6951 35.1499 72.6551 33.1899 71.6751 32.73C70.6951 32.27 69.1551 33.4799 68.2351 35.4299C67.3051 37.3799 67.3451 39.3399 68.3251 39.7999C69.3051 40.2599 70.8451 39.0499 71.7651 37.0999Z",
10206
+ fill: fillColor
10207
+ }
10208
+ )
10209
+ }
10210
+ )
10211
+ ] })
10212
+ ]
10213
+ }
10155
10214
  );
10156
- return {
10157
- session,
10158
- state,
10159
- ui: state.ui,
10160
- setUi,
10161
- updateUi
10162
- };
10163
10215
  }
10164
10216
  export {
10165
- AppSession,
10166
- ChatGPTHostClient,
10167
- McpHostClient,
10217
+ ChatGptAppHostClient,
10218
+ CreatureIcon,
10219
+ McpAppHostClient,
10168
10220
  WidgetStateContext,
10169
10221
  YU as applyDocumentTheme,
10170
10222
  qU as applyHostFonts,
10171
10223
  QU as applyHostStyleVariables,
10172
- createChannel,
10173
10224
  createHost,
10225
+ createWebSocket,
10174
10226
  detectEnvironment,
10175
10227
  VU as getDocumentTheme,
10176
- useAppSession,
10177
- useChannel,
10178
10228
  useHost,
10179
10229
  useToolResult,
10230
+ useWebSocket,
10180
10231
  useWidgetState
10181
10232
  };
10182
10233
  //# sourceMappingURL=index.js.map