@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.
- package/.git-blame-ignore-revs +2 -0
- package/.github/workflows/compare-build-output.yml +28 -0
- package/.github/workflows/pr.yaml +23 -15
- package/.github/workflows/release.yaml +46 -46
- package/.prettierrc +9 -0
- package/config/compare-build-output-to.sh +90 -0
- package/dist/core/ApolloClient.d.ts +14 -0
- package/dist/index.d.ts +17 -10
- package/dist/index.js +164 -62
- package/dist/link/ToolCallLink.d.ts +26 -0
- package/dist/react/ApolloProvider.d.ts +9 -0
- package/dist/react/context/ToolUseContext.d.ts +15 -0
- package/dist/{hooks → react/hooks}/useOpenAiGlobal.d.ts +1 -1
- package/dist/react/hooks/useOpenExternal.d.ts +3 -0
- package/dist/{hooks → react/hooks}/useRequestDisplayMode.d.ts +1 -1
- package/dist/{hooks → react/hooks}/useToolEffect.d.ts +0 -4
- package/dist/react/hooks/useToolOutput.d.ts +1 -0
- package/dist/react/hooks/useToolResponseMetadata.d.ts +1 -0
- package/dist/react/hooks/useWidgetState.d.ts +4 -0
- package/dist/types/openai.d.ts +1 -2
- package/dist/vite/index.js +74 -21
- package/package.json +9 -2
- package/scripts/dev.mjs +3 -1
- package/src/core/ApolloClient.ts +108 -0
- package/src/{apollo_client/client.test.ts → core/__tests__/ApolloClient.test.ts} +232 -20
- package/src/index.ts +36 -10
- package/src/link/ToolCallLink.ts +49 -0
- package/src/{apollo_client/provider.tsx → react/ApolloProvider.tsx} +19 -9
- package/src/{apollo_client/provider.test.tsx → react/__tests__/ApolloProvider.test.tsx} +9 -9
- package/src/react/context/ToolUseContext.tsx +30 -0
- package/src/{hooks → react/hooks/__tests__}/useCallTool.test.ts +1 -1
- package/src/{hooks → react/hooks/__tests__}/useOpenAiGlobal.test.ts +5 -3
- package/src/react/hooks/__tests__/useOpenExternal.test.tsx +24 -0
- package/src/{hooks → react/hooks/__tests__}/useRequestDisplayMode.test.ts +2 -2
- package/src/{hooks → react/hooks/__tests__}/useSendFollowUpMessage.test.ts +4 -2
- package/src/{hooks → react/hooks/__tests__}/useToolEffect.test.tsx +27 -10
- package/src/{hooks → react/hooks/__tests__}/useToolInput.test.ts +1 -1
- package/src/{hooks → react/hooks/__tests__}/useToolName.test.ts +1 -1
- package/src/react/hooks/__tests__/useToolOutput.test.tsx +49 -0
- package/src/react/hooks/__tests__/useToolResponseMetadata.test.tsx +49 -0
- package/src/react/hooks/__tests__/useWidgetState.test.tsx +158 -0
- package/src/react/hooks/useCallTool.ts +13 -0
- package/src/{hooks → react/hooks}/useOpenAiGlobal.ts +11 -5
- package/src/react/hooks/useOpenExternal.ts +11 -0
- package/src/{hooks → react/hooks}/useRequestDisplayMode.ts +1 -1
- package/src/react/hooks/useToolEffect.tsx +37 -0
- package/src/{hooks → react/hooks}/useToolName.ts +1 -1
- package/src/react/hooks/useToolOutput.ts +5 -0
- package/src/react/hooks/useToolResponseMetadata.ts +5 -0
- package/src/react/hooks/useWidgetState.ts +48 -0
- package/src/testing/internal/index.ts +2 -0
- package/src/testing/internal/matchers/index.d.ts +9 -0
- package/src/testing/internal/matchers/index.ts +1 -0
- package/src/testing/internal/matchers/toRerender.ts +49 -0
- package/src/testing/internal/openai/dispatchStateChange.ts +9 -0
- package/src/testing/internal/openai/stubOpenAiGlobals.ts +13 -0
- package/src/types/openai.ts +6 -3
- package/src/vite/{absolute_asset_imports_plugin.test.ts → __tests__/absolute_asset_imports_plugin.test.ts} +4 -2
- package/src/vite/{application_manifest_plugin.test.ts → __tests__/application_manifest_plugin.test.ts} +176 -53
- package/src/vite/absolute_asset_imports_plugin.ts +3 -1
- package/src/vite/application_manifest_plugin.ts +84 -24
- package/vitest-setup.ts +1 -0
- package/dist/apollo_client/client.d.ts +0 -14
- package/dist/apollo_client/provider.d.ts +0 -5
- package/src/apollo_client/client.ts +0 -90
- package/src/hooks/useCallTool.ts +0 -8
- package/src/hooks/useToolEffect.tsx +0 -41
- /package/dist/{hooks → react/hooks}/useSendFollowUpMessage.d.ts +0 -0
- /package/dist/{hooks → react/hooks}/useToolInput.d.ts +0 -0
- /package/dist/{hooks → react/hooks}/useToolName.d.ts +0 -0
- /package/src/{hooks → react/hooks}/useSendFollowUpMessage.ts +0 -0
- /package/src/{hooks → react/hooks}/useToolInput.ts +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ApolloLink, Observable } from "@apollo/client";
|
|
2
|
+
/**
|
|
3
|
+
* A terminating link that sends a GraphQL request through an agent tool call.
|
|
4
|
+
* When providing a custom link chain to `ApolloClient`, `ApolloClient` will
|
|
5
|
+
* validate that the terminating link is an instance of this link.
|
|
6
|
+
*
|
|
7
|
+
* @example Provding a custom link chain
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { ApolloLink } from "@apollo/client";
|
|
11
|
+
* import { ApolloClient, ToolCallLink } from "@apollo/client-ai-apps";
|
|
12
|
+
*
|
|
13
|
+
* const link = ApolloLink.from([
|
|
14
|
+
* ...otherLinks,
|
|
15
|
+
* new ToolCallLink()
|
|
16
|
+
* ]);
|
|
17
|
+
*
|
|
18
|
+
* const client = new ApolloClient({
|
|
19
|
+
* link,
|
|
20
|
+
* // ...
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare class ToolCallLink extends ApolloLink {
|
|
25
|
+
request(operation: ApolloLink.Operation): Observable<ApolloLink.Result>;
|
|
26
|
+
}
|
|
@@ -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 "
|
|
1
|
+
import { OpenAiGlobals } from "../../types/openai";
|
|
2
2
|
export declare function useOpenAiGlobal<K extends keyof OpenAiGlobals>(key: K): OpenAiGlobals[K];
|
|
@@ -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];
|
package/dist/types/openai.d.ts
CHANGED
package/dist/vite/index.js
CHANGED
|
@@ -26,14 +26,18 @@ var getRawValue = (node) => {
|
|
|
26
26
|
return acc;
|
|
27
27
|
}, {});
|
|
28
28
|
default:
|
|
29
|
-
throw new Error(
|
|
29
|
+
throw new Error(
|
|
30
|
+
`Error when parsing directive values: unexpected type '${node.kind}'`
|
|
31
|
+
);
|
|
30
32
|
}
|
|
31
33
|
};
|
|
32
34
|
var getTypedDirectiveArgument = (argumentName, expectedType, directiveArguments) => {
|
|
33
35
|
if (!directiveArguments || directiveArguments.length === 0) {
|
|
34
36
|
return void 0;
|
|
35
37
|
}
|
|
36
|
-
let argument = directiveArguments.find(
|
|
38
|
+
let argument = directiveArguments.find(
|
|
39
|
+
(directiveArgument) => directiveArgument.name.value === argumentName
|
|
40
|
+
);
|
|
37
41
|
if (!argument) {
|
|
38
42
|
return void 0;
|
|
39
43
|
}
|
|
@@ -59,25 +63,52 @@ var ApplicationManifestPlugin = () => {
|
|
|
59
63
|
const client = new ApolloClient({
|
|
60
64
|
cache: clientCache,
|
|
61
65
|
link: new ApolloLink((operation) => {
|
|
62
|
-
const body = print(
|
|
66
|
+
const body = print(
|
|
67
|
+
removeClientDirective(sortTopLevelDefinitions(operation.query))
|
|
68
|
+
);
|
|
63
69
|
const name = operation.operationName;
|
|
64
|
-
const variables = operation.query.definitions.find(
|
|
65
|
-
(
|
|
70
|
+
const variables = operation.query.definitions.find(
|
|
71
|
+
(d) => d.kind === "OperationDefinition"
|
|
72
|
+
).variableDefinitions?.reduce(
|
|
73
|
+
(obj, varDef) => ({
|
|
74
|
+
...obj,
|
|
75
|
+
[varDef.variable.name.value]: getTypeName(varDef.type)
|
|
76
|
+
}),
|
|
66
77
|
{}
|
|
67
78
|
);
|
|
68
|
-
const type = operation.query.definitions.find(
|
|
69
|
-
|
|
79
|
+
const type = operation.query.definitions.find(
|
|
80
|
+
(d) => d.kind === "OperationDefinition"
|
|
81
|
+
).operation;
|
|
82
|
+
const prefetch = operation.query.definitions.find(
|
|
83
|
+
(d) => d.kind === "OperationDefinition"
|
|
84
|
+
).directives?.some((d) => d.name.value === "prefetch");
|
|
70
85
|
const id = createHash("sha256").update(body).digest("hex");
|
|
71
86
|
const prefetchID = prefetch ? "__anonymous" : void 0;
|
|
72
|
-
const tools = operation.query.definitions.find(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const
|
|
87
|
+
const tools = operation.query.definitions.find(
|
|
88
|
+
(d) => d.kind === "OperationDefinition"
|
|
89
|
+
).directives?.filter((d) => d.name.value === "tool").map((directive) => {
|
|
90
|
+
const name2 = getTypedDirectiveArgument(
|
|
91
|
+
"name",
|
|
92
|
+
Kind.STRING,
|
|
93
|
+
directive.arguments
|
|
94
|
+
);
|
|
95
|
+
const description = getTypedDirectiveArgument(
|
|
96
|
+
"description",
|
|
97
|
+
Kind.STRING,
|
|
98
|
+
directive.arguments
|
|
99
|
+
);
|
|
100
|
+
const extraInputs = getTypedDirectiveArgument(
|
|
101
|
+
"extraInputs",
|
|
102
|
+
Kind.LIST,
|
|
103
|
+
directive.arguments
|
|
104
|
+
);
|
|
76
105
|
if (!name2) {
|
|
77
106
|
throw new Error("'name' argument must be supplied for @tool");
|
|
78
107
|
}
|
|
79
108
|
if (!description) {
|
|
80
|
-
throw new Error(
|
|
109
|
+
throw new Error(
|
|
110
|
+
"'description' argument must be supplied for @tool"
|
|
111
|
+
);
|
|
81
112
|
}
|
|
82
113
|
return {
|
|
83
114
|
name: name2,
|
|
@@ -85,7 +116,9 @@ var ApplicationManifestPlugin = () => {
|
|
|
85
116
|
extraInputs
|
|
86
117
|
};
|
|
87
118
|
});
|
|
88
|
-
return Observable.of({
|
|
119
|
+
return Observable.of({
|
|
120
|
+
data: { id, name, type, body, variables, prefetch, prefetchID, tools }
|
|
121
|
+
});
|
|
89
122
|
})
|
|
90
123
|
});
|
|
91
124
|
const processFile = async (file) => {
|
|
@@ -105,14 +138,24 @@ var ApplicationManifestPlugin = () => {
|
|
|
105
138
|
}));
|
|
106
139
|
const operations = [];
|
|
107
140
|
for (const source of sources) {
|
|
108
|
-
const type = source.node.definitions.find(
|
|
141
|
+
const type = source.node.definitions.find(
|
|
142
|
+
(d) => d.kind === "OperationDefinition"
|
|
143
|
+
).operation;
|
|
109
144
|
let result;
|
|
110
145
|
if (type === "query") {
|
|
111
|
-
result = await client.query({
|
|
146
|
+
result = await client.query({
|
|
147
|
+
query: source.node,
|
|
148
|
+
fetchPolicy: "no-cache"
|
|
149
|
+
});
|
|
112
150
|
} else if (type === "mutation") {
|
|
113
|
-
result = await client.mutate({
|
|
151
|
+
result = await client.mutate({
|
|
152
|
+
mutation: source.node,
|
|
153
|
+
fetchPolicy: "no-cache"
|
|
154
|
+
});
|
|
114
155
|
} else {
|
|
115
|
-
throw new Error(
|
|
156
|
+
throw new Error(
|
|
157
|
+
"Found an unsupported operation type. Only Query and Mutation are supported."
|
|
158
|
+
);
|
|
116
159
|
}
|
|
117
160
|
operations.push(result.data);
|
|
118
161
|
}
|
|
@@ -123,7 +166,9 @@ var ApplicationManifestPlugin = () => {
|
|
|
123
166
|
});
|
|
124
167
|
};
|
|
125
168
|
const generateManifest = async () => {
|
|
126
|
-
const operations = Array.from(cache.values()).flatMap(
|
|
169
|
+
const operations = Array.from(cache.values()).flatMap(
|
|
170
|
+
(entry) => entry.operations
|
|
171
|
+
);
|
|
127
172
|
if (operations.filter((o) => o.prefetch).length > 1) {
|
|
128
173
|
throw new Error(
|
|
129
174
|
"Found multiple operations marked as `@prefetch`. You can only mark 1 operation with `@prefetch`."
|
|
@@ -150,14 +195,20 @@ var ApplicationManifestPlugin = () => {
|
|
|
150
195
|
name: packageJson.name,
|
|
151
196
|
description: packageJson.description,
|
|
152
197
|
hash: createHash("sha256").update(Date.now().toString()).digest("hex"),
|
|
153
|
-
operations: Array.from(cache.values()).flatMap(
|
|
198
|
+
operations: Array.from(cache.values()).flatMap(
|
|
199
|
+
(entry) => entry.operations
|
|
200
|
+
),
|
|
154
201
|
resource,
|
|
155
202
|
csp: {
|
|
156
203
|
connectDomains: packageJson.csp?.connectDomains ?? [],
|
|
157
204
|
resourceDomains: packageJson.csp?.resourceDomains ?? []
|
|
158
205
|
}
|
|
159
206
|
};
|
|
160
|
-
const dest = path.resolve(
|
|
207
|
+
const dest = path.resolve(
|
|
208
|
+
root,
|
|
209
|
+
config.build.outDir,
|
|
210
|
+
".application-manifest.json"
|
|
211
|
+
);
|
|
161
212
|
mkdirSync(path.dirname(dest), { recursive: true });
|
|
162
213
|
writeFileSync(dest, JSON.stringify(manifest));
|
|
163
214
|
writeFileSync(".application-manifest.json", JSON.stringify(manifest));
|
|
@@ -224,7 +275,9 @@ function removeClientDirective(doc) {
|
|
|
224
275
|
OperationDefinition(node) {
|
|
225
276
|
return {
|
|
226
277
|
...node,
|
|
227
|
-
directives: node.directives?.filter(
|
|
278
|
+
directives: node.directives?.filter(
|
|
279
|
+
(d) => d.name.value !== "prefetch" && d.name.value !== "tool"
|
|
280
|
+
)
|
|
228
281
|
};
|
|
229
282
|
}
|
|
230
283
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apollo/client-ai-apps",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -17,12 +17,16 @@
|
|
|
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
|
-
"changeset": "knope document-change"
|
|
27
|
+
"changeset": "knope document-change",
|
|
28
|
+
"format": "prettier --write .",
|
|
29
|
+
"format:check": "prettier --check ."
|
|
26
30
|
},
|
|
27
31
|
"keywords": [],
|
|
28
32
|
"author": "",
|
|
@@ -31,6 +35,7 @@
|
|
|
31
35
|
"devDependencies": {
|
|
32
36
|
"@testing-library/jest-dom": "^6.9.1",
|
|
33
37
|
"@testing-library/react": "^16.3.0",
|
|
38
|
+
"@testing-library/react-render-stream": "^2.0.2",
|
|
34
39
|
"@types/node": "^24.10.0",
|
|
35
40
|
"@types/react": "^19.2.2",
|
|
36
41
|
"@vitejs/plugin-react": "^5.1.1",
|
|
@@ -38,6 +43,8 @@
|
|
|
38
43
|
"esbuild": "^0.25.12",
|
|
39
44
|
"graphql": "^16.9.0",
|
|
40
45
|
"happy-dom": "^20.0.10",
|
|
46
|
+
"prettier": "^3.7.4",
|
|
47
|
+
"rimraf": "^6.1.2",
|
|
41
48
|
"rxjs": "^7.8.1",
|
|
42
49
|
"typescript": "^5.9.3",
|
|
43
50
|
"vitest": "^4.0.13"
|
package/scripts/dev.mjs
CHANGED
|
@@ -10,7 +10,9 @@ let ctx = await esbuild.context({
|
|
|
10
10
|
name: "rebuild-logger",
|
|
11
11
|
setup(build) {
|
|
12
12
|
build.onEnd((result) => {
|
|
13
|
-
console.log(
|
|
13
|
+
console.log(
|
|
14
|
+
`Rebuilt at ${new Date().toLocaleTimeString()} (${result.errors.length} errors)`
|
|
15
|
+
);
|
|
14
16
|
});
|
|
15
17
|
},
|
|
16
18
|
},
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ApolloLink } from "@apollo/client";
|
|
2
|
+
import { ApolloClient as BaseApolloClient } from "@apollo/client";
|
|
3
|
+
import { DocumentTransform } from "@apollo/client";
|
|
4
|
+
import { removeDirectivesFromDocument } from "@apollo/client/utilities/internal";
|
|
5
|
+
import { parse } from "graphql";
|
|
6
|
+
import { __DEV__ } from "@apollo/client/utilities/environment";
|
|
7
|
+
import "../types/openai";
|
|
8
|
+
import { ApplicationManifest } from "../types/application-manifest";
|
|
9
|
+
import { ToolCallLink } from "../link/ToolCallLink";
|
|
10
|
+
|
|
11
|
+
// TODO: In the future if/when we support PQs again, do pqLink.concat(toolCallLink)
|
|
12
|
+
// Commenting this out for now.
|
|
13
|
+
// import { sha256 } from "crypto-hash";
|
|
14
|
+
// import { PersistedQueryLink } from "@apollo/client/link/persisted-queries";
|
|
15
|
+
// const pqLink = new PersistedQueryLink({
|
|
16
|
+
// sha256: (queryString) => sha256(queryString),
|
|
17
|
+
// });
|
|
18
|
+
|
|
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
|
+
}
|
|
26
|
+
|
|
27
|
+
export class ApolloClient extends BaseApolloClient {
|
|
28
|
+
manifest: ApplicationManifest;
|
|
29
|
+
|
|
30
|
+
constructor(options: ApolloClient.Options) {
|
|
31
|
+
const link = options.link ?? new ToolCallLink();
|
|
32
|
+
|
|
33
|
+
if (__DEV__) {
|
|
34
|
+
validateTerminatingLink(link);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
super({
|
|
38
|
+
...options,
|
|
39
|
+
link,
|
|
40
|
+
// Strip out the prefetch/tool directives so they don't get sent with the operation to the server
|
|
41
|
+
documentTransform: new DocumentTransform((document) => {
|
|
42
|
+
return removeDirectivesFromDocument(
|
|
43
|
+
[{ name: "prefetch" }, { name: "tool" }],
|
|
44
|
+
document
|
|
45
|
+
)!;
|
|
46
|
+
}),
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
this.manifest = options.manifest;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async prefetchData() {
|
|
53
|
+
// Write prefetched data to the cache
|
|
54
|
+
this.manifest.operations.forEach((operation) => {
|
|
55
|
+
if (
|
|
56
|
+
operation.prefetch &&
|
|
57
|
+
operation.prefetchID &&
|
|
58
|
+
window.openai.toolOutput?.prefetch?.[operation.prefetchID]
|
|
59
|
+
) {
|
|
60
|
+
this.writeQuery({
|
|
61
|
+
query: parse(operation.body),
|
|
62
|
+
data: window.openai.toolOutput.prefetch[operation.prefetchID].data,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// If this operation has the tool that matches up with the tool that was executed, write the tool result to the cache
|
|
67
|
+
if (
|
|
68
|
+
operation.tools?.find(
|
|
69
|
+
(tool) =>
|
|
70
|
+
`${this.manifest.name}--${tool.name}` ===
|
|
71
|
+
window.openai.toolResponseMetadata?.toolName
|
|
72
|
+
)
|
|
73
|
+
) {
|
|
74
|
+
// We need to include the variables that were used as part of the tool call so that we get a proper cache entry
|
|
75
|
+
// However, we only want to include toolInput's that were graphql operation (ignore extraInputs)
|
|
76
|
+
const variables = Object.keys(window.openai.toolInput).reduce(
|
|
77
|
+
(obj, key) =>
|
|
78
|
+
operation.variables?.[key] ?
|
|
79
|
+
{ ...obj, [key]: window.openai.toolInput[key] }
|
|
80
|
+
: obj,
|
|
81
|
+
{}
|
|
82
|
+
);
|
|
83
|
+
|
|
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
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function validateTerminatingLink(link: ApolloLink) {
|
|
97
|
+
let terminatingLink = link;
|
|
98
|
+
|
|
99
|
+
while (terminatingLink.right) {
|
|
100
|
+
terminatingLink = terminatingLink.right;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (terminatingLink.constructor.name !== "ToolCallLink") {
|
|
104
|
+
throw new Error(
|
|
105
|
+
"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."
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|