@apollo/client-ai-apps 0.3.0 → 0.3.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.
Files changed (63) hide show
  1. package/.github/workflows/compare-build-output.yml +28 -0
  2. package/config/compare-build-output-to.sh +90 -0
  3. package/dist/core/ApolloClient.d.ts +14 -0
  4. package/dist/index.d.ts +17 -11
  5. package/dist/index.js +96 -44
  6. package/dist/react/ApolloProvider.d.ts +9 -0
  7. package/dist/react/context/ToolUseContext.d.ts +15 -0
  8. package/dist/{hooks → react/hooks}/useOpenAiGlobal.d.ts +1 -1
  9. package/dist/react/hooks/useOpenExternal.d.ts +3 -0
  10. package/dist/{hooks → react/hooks}/useRequestDisplayMode.d.ts +1 -1
  11. package/dist/{hooks → react/hooks}/useToolEffect.d.ts +0 -4
  12. package/dist/react/hooks/useToolOutput.d.ts +1 -0
  13. package/dist/react/hooks/useToolResponseMetadata.d.ts +1 -0
  14. package/dist/react/hooks/useWidgetState.d.ts +4 -0
  15. package/dist/types/openai.d.ts +1 -2
  16. package/dist/vite/index.js +5 -0
  17. package/package.json +5 -1
  18. package/src/{apollo_client/client.ts → core/ApolloClient.ts} +21 -17
  19. package/src/{apollo_client/client.test.ts → core/__tests__/ApolloClient.test.ts} +8 -9
  20. package/src/index.ts +36 -11
  21. package/src/{apollo_client/provider.tsx → react/ApolloProvider.tsx} +12 -8
  22. package/src/{apollo_client/provider.test.tsx → react/__tests__/ApolloProvider.test.tsx} +9 -9
  23. package/src/react/context/ToolUseContext.tsx +30 -0
  24. package/src/{hooks → react/hooks/__tests__}/useCallTool.test.ts +1 -1
  25. package/src/{hooks → react/hooks/__tests__}/useOpenAiGlobal.test.ts +2 -2
  26. package/src/react/hooks/__tests__/useOpenExternal.test.tsx +24 -0
  27. package/src/{hooks → react/hooks/__tests__}/useRequestDisplayMode.test.ts +2 -2
  28. package/src/{hooks → react/hooks/__tests__}/useSendFollowUpMessage.test.ts +1 -1
  29. package/src/{hooks → react/hooks/__tests__}/useToolEffect.test.tsx +2 -1
  30. package/src/{hooks → react/hooks/__tests__}/useToolInput.test.ts +1 -1
  31. package/src/{hooks → react/hooks/__tests__}/useToolName.test.ts +1 -1
  32. package/src/react/hooks/__tests__/useToolOutput.test.tsx +49 -0
  33. package/src/react/hooks/__tests__/useToolResponseMetadata.test.tsx +49 -0
  34. package/src/react/hooks/__tests__/useWidgetState.test.tsx +158 -0
  35. package/src/{hooks → react/hooks}/useOpenAiGlobal.ts +4 -4
  36. package/src/react/hooks/useOpenExternal.ts +11 -0
  37. package/src/{hooks → react/hooks}/useRequestDisplayMode.ts +1 -1
  38. package/src/{hooks → react/hooks}/useToolEffect.tsx +3 -26
  39. package/src/{hooks → react/hooks}/useToolName.ts +1 -1
  40. package/src/react/hooks/useToolOutput.ts +5 -0
  41. package/src/react/hooks/useToolResponseMetadata.ts +5 -0
  42. package/src/react/hooks/useWidgetState.ts +48 -0
  43. package/src/testing/internal/index.ts +2 -0
  44. package/src/testing/internal/matchers/index.d.ts +9 -0
  45. package/src/testing/internal/matchers/index.ts +1 -0
  46. package/src/testing/internal/matchers/toRerender.ts +49 -0
  47. package/src/testing/internal/openai/dispatchStateChange.ts +9 -0
  48. package/src/testing/internal/openai/stubOpenAiGlobals.ts +13 -0
  49. package/src/types/openai.ts +1 -1
  50. package/src/vite/{absolute_asset_imports_plugin.test.ts → __tests__/absolute_asset_imports_plugin.test.ts} +1 -1
  51. package/src/vite/{application_manifest_plugin.test.ts → __tests__/application_manifest_plugin.test.ts} +33 -7
  52. package/src/vite/application_manifest_plugin.ts +6 -0
  53. package/vitest-setup.ts +1 -0
  54. package/dist/apollo_client/client.d.ts +0 -13
  55. package/dist/apollo_client/provider.d.ts +0 -5
  56. /package/dist/{apollo_client/link → link}/ToolCallLink.d.ts +0 -0
  57. /package/dist/{hooks → react/hooks}/useSendFollowUpMessage.d.ts +0 -0
  58. /package/dist/{hooks → react/hooks}/useToolInput.d.ts +0 -0
  59. /package/dist/{hooks → react/hooks}/useToolName.d.ts +0 -0
  60. /package/src/{apollo_client/link → link}/ToolCallLink.ts +0 -0
  61. /package/src/{hooks → react/hooks}/useCallTool.ts +0 -0
  62. /package/src/{hooks → react/hooks}/useSendFollowUpMessage.ts +0 -0
  63. /package/src/{hooks → react/hooks}/useToolInput.ts +0 -0
@@ -0,0 +1,28 @@
1
+ name: Compare Build Output
2
+ on:
3
+ pull_request:
4
+
5
+ concurrency: ${{ github.workflow }}-${{ github.ref }}
6
+
7
+ jobs:
8
+ comparebuildoutput:
9
+ name: Compare Build Output
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout repo
13
+ uses: actions/checkout@v5
14
+ with:
15
+ # Fetch entire git history so we have the parent commit to compare against
16
+ fetch-depth: 0
17
+ - name: Setup Node.js
18
+ uses: actions/setup-node@v6
19
+ with:
20
+ node-version: ">=23.6.0"
21
+ - name: Install dependencies (with cache)
22
+ uses: bahmutov/npm-install@v1
23
+
24
+ - name: Run comparison script
25
+ id: attw
26
+ run: ./config/compare-build-output-to.sh $(git merge-base HEAD origin/${{ github.base_ref }}) | tee $GITHUB_STEP_SUMMARY
27
+ env:
28
+ RUNNER_TEMP: ${{ runner.temp }}
@@ -0,0 +1,90 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ upstream=$1
4
+ comparison="${RUNNER_TEMP:-/tmp}/comparison_checkout"
5
+ root=$(git rev-parse --show-toplevel)
6
+
7
+ temp=$(mktemp --tmpdir="${RUNNER_TEMP:-/tmp}")
8
+ trap 'rm -f "$temp"' EXIT
9
+
10
+ patterndiff(){
11
+ cd dist || { echo "dist folder not found"; exit 1; }
12
+ count=0
13
+ while IFS= read -r -d '' file
14
+ do
15
+ if ! filediff="$(diff <(tr "'" '"' < "$comparison/dist/$file") <(tr "'" '"' < "$root/dist/$file"))"; then
16
+ (( count++ ))
17
+ echo "$file"
18
+ if [[ "$file" == *.min.* ]]; then
19
+ echo "> Minified file differs."
20
+ else
21
+ echo "$filediff"
22
+ fi
23
+ fi
24
+ done >"$temp" < <(find . -name "$1" -print0)
25
+
26
+ output="$(cat <"$temp")"
27
+
28
+ cat <<EOF
29
+
30
+ ## differences in $1 files
31
+
32
+ <details>
33
+ <summary>
34
+
35
+ ### $count files with differences
36
+
37
+ </summary>
38
+
39
+ \`\`\`diff
40
+
41
+ $output
42
+
43
+ \`\`\`
44
+
45
+ </details>
46
+ EOF
47
+
48
+ cd ..
49
+ }
50
+
51
+ [ -z "$upstream" ] && { echo "need upstream argument"; exit 1; }
52
+
53
+ git worktree add --force --detach --checkout "$comparison" "$upstream" || { cd "$comparison" && git checkout "$upstream"; } || exit 1
54
+
55
+ cd "$comparison" || { echo "checkout failed"; exit 1; }
56
+ [ -d node_modules ] || cp -r "$root/node_modules" .
57
+ npm i >&2
58
+ git status >&2
59
+ npm run build >&2
60
+ cd "$root" || exit 1
61
+ git status >&2
62
+ npm run build >&2
63
+
64
+ set +e
65
+
66
+ patterndiff "*.js"
67
+ patterndiff "*.cjs"
68
+ patterndiff "*.d.ts"
69
+ patterndiff "*.d.cts"
70
+
71
+ cat <<EOF
72
+
73
+ ## differences in other files
74
+
75
+ <details>
76
+ <summary>
77
+
78
+ ### $(diff -qr "$comparison/dist" "dist" -x "*.map" -x "*.native.*" -x "*.js" -x "*.cjs" -x "*.d.ts" -x "*.d.cts" -w | wc -l) files with differences
79
+
80
+ </summary>
81
+
82
+ \`\`\`diff
83
+
84
+ $(diff -r "$comparison/dist" "dist" -x "*.map" -x "*.native.*" -x "*.js" -x "*.cjs" -x "*.d.ts" -x "*.d.cts" -w)
85
+
86
+ \`\`\`
87
+
88
+ </details>
89
+ EOF
90
+
@@ -0,0 +1,14 @@
1
+ import { ApolloClient as BaseApolloClient } from "@apollo/client";
2
+ import "../types/openai";
3
+ import { ApplicationManifest } from "../types/application-manifest";
4
+ export declare namespace ApolloClient {
5
+ interface Options extends Omit<BaseApolloClient.Options, "link"> {
6
+ link?: BaseApolloClient.Options["link"];
7
+ manifest: ApplicationManifest;
8
+ }
9
+ }
10
+ export declare class ApolloClient extends BaseApolloClient {
11
+ manifest: ApplicationManifest;
12
+ constructor(options: ApolloClient.Options);
13
+ prefetchData(): Promise<void>;
14
+ }
package/dist/index.d.ts CHANGED
@@ -1,12 +1,18 @@
1
- export * from "./types/openai";
2
- export * from "./types/application-manifest";
3
- export * from "./hooks/useOpenAiGlobal";
4
- export * from "./hooks/useToolName";
5
- export * from "./hooks/useToolInput";
6
- export * from "./hooks/useSendFollowUpMessage";
7
- export * from "./hooks/useRequestDisplayMode";
8
- export * from "./hooks/useToolEffect";
1
+ export type { API, CallTool, DeviceType, DisplayMode, OpenAiGlobals, SafeArea, SafeAreaInsets, Theme, UserAgent, UnknownObject, } from "./types/openai";
2
+ export { SET_GLOBALS_EVENT_TYPE, SetGlobalsEvent } from "./types/openai";
3
+ export type { ApplicationManifest, ManifestOperation, ManifestTool, ManifestExtraInput, ManifestCsp, } from "./types/application-manifest";
4
+ export { ToolUseProvider } from "./react/context/ToolUseContext";
5
+ export { useOpenAiGlobal } from "./react/hooks/useOpenAiGlobal";
6
+ export { useToolName } from "./react/hooks/useToolName";
7
+ export { useToolInput } from "./react/hooks/useToolInput";
8
+ export { useSendFollowUpMessage } from "./react/hooks/useSendFollowUpMessage";
9
+ export { useRequestDisplayMode } from "./react/hooks/useRequestDisplayMode";
10
+ export { useToolEffect } from "./react/hooks/useToolEffect";
11
+ export { useOpenExternal } from "./react/hooks/useOpenExternal";
12
+ export { useToolOutput } from "./react/hooks/useToolOutput";
13
+ export { useToolResponseMetadata } from "./react/hooks/useToolResponseMetadata";
14
+ export { useWidgetState } from "./react/hooks/useWidgetState";
9
15
  export * from "@apollo/client";
10
- export { ExtendedApolloClient as ApolloClient } from "./apollo_client/client";
11
- export { ExtendedApolloProvider as ApolloProvider } from "./apollo_client/provider";
12
- export { ToolCallLink } from "./apollo_client/link/ToolCallLink";
16
+ export { ApolloClient } from "./core/ApolloClient";
17
+ export { ApolloProvider } from "./react/ApolloProvider";
18
+ export { ToolCallLink } from "./link/ToolCallLink";
package/dist/index.js CHANGED
@@ -4,11 +4,22 @@ var SetGlobalsEvent = class extends CustomEvent {
4
4
  type = SET_GLOBALS_EVENT_TYPE;
5
5
  };
6
6
 
7
- // src/hooks/useOpenAiGlobal.ts
8
- import { useSyncExternalStore } from "react";
7
+ // src/react/context/ToolUseContext.tsx
8
+ import React, { createContext, useContext, useState } from "react";
9
+ var ToolUseContext = createContext(null);
10
+ function ToolUseProvider({ children, appName }) {
11
+ const [hasNavigated, setHasNavigated] = useState(false);
12
+ return /* @__PURE__ */ React.createElement(ToolUseContext.Provider, { value: { hasNavigated, setHasNavigated, appName } }, children);
13
+ }
14
+ function useToolUseState() {
15
+ return useContext(ToolUseContext);
16
+ }
17
+
18
+ // src/react/hooks/useOpenAiGlobal.ts
19
+ import { useSyncExternalStore, useCallback } from "react";
9
20
  function useOpenAiGlobal(key) {
10
21
  return useSyncExternalStore(
11
- (onChange) => {
22
+ useCallback((onChange) => {
12
23
  const handleSetGlobal = (event) => {
13
24
  const value = event.detail.globals[key];
14
25
  if (value === void 0) {
@@ -22,24 +33,24 @@ function useOpenAiGlobal(key) {
22
33
  return () => {
23
34
  window.removeEventListener(SET_GLOBALS_EVENT_TYPE, handleSetGlobal);
24
35
  };
25
- },
36
+ }, []),
26
37
  () => window.openai[key]
27
38
  );
28
39
  }
29
40
 
30
- // src/hooks/useToolName.ts
41
+ // src/react/hooks/useToolName.ts
31
42
  var useToolName = () => {
32
43
  const toolResponseMetadata = useOpenAiGlobal("toolResponseMetadata");
33
44
  return toolResponseMetadata?.toolName;
34
45
  };
35
46
 
36
- // src/hooks/useToolInput.ts
47
+ // src/react/hooks/useToolInput.ts
37
48
  var useToolInput = () => {
38
49
  const toolInput = useOpenAiGlobal("toolInput");
39
50
  return toolInput;
40
51
  };
41
52
 
42
- // src/hooks/useSendFollowUpMessage.ts
53
+ // src/react/hooks/useSendFollowUpMessage.ts
43
54
  var useSendFollowUpMessage = () => {
44
55
  return async (prompt) => {
45
56
  await window.openai?.sendFollowUpMessage({
@@ -48,25 +59,17 @@ var useSendFollowUpMessage = () => {
48
59
  };
49
60
  };
50
61
 
51
- // src/hooks/useRequestDisplayMode.ts
62
+ // src/react/hooks/useRequestDisplayMode.ts
52
63
  var useRequestDisplayMode = () => {
53
64
  return async (args) => {
54
65
  return await window.openai?.requestDisplayMode(args);
55
66
  };
56
67
  };
57
68
 
58
- // src/hooks/useToolEffect.tsx
59
- import React, { useEffect, useState } from "react";
60
- var ToolUseContext = React.createContext(null);
61
- function ToolUseProvider({
62
- children,
63
- appName
64
- }) {
65
- const [hasNavigated, setHasNavigated] = useState(false);
66
- return /* @__PURE__ */ React.createElement(ToolUseContext.Provider, { value: { hasNavigated, setHasNavigated, appName } }, children);
67
- }
69
+ // src/react/hooks/useToolEffect.tsx
70
+ import { useEffect } from "react";
68
71
  var useToolEffect = (toolName, effect, deps = []) => {
69
- const ctx = React.useContext(ToolUseContext);
72
+ const ctx = useToolUseState();
70
73
  const fullToolName = useToolName();
71
74
  const toolInput = useToolInput();
72
75
  if (!ctx)
@@ -91,17 +94,63 @@ var useToolEffect = (toolName, effect, deps = []) => {
91
94
  ]);
92
95
  };
93
96
 
97
+ // src/react/hooks/useOpenExternal.ts
98
+ import { useCallback as useCallback2 } from "react";
99
+ function useOpenExternal() {
100
+ return useCallback2(
101
+ (...args) => window.openai.openExternal(...args),
102
+ []
103
+ );
104
+ }
105
+
106
+ // src/react/hooks/useToolOutput.ts
107
+ function useToolOutput() {
108
+ return useOpenAiGlobal("toolOutput") ?? null;
109
+ }
110
+
111
+ // src/react/hooks/useToolResponseMetadata.ts
112
+ function useToolResponseMetadata() {
113
+ return useOpenAiGlobal("toolResponseMetadata") ?? null;
114
+ }
115
+
116
+ // src/react/hooks/useWidgetState.ts
117
+ import { useCallback as useCallback3, useState as useState2 } from "react";
118
+ function useWidgetState(defaultState) {
119
+ const widgetStateFromWindow = useOpenAiGlobal("widgetState");
120
+ const [previousWidgetStateFromWindow, setPreviousWidgetStateFromWindow] = useState2(widgetStateFromWindow);
121
+ let [widgetState, _setWidgetState] = useState2(() => {
122
+ if (widgetStateFromWindow != null) {
123
+ return widgetStateFromWindow;
124
+ }
125
+ return typeof defaultState === "function" ? defaultState() : defaultState ?? null;
126
+ });
127
+ if (previousWidgetStateFromWindow !== widgetStateFromWindow) {
128
+ _setWidgetState(widgetState = widgetStateFromWindow);
129
+ setPreviousWidgetStateFromWindow(widgetStateFromWindow);
130
+ }
131
+ const setWidgetState = useCallback3((state) => {
132
+ _setWidgetState((prevState) => {
133
+ const newState = typeof state === "function" ? state(prevState) : state;
134
+ if (newState != null && typeof window !== "undefined") {
135
+ void window.openai?.setWidgetState?.(newState);
136
+ }
137
+ return newState;
138
+ });
139
+ }, []);
140
+ return [widgetState, setWidgetState];
141
+ }
142
+
94
143
  // src/index.ts
95
144
  export * from "@apollo/client";
96
145
 
97
- // src/apollo_client/client.ts
98
- import { ApolloClient } from "@apollo/client";
146
+ // src/core/ApolloClient.ts
147
+ import { ApolloClient as BaseApolloClient } from "@apollo/client";
99
148
  import { DocumentTransform } from "@apollo/client";
100
149
  import { removeDirectivesFromDocument } from "@apollo/client/utilities/internal";
101
150
  import { parse } from "graphql";
102
151
  import { __DEV__ } from "@apollo/client/utilities/environment";
103
152
 
104
- // src/apollo_client/link/ToolCallLink.ts
153
+ // src/link/ToolCallLink.ts
105
154
  import { ApolloLink } from "@apollo/client";
106
155
  import { from, map } from "rxjs";
107
156
  import {
@@ -128,8 +177,8 @@ var ToolCallLink = class extends ApolloLink {
128
177
  }
129
178
  };
130
179
 
131
- // src/apollo_client/client.ts
132
- var ExtendedApolloClient = class extends ApolloClient {
180
+ // src/core/ApolloClient.ts
181
+ var ApolloClient = class extends BaseApolloClient {
133
182
  manifest;
134
183
  constructor(options) {
135
184
  const link = options.link ?? new ToolCallLink();
@@ -151,24 +200,26 @@ var ExtendedApolloClient = class extends ApolloClient {
151
200
  }
152
201
  async prefetchData() {
153
202
  this.manifest.operations.forEach((operation) => {
154
- if (operation.prefetch && operation.prefetchID && window.openai.toolOutput.prefetch?.[operation.prefetchID]) {
203
+ if (operation.prefetch && operation.prefetchID && window.openai.toolOutput?.prefetch?.[operation.prefetchID]) {
155
204
  this.writeQuery({
156
205
  query: parse(operation.body),
157
206
  data: window.openai.toolOutput.prefetch[operation.prefetchID].data
158
207
  });
159
208
  }
160
209
  if (operation.tools?.find(
161
- (tool) => `${this.manifest.name}--${tool.name}` === window.openai.toolResponseMetadata.toolName
210
+ (tool) => `${this.manifest.name}--${tool.name}` === window.openai.toolResponseMetadata?.toolName
162
211
  )) {
163
212
  const variables = Object.keys(window.openai.toolInput).reduce(
164
- (obj, key) => operation.variables[key] ? { ...obj, [key]: window.openai.toolInput[key] } : obj,
213
+ (obj, key) => operation.variables?.[key] ? { ...obj, [key]: window.openai.toolInput[key] } : obj,
165
214
  {}
166
215
  );
167
- this.writeQuery({
168
- query: parse(operation.body),
169
- data: window.openai.toolOutput.result.data,
170
- variables
171
- });
216
+ if (window.openai.toolOutput) {
217
+ this.writeQuery({
218
+ query: parse(operation.body),
219
+ data: window.openai.toolOutput.result.data,
220
+ variables
221
+ });
222
+ }
172
223
  }
173
224
  });
174
225
  }
@@ -185,14 +236,11 @@ function validateTerminatingLink(link) {
185
236
  }
186
237
  }
187
238
 
188
- // src/apollo_client/provider.tsx
189
- import React2, { useEffect as useEffect2, useState as useState2 } from "react";
190
- import { ApolloProvider } from "@apollo/client/react";
191
- var ExtendedApolloProvider = ({
192
- children,
193
- client
194
- }) => {
195
- const [hasPreloaded, setHasPreloaded] = useState2(false);
239
+ // src/react/ApolloProvider.tsx
240
+ import React3, { useEffect as useEffect2, useState as useState3 } from "react";
241
+ import { ApolloProvider as BaseApolloProvider } from "@apollo/client/react";
242
+ var ApolloProvider = ({ children, client }) => {
243
+ const [hasPreloaded, setHasPreloaded] = useState3(false);
196
244
  useEffect2(() => {
197
245
  const prefetchData = async () => {
198
246
  await client.prefetchData();
@@ -209,19 +257,23 @@ var ExtendedApolloProvider = ({
209
257
  window.removeEventListener(SET_GLOBALS_EVENT_TYPE, prefetchData);
210
258
  };
211
259
  }, []);
212
- return hasPreloaded ? /* @__PURE__ */ React2.createElement(ApolloProvider, { client }, children) : null;
260
+ return hasPreloaded ? /* @__PURE__ */ React3.createElement(BaseApolloProvider, { client }, children) : null;
213
261
  };
214
262
  export {
215
- ExtendedApolloClient as ApolloClient,
216
- ExtendedApolloProvider as ApolloProvider,
263
+ ApolloClient,
264
+ ApolloProvider,
217
265
  SET_GLOBALS_EVENT_TYPE,
218
266
  SetGlobalsEvent,
219
267
  ToolCallLink,
220
268
  ToolUseProvider,
221
269
  useOpenAiGlobal,
270
+ useOpenExternal,
222
271
  useRequestDisplayMode,
223
272
  useSendFollowUpMessage,
224
273
  useToolEffect,
225
274
  useToolInput,
226
- useToolName
275
+ useToolName,
276
+ useToolOutput,
277
+ useToolResponseMetadata,
278
+ useWidgetState
227
279
  };
@@ -0,0 +1,9 @@
1
+ import React, { ReactNode } from "react";
2
+ import { ApolloClient } from "../core/ApolloClient";
3
+ export declare namespace ApolloProvider {
4
+ interface Props {
5
+ children?: ReactNode;
6
+ client: ApolloClient;
7
+ }
8
+ }
9
+ export declare const ApolloProvider: ({ children, client }: ApolloProvider.Props) => React.JSX.Element;
@@ -0,0 +1,15 @@
1
+ import React, { ReactNode } from "react";
2
+ interface ToolUseState {
3
+ appName: string;
4
+ hasNavigated: boolean;
5
+ setHasNavigated: (v: boolean) => void;
6
+ }
7
+ export declare namespace ToolUseProvider {
8
+ interface Props {
9
+ children?: ReactNode;
10
+ appName: string;
11
+ }
12
+ }
13
+ export declare function ToolUseProvider({ children, appName }: ToolUseProvider.Props): React.JSX.Element;
14
+ export declare function useToolUseState(): ToolUseState;
15
+ export {};
@@ -1,2 +1,2 @@
1
- import { OpenAiGlobals } from "../types/openai";
1
+ import { OpenAiGlobals } from "../../types/openai";
2
2
  export declare function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K];
@@ -0,0 +1,3 @@
1
+ export declare function useOpenExternal(): (payload: {
2
+ href: string;
3
+ }) => void;
@@ -1,4 +1,4 @@
1
- import { DisplayMode } from "../types/openai";
1
+ import { DisplayMode } from "../../types/openai";
2
2
  export declare const useRequestDisplayMode: () => (args: {
3
3
  mode: DisplayMode;
4
4
  }) => Promise<{
@@ -1,6 +1,2 @@
1
1
  import React from "react";
2
- export declare function ToolUseProvider({ children, appName, }: {
3
- children: any;
4
- appName: string;
5
- }): React.JSX.Element;
6
2
  export declare const useToolEffect: (toolName: string | string[], effect: (toolInput: any) => void, deps?: React.DependencyList) => void;
@@ -0,0 +1 @@
1
+ export declare function useToolOutput(): import("../..").UnknownObject;
@@ -0,0 +1 @@
1
+ export declare function useToolResponseMetadata(): import("../..").UnknownObject;
@@ -0,0 +1,4 @@
1
+ import { SetStateAction } from "react";
2
+ import { UnknownObject } from "../../types/openai";
3
+ export declare function useWidgetState<T extends UnknownObject>(defaultState: T | (() => T)): readonly [T, (state: SetStateAction<T>) => void];
4
+ export declare function useWidgetState<T extends UnknownObject>(defaultState?: T | (() => T | null) | null): readonly [T | null, (state: SetStateAction<T | null>) => void];
@@ -1,4 +1,4 @@
1
- type UnknownObject = any;
1
+ export type UnknownObject = Record<string, unknown>;
2
2
  declare global {
3
3
  interface Window {
4
4
  openai: API<any> & OpenAiGlobals;
@@ -70,4 +70,3 @@ export type UserAgent = {
70
70
  touch: boolean;
71
71
  };
72
72
  };
73
- export {};
@@ -105,6 +105,11 @@ var ApplicationManifestPlugin = () => {
105
105
  if (!name2) {
106
106
  throw new Error("'name' argument must be supplied for @tool");
107
107
  }
108
+ if (name2.indexOf(" ") > -1) {
109
+ throw new Error(
110
+ `Tool with name "${name2}" contains spaces which is not allowed.`
111
+ );
112
+ }
108
113
  if (!description) {
109
114
  throw new Error(
110
115
  "'description' argument must be supplied for @tool"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apollo/client-ai-apps",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -17,9 +17,11 @@
17
17
  },
18
18
  "scripts": {
19
19
  "dev": "node ./scripts/dev.mjs",
20
+ "prebuild": "npm run clean",
20
21
  "build": "npm run build:react && npm run build:vite",
21
22
  "build:react": "node ./scripts/build.mjs && tsc src/index.ts --emitDeclarationOnly --declaration --outDir dist --skipLibCheck --lib ES2015,DOM --target ES2015 --moduleResolution bundler --jsx react",
22
23
  "build:vite": "node ./scripts/build-vite.mjs && tsc src/vite/index.ts --emitDeclarationOnly --declaration --outDir dist/vite --skipLibCheck --lib ES2015,DOM --target ES2020 --module esnext --moduleResolution node --allowSyntheticDefaultImports",
24
+ "clean": "rimraf dist",
23
25
  "test": "vitest run --coverage",
24
26
  "test:watch": "vitest --coverage",
25
27
  "changeset": "knope document-change",
@@ -33,6 +35,7 @@
33
35
  "devDependencies": {
34
36
  "@testing-library/jest-dom": "^6.9.1",
35
37
  "@testing-library/react": "^16.3.0",
38
+ "@testing-library/react-render-stream": "^2.0.2",
36
39
  "@types/node": "^24.10.0",
37
40
  "@types/react": "^19.2.2",
38
41
  "@vitejs/plugin-react": "^5.1.1",
@@ -41,6 +44,7 @@
41
44
  "graphql": "^16.9.0",
42
45
  "happy-dom": "^20.0.10",
43
46
  "prettier": "^3.7.4",
47
+ "rimraf": "^6.1.2",
44
48
  "rxjs": "^7.8.1",
45
49
  "typescript": "^5.9.3",
46
50
  "vitest": "^4.0.13"
@@ -1,12 +1,12 @@
1
1
  import type { ApolloLink } from "@apollo/client";
2
- import { ApolloClient } from "@apollo/client";
2
+ import { ApolloClient as BaseApolloClient } from "@apollo/client";
3
3
  import { DocumentTransform } from "@apollo/client";
4
4
  import { removeDirectivesFromDocument } from "@apollo/client/utilities/internal";
5
5
  import { parse } from "graphql";
6
6
  import { __DEV__ } from "@apollo/client/utilities/environment";
7
7
  import "../types/openai";
8
8
  import { ApplicationManifest } from "../types/application-manifest";
9
- import { ToolCallLink } from "./link/ToolCallLink";
9
+ import { ToolCallLink } from "../link/ToolCallLink";
10
10
 
11
11
  // TODO: In the future if/when we support PQs again, do pqLink.concat(toolCallLink)
12
12
  // Commenting this out for now.
@@ -16,16 +16,18 @@ import { ToolCallLink } from "./link/ToolCallLink";
16
16
  // sha256: (queryString) => sha256(queryString),
17
17
  // });
18
18
 
19
- // This allows us to extend the options with the "manifest" option AND make link optional (it is normally required)
20
- type ExtendedApolloClientOptions = Omit<ApolloClient.Options, "link"> & {
21
- link?: ApolloClient.Options["link"];
22
- manifest: ApplicationManifest;
23
- };
19
+ export declare namespace ApolloClient {
20
+ // This allows us to extend the options with the "manifest" option AND make link optional (it is normally required)
21
+ export interface Options extends Omit<BaseApolloClient.Options, "link"> {
22
+ link?: BaseApolloClient.Options["link"];
23
+ manifest: ApplicationManifest;
24
+ }
25
+ }
24
26
 
25
- export class ExtendedApolloClient extends ApolloClient {
27
+ export class ApolloClient extends BaseApolloClient {
26
28
  manifest: ApplicationManifest;
27
29
 
28
- constructor(options: ExtendedApolloClientOptions) {
30
+ constructor(options: ApolloClient.Options) {
29
31
  const link = options.link ?? new ToolCallLink();
30
32
 
31
33
  if (__DEV__) {
@@ -53,7 +55,7 @@ export class ExtendedApolloClient extends ApolloClient {
53
55
  if (
54
56
  operation.prefetch &&
55
57
  operation.prefetchID &&
56
- window.openai.toolOutput.prefetch?.[operation.prefetchID]
58
+ window.openai.toolOutput?.prefetch?.[operation.prefetchID]
57
59
  ) {
58
60
  this.writeQuery({
59
61
  query: parse(operation.body),
@@ -66,24 +68,26 @@ export class ExtendedApolloClient extends ApolloClient {
66
68
  operation.tools?.find(
67
69
  (tool) =>
68
70
  `${this.manifest.name}--${tool.name}` ===
69
- window.openai.toolResponseMetadata.toolName
71
+ window.openai.toolResponseMetadata?.toolName
70
72
  )
71
73
  ) {
72
74
  // We need to include the variables that were used as part of the tool call so that we get a proper cache entry
73
75
  // However, we only want to include toolInput's that were graphql operation (ignore extraInputs)
74
76
  const variables = Object.keys(window.openai.toolInput).reduce(
75
77
  (obj, key) =>
76
- operation.variables[key] ?
78
+ operation.variables?.[key] ?
77
79
  { ...obj, [key]: window.openai.toolInput[key] }
78
80
  : obj,
79
81
  {}
80
82
  );
81
83
 
82
- this.writeQuery({
83
- query: parse(operation.body),
84
- data: window.openai.toolOutput.result.data,
85
- variables,
86
- });
84
+ if (window.openai.toolOutput) {
85
+ this.writeQuery({
86
+ query: parse(operation.body),
87
+ data: (window.openai.toolOutput.result as any).data,
88
+ variables,
89
+ });
90
+ }
87
91
  }
88
92
  });
89
93
  }