Skip to content

πŸ› Bug Report: OpenAI Hooks Missing or Not WorkingΒ #4

@JakeLin

Description

@JakeLin

Description

The README advertises these hooks but they're either not exported or not implemented:

useOpenAiGlobal()  // ❌ Not found
useWidgetState()   // ❌ Not found
useMaxHeight()     // ❌ Not found

Current Behavior

import { useOpenAiGlobal } from '@ainativekit/ui';
// Error: Module '"@ainativekit/ui"' has no exported member 'useOpenAiGlobal'

Expected Behavior

Hooks should be available and functional as documented.

Proposed Implementation

File: packages/ui/src/hooks/openai/useOpenAiGlobal.ts

import { useEffect, useState } from 'react';
import type { OpenAIGlobal } from '../../types/global';

/**
 * Access the ChatGPT Apps SDK global object
 * @returns OpenAI global object or undefined if not in ChatGPT
 */
export function useOpenAiGlobal(): OpenAIGlobal | undefined {
  const [openai, setOpenai] = useState<OpenAIGlobal | undefined>(
    typeof window !== 'undefined' ? window.openai : undefined
  );

  useEffect(() => {
    // Update if window.openai changes
    if (typeof window !== 'undefined') {
      setOpenai(window.openai);
    }
  }, []);

  return openai;
}

File: packages/ui/src/hooks/openai/useTheme.ts

import { useEffect, useState } from 'react';

/**
 * Get current theme and listen for changes
 * @returns 'light' | 'dark'
 */
export function useTheme(): 'light' | 'dark' {
  const [theme, setTheme] = useState<'light' | 'dark'>(() => {
    if (typeof window === 'undefined') return 'light';
    return window.openai?.theme || 'light';
  });

  useEffect(() => {
    const handleThemeChange = () => {
      setTheme(window.openai?.theme || 'light');
    };

    // Poll for theme changes (if no event system)
    const interval = setInterval(handleThemeChange, 1000);

    return () => clearInterval(interval);
  }, []);

  return theme;
}

File: packages/ui/src/hooks/openai/useWidgetState.ts

import { useCallback, useEffect, useState } from 'react';

/**
 * Persist state in ChatGPT widget state
 * @param key - State key
 * @param defaultValue - Default value
 * @returns [state, setState]
 */
export function useWidgetState<T>(
  key: string,
  defaultValue: T
): [T, (value: T) => void] {
  const [state, setState] = useState<T>(() => {
    if (typeof window === 'undefined') return defaultValue;
    const widgetState = window.openai?.widgetState;
    return widgetState?.[key] ?? defaultValue;
  });

  const updateState = useCallback(
    (value: T) => {
      setState(value);

      if (typeof window !== 'undefined' && window.openai?.setWidgetState) {
        window.openai.setWidgetState({
          ...window.openai.widgetState,
          [key]: value,
        });
      }
    },
    [key]
  );

  return [state, updateState];
}

File: packages/ui/src/hooks/openai/useMaxHeight.ts

import { useEffect, useState } from 'react';

/**
 * Get maximum height for widget layout
 * @returns max height in pixels
 */
export function useMaxHeight(): number {
  const [maxHeight, setMaxHeight] = useState(600);

  useEffect(() => {
    const updateHeight = () => {
      const displayMode = window.openai?.displayMode;

      switch (displayMode) {
        case 'fullscreen':
          setMaxHeight(window.innerHeight - 100);
          break;
        case 'pip':
          setMaxHeight(400);
          break;
        default:
          setMaxHeight(600);
      }
    };

    updateHeight();
    window.addEventListener('resize', updateHeight);

    return () => window.removeEventListener('resize', updateHeight);
  }, []);

  return maxHeight;
}

Export from: packages/ui/src/hooks/openai/index.ts

export { useOpenAiGlobal } from './useOpenAiGlobal';
export { useTheme } from './useTheme';
export { useWidgetState } from './useWidgetState';
export { useMaxHeight } from './useMaxHeight';

Export from: packages/ui/src/index.ts

export * from './hooks/openai';

Usage Example

import { useOpenAiGlobal, useWidgetState, useTheme } from '@ainativekit/ui';

function MyWidget() {
  const openai = useOpenAiGlobal();
  const theme = useTheme();
  const [favorites, setFavorites] = useWidgetState<string[]>('favorites', []);

  return (
    <div data-theme={theme}>
      {openai ? 'Running in ChatGPT' : 'Development mode'}
    </div>
  );
}

Testing Checklist

  • All hooks export correctly
  • Hooks work in ChatGPT environment
  • Hooks work in development (no window.openai)
  • TypeScript types are correct
  • SSR-safe (no window access during import)
  • Documentation updated

Priority

🟑 Medium - Promised features not working

Labels

bug, hooks, openai, dx

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions