@apollo/client-ai-apps 0.2.4 → 0.3.1

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 (72) hide show
  1. package/.git-blame-ignore-revs +2 -0
  2. package/.github/workflows/compare-build-output.yml +28 -0
  3. package/.github/workflows/pr.yaml +23 -15
  4. package/.github/workflows/release.yaml +46 -46
  5. package/.prettierrc +9 -0
  6. package/config/compare-build-output-to.sh +90 -0
  7. package/dist/core/ApolloClient.d.ts +14 -0
  8. package/dist/index.d.ts +17 -10
  9. package/dist/index.js +164 -62
  10. package/dist/link/ToolCallLink.d.ts +26 -0
  11. package/dist/react/ApolloProvider.d.ts +9 -0
  12. package/dist/react/context/ToolUseContext.d.ts +15 -0
  13. package/dist/{hooks → react/hooks}/useOpenAiGlobal.d.ts +1 -1
  14. package/dist/react/hooks/useOpenExternal.d.ts +3 -0
  15. package/dist/{hooks → react/hooks}/useRequestDisplayMode.d.ts +1 -1
  16. package/dist/{hooks → react/hooks}/useToolEffect.d.ts +0 -4
  17. package/dist/react/hooks/useToolOutput.d.ts +1 -0
  18. package/dist/react/hooks/useToolResponseMetadata.d.ts +1 -0
  19. package/dist/react/hooks/useWidgetState.d.ts +4 -0
  20. package/dist/types/openai.d.ts +1 -2
  21. package/dist/vite/index.js +74 -21
  22. package/package.json +9 -2
  23. package/scripts/dev.mjs +3 -1
  24. package/src/core/ApolloClient.ts +108 -0
  25. package/src/{apollo_client/client.test.ts → core/__tests__/ApolloClient.test.ts} +232 -20
  26. package/src/index.ts +36 -10
  27. package/src/link/ToolCallLink.ts +49 -0
  28. package/src/{apollo_client/provider.tsx → react/ApolloProvider.tsx} +19 -9
  29. package/src/{apollo_client/provider.test.tsx → react/__tests__/ApolloProvider.test.tsx} +9 -9
  30. package/src/react/context/ToolUseContext.tsx +30 -0
  31. package/src/{hooks → react/hooks/__tests__}/useCallTool.test.ts +1 -1
  32. package/src/{hooks → react/hooks/__tests__}/useOpenAiGlobal.test.ts +5 -3
  33. package/src/react/hooks/__tests__/useOpenExternal.test.tsx +24 -0
  34. package/src/{hooks → react/hooks/__tests__}/useRequestDisplayMode.test.ts +2 -2
  35. package/src/{hooks → react/hooks/__tests__}/useSendFollowUpMessage.test.ts +4 -2
  36. package/src/{hooks → react/hooks/__tests__}/useToolEffect.test.tsx +27 -10
  37. package/src/{hooks → react/hooks/__tests__}/useToolInput.test.ts +1 -1
  38. package/src/{hooks → react/hooks/__tests__}/useToolName.test.ts +1 -1
  39. package/src/react/hooks/__tests__/useToolOutput.test.tsx +49 -0
  40. package/src/react/hooks/__tests__/useToolResponseMetadata.test.tsx +49 -0
  41. package/src/react/hooks/__tests__/useWidgetState.test.tsx +158 -0
  42. package/src/react/hooks/useCallTool.ts +13 -0
  43. package/src/{hooks → react/hooks}/useOpenAiGlobal.ts +11 -5
  44. package/src/react/hooks/useOpenExternal.ts +11 -0
  45. package/src/{hooks → react/hooks}/useRequestDisplayMode.ts +1 -1
  46. package/src/react/hooks/useToolEffect.tsx +37 -0
  47. package/src/{hooks → react/hooks}/useToolName.ts +1 -1
  48. package/src/react/hooks/useToolOutput.ts +5 -0
  49. package/src/react/hooks/useToolResponseMetadata.ts +5 -0
  50. package/src/react/hooks/useWidgetState.ts +48 -0
  51. package/src/testing/internal/index.ts +2 -0
  52. package/src/testing/internal/matchers/index.d.ts +9 -0
  53. package/src/testing/internal/matchers/index.ts +1 -0
  54. package/src/testing/internal/matchers/toRerender.ts +49 -0
  55. package/src/testing/internal/openai/dispatchStateChange.ts +9 -0
  56. package/src/testing/internal/openai/stubOpenAiGlobals.ts +13 -0
  57. package/src/types/openai.ts +6 -3
  58. package/src/vite/{absolute_asset_imports_plugin.test.ts → __tests__/absolute_asset_imports_plugin.test.ts} +4 -2
  59. package/src/vite/{application_manifest_plugin.test.ts → __tests__/application_manifest_plugin.test.ts} +176 -53
  60. package/src/vite/absolute_asset_imports_plugin.ts +3 -1
  61. package/src/vite/application_manifest_plugin.ts +84 -24
  62. package/vitest-setup.ts +1 -0
  63. package/dist/apollo_client/client.d.ts +0 -14
  64. package/dist/apollo_client/provider.d.ts +0 -5
  65. package/src/apollo_client/client.ts +0 -90
  66. package/src/hooks/useCallTool.ts +0 -8
  67. package/src/hooks/useToolEffect.tsx +0 -41
  68. /package/dist/{hooks → react/hooks}/useSendFollowUpMessage.d.ts +0 -0
  69. /package/dist/{hooks → react/hooks}/useToolInput.d.ts +0 -0
  70. /package/dist/{hooks → react/hooks}/useToolName.d.ts +0 -0
  71. /package/src/{hooks → react/hooks}/useSendFollowUpMessage.ts +0 -0
  72. /package/src/{hooks → react/hooks}/useToolInput.ts +0 -0
@@ -0,0 +1,2 @@
1
+ # Run prettier on the repo
2
+ 22f22733a5c5f98266b3817767739d6968e8014e
@@ -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 }}
@@ -1,24 +1,32 @@
1
1
  name: Build on PR
2
2
 
3
3
  on:
4
- pull_request:
5
- types: [opened, synchronize, reopened]
4
+ pull_request:
5
+ types: [opened, synchronize, reopened]
6
6
 
7
7
  jobs:
8
- build:
9
- runs-on: ubuntu-latest
8
+ build:
9
+ runs-on: ubuntu-latest
10
10
 
11
- steps:
12
- - name: Checkout code
13
- uses: actions/checkout@v4
11
+ steps:
12
+ - name: Checkout code
13
+ uses: actions/checkout@v4
14
14
 
15
- - name: Set up Node.js
16
- uses: actions/setup-node@v4
17
- with:
18
- node-version: 20.x
15
+ - name: Set up Node.js
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: 20.x
19
19
 
20
- - name: Install dependencies
21
- run: npm ci
20
+ - name: Install dependencies
21
+ run: npm ci
22
22
 
23
- - name: Run build
24
- run: npm run build
23
+ - name: Run build
24
+ run: npm run build
25
+
26
+ - name: Test
27
+ shell: bash
28
+ run: npm run test
29
+
30
+ - name: Check formatting
31
+ shell: bash
32
+ run: npm run format:check
@@ -1,53 +1,53 @@
1
1
  name: Release new Version
2
2
 
3
3
  on:
4
- workflow_dispatch:
4
+ workflow_dispatch:
5
5
 
6
6
  permissions:
7
- contents: write
8
- id-token: write # Required for OIDC
7
+ contents: write
8
+ id-token: write # Required for OIDC
9
9
 
10
10
  jobs:
11
- release:
12
- name: Release
13
- if: github.repository == 'apollographql/apollo-ai-apps-client'
14
- runs-on: ubuntu-latest
15
- steps:
16
- - uses: actions/checkout@v4
17
-
18
- - name: Setup Node.js 20.x
19
- uses: actions/setup-node@v4
20
- with:
21
- node-version: ">=23.6.0"
22
- registry-url: "https://registry.npmjs.org/"
23
- env:
24
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
25
-
26
- - name: Install dependencies
27
- shell: bash
28
- run: npm ci
29
-
30
- - name: Build
31
- shell: bash
32
- run: npm run build
33
-
34
- - name: Test
35
- shell: bash
36
- run: npm run test
37
-
38
- - name: Configure Git
39
- run: |
40
- git config --global user.name GitHub Actions
41
- git config user.email github-actions@github.com
42
-
43
- - uses: knope-dev/action@v2.1.0
44
- with:
45
- version: 0.21.5
46
-
47
- - run: knope release
48
- env:
49
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50
-
51
- - name: Publish to npm
52
- shell: bash
53
- run: npm publish --provenance --access public
11
+ release:
12
+ name: Release
13
+ if: github.repository == 'apollographql/apollo-ai-apps-client'
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Setup Node.js 20.x
19
+ uses: actions/setup-node@v4
20
+ with:
21
+ node-version: ">=23.6.0"
22
+ registry-url: "https://registry.npmjs.org/"
23
+ env:
24
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
25
+
26
+ - name: Install dependencies
27
+ shell: bash
28
+ run: npm ci
29
+
30
+ - name: Build
31
+ shell: bash
32
+ run: npm run build
33
+
34
+ - name: Test
35
+ shell: bash
36
+ run: npm run test
37
+
38
+ - name: Configure Git
39
+ run: |
40
+ git config --global user.name GitHub Actions
41
+ git config user.email github-actions@github.com
42
+
43
+ - uses: knope-dev/action@v2.1.0
44
+ with:
45
+ version: 0.21.5
46
+
47
+ - run: knope release
48
+ env:
49
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
50
+
51
+ - name: Publish to npm
52
+ shell: bash
53
+ run: npm publish --provenance --access public
package/.prettierrc ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "bracketSpacing": true,
3
+ "printWidth": 80,
4
+ "semi": true,
5
+ "singleQuote": false,
6
+ "tabWidth": 2,
7
+ "trailingComma": "es5",
8
+ "experimentalTernaries": true
9
+ }
@@ -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,11 +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";
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,105 +59,188 @@ 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({ children, appName }) {
62
- const [hasNavigated, setHasNavigated] = useState(false);
63
- return /* @__PURE__ */ React.createElement(ToolUseContext.Provider, { value: { hasNavigated, setHasNavigated, appName } }, children);
64
- }
69
+ // src/react/hooks/useToolEffect.tsx
70
+ import { useEffect } from "react";
65
71
  var useToolEffect = (toolName, effect, deps = []) => {
66
- const ctx = React.useContext(ToolUseContext);
72
+ const ctx = useToolUseState();
67
73
  const fullToolName = useToolName();
68
74
  const toolInput = useToolInput();
69
- if (!ctx) throw new Error("useToolEffect must be used within ToolUseProvider");
75
+ if (!ctx)
76
+ throw new Error("useToolEffect must be used within ToolUseProvider");
70
77
  const toolNames = Array.isArray(toolName) ? toolName : [toolName];
71
78
  useEffect(() => {
72
- const matches = toolNames.some((name) => fullToolName === `${ctx.appName}--${name}`);
79
+ const matches = toolNames.some(
80
+ (name) => fullToolName === `${ctx.appName}--${name}`
81
+ );
73
82
  if (!ctx.hasNavigated && matches) {
74
83
  effect(toolInput);
75
84
  ctx.setHasNavigated(true);
76
85
  }
77
- }, [ctx.hasNavigated, ctx.setHasNavigated, ctx.appName, toolNames, fullToolName, toolInput, ...deps]);
86
+ }, [
87
+ ctx.hasNavigated,
88
+ ctx.setHasNavigated,
89
+ ctx.appName,
90
+ toolNames,
91
+ fullToolName,
92
+ toolInput,
93
+ ...deps
94
+ ]);
78
95
  };
79
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
+
80
143
  // src/index.ts
81
144
  export * from "@apollo/client";
82
145
 
83
- // src/apollo_client/client.ts
84
- import { ApolloClient, ApolloLink, InMemoryCache } from "@apollo/client";
85
- import * as Observable from "rxjs";
86
- import { selectHttpOptionsAndBody } from "@apollo/client/link/http";
87
- import { fallbackHttpConfig } from "@apollo/client/link/http";
146
+ // src/core/ApolloClient.ts
147
+ import { ApolloClient as BaseApolloClient } from "@apollo/client";
88
148
  import { DocumentTransform } from "@apollo/client";
89
149
  import { removeDirectivesFromDocument } from "@apollo/client/utilities/internal";
90
150
  import { parse } from "graphql";
91
- var toolCallLink = new ApolloLink((operation) => {
92
- const context = operation.getContext();
93
- const contextConfig = {
94
- http: context.http,
95
- options: context.fetchOptions,
96
- credentials: context.credentials,
97
- headers: context.headers
98
- };
99
- const { query, variables } = selectHttpOptionsAndBody(operation, fallbackHttpConfig, contextConfig).body;
100
- return Observable.from(window.openai.callTool("execute", { query, variables })).pipe(
101
- Observable.map((result) => ({ data: result.structuredContent.data }))
102
- );
103
- });
104
- var ExtendedApolloClient = class extends ApolloClient {
151
+ import { __DEV__ } from "@apollo/client/utilities/environment";
152
+
153
+ // src/link/ToolCallLink.ts
154
+ import { ApolloLink } from "@apollo/client";
155
+ import { from, map } from "rxjs";
156
+ import {
157
+ fallbackHttpConfig,
158
+ selectHttpOptionsAndBody
159
+ } from "@apollo/client/link/http";
160
+ var ToolCallLink = class extends ApolloLink {
161
+ request(operation) {
162
+ const context = operation.getContext();
163
+ const contextConfig = {
164
+ http: context.http,
165
+ options: context.fetchOptions,
166
+ credentials: context.credentials,
167
+ headers: context.headers
168
+ };
169
+ const { query, variables } = selectHttpOptionsAndBody(
170
+ operation,
171
+ fallbackHttpConfig,
172
+ contextConfig
173
+ ).body;
174
+ return from(window.openai.callTool("execute", { query, variables })).pipe(
175
+ map((result) => ({ data: result.structuredContent.data }))
176
+ );
177
+ }
178
+ };
179
+
180
+ // src/core/ApolloClient.ts
181
+ var ApolloClient = class extends BaseApolloClient {
105
182
  manifest;
106
183
  constructor(options) {
184
+ const link = options.link ?? new ToolCallLink();
185
+ if (__DEV__) {
186
+ validateTerminatingLink(link);
187
+ }
107
188
  super({
108
- link: toolCallLink,
109
- cache: options.cache ?? new InMemoryCache(),
189
+ ...options,
190
+ link,
110
191
  // Strip out the prefetch/tool directives so they don't get sent with the operation to the server
111
192
  documentTransform: new DocumentTransform((document) => {
112
- return removeDirectivesFromDocument([{ name: "prefetch" }, { name: "tool" }], document);
193
+ return removeDirectivesFromDocument(
194
+ [{ name: "prefetch" }, { name: "tool" }],
195
+ document
196
+ );
113
197
  })
114
198
  });
115
199
  this.manifest = options.manifest;
116
200
  }
117
201
  async prefetchData() {
118
202
  this.manifest.operations.forEach((operation) => {
119
- if (operation.prefetch && operation.prefetchID && window.openai.toolOutput.prefetch?.[operation.prefetchID]) {
203
+ if (operation.prefetch && operation.prefetchID && window.openai.toolOutput?.prefetch?.[operation.prefetchID]) {
120
204
  this.writeQuery({
121
205
  query: parse(operation.body),
122
206
  data: window.openai.toolOutput.prefetch[operation.prefetchID].data
123
207
  });
124
208
  }
125
209
  if (operation.tools?.find(
126
- (tool) => `${this.manifest.name}--${tool.name}` === window.openai.toolResponseMetadata.toolName
210
+ (tool) => `${this.manifest.name}--${tool.name}` === window.openai.toolResponseMetadata?.toolName
127
211
  )) {
128
212
  const variables = Object.keys(window.openai.toolInput).reduce(
129
- (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,
130
214
  {}
131
215
  );
132
- this.writeQuery({
133
- query: parse(operation.body),
134
- data: window.openai.toolOutput.result.data,
135
- variables
136
- });
216
+ if (window.openai.toolOutput) {
217
+ this.writeQuery({
218
+ query: parse(operation.body),
219
+ data: window.openai.toolOutput.result.data,
220
+ variables
221
+ });
222
+ }
137
223
  }
138
224
  });
139
225
  }
140
226
  };
227
+ function validateTerminatingLink(link) {
228
+ let terminatingLink = link;
229
+ while (terminatingLink.right) {
230
+ terminatingLink = terminatingLink.right;
231
+ }
232
+ if (terminatingLink.constructor.name !== "ToolCallLink") {
233
+ throw new Error(
234
+ "The terminating link must be a `ToolCallLink`. If you are using a `split` link, ensure the `right` branch uses a `ToolCallLink` as the terminating link."
235
+ );
236
+ }
237
+ }
141
238
 
142
- // src/apollo_client/provider.tsx
143
- import React2, { useEffect as useEffect2, useState as useState2 } from "react";
144
- import { ApolloProvider } from "@apollo/client/react";
145
- var ExtendedApolloProvider = ({
146
- children,
147
- client
148
- }) => {
149
- 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);
150
244
  useEffect2(() => {
151
245
  const prefetchData = async () => {
152
246
  await client.prefetchData();
@@ -159,19 +253,27 @@ var ExtendedApolloProvider = ({
159
253
  if (window.openai?.toolOutput) {
160
254
  window.dispatchEvent(new CustomEvent(SET_GLOBALS_EVENT_TYPE));
161
255
  }
162
- }, [setHasPreloaded]);
163
- return hasPreloaded ? /* @__PURE__ */ React2.createElement(ApolloProvider, { client }, children) : null;
256
+ return () => {
257
+ window.removeEventListener(SET_GLOBALS_EVENT_TYPE, prefetchData);
258
+ };
259
+ }, []);
260
+ return hasPreloaded ? /* @__PURE__ */ React3.createElement(BaseApolloProvider, { client }, children) : null;
164
261
  };
165
262
  export {
166
- ExtendedApolloClient as ApolloClient,
167
- ExtendedApolloProvider as ApolloProvider,
263
+ ApolloClient,
264
+ ApolloProvider,
168
265
  SET_GLOBALS_EVENT_TYPE,
169
266
  SetGlobalsEvent,
267
+ ToolCallLink,
170
268
  ToolUseProvider,
171
269
  useOpenAiGlobal,
270
+ useOpenExternal,
172
271
  useRequestDisplayMode,
173
272
  useSendFollowUpMessage,
174
273
  useToolEffect,
175
274
  useToolInput,
176
- useToolName
275
+ useToolName,
276
+ useToolOutput,
277
+ useToolResponseMetadata,
278
+ useWidgetState
177
279
  };