@apollo/client-ai-apps 0.6.5 → 0.7.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/CHANGELOG.md +70 -0
- package/CONTRIBUTING.md +195 -0
- package/README.md +74 -0
- package/dist/core/AbstractApolloClient.d.ts +33 -0
- package/dist/core/AbstractApolloClient.d.ts.map +1 -0
- package/dist/core/AbstractApolloClient.js +129 -0
- package/dist/core/AbstractApolloClient.js.map +1 -0
- package/dist/core/ApolloClient.d.ts +3 -7
- package/dist/core/ApolloClient.d.ts.map +1 -1
- package/dist/core/ApolloClient.js +5 -4
- package/dist/core/ApolloClient.js.map +1 -1
- package/dist/{mcp/core → core}/McpAppManager.d.ts +14 -10
- package/dist/core/McpAppManager.d.ts.map +1 -0
- package/dist/core/McpAppManager.js +56 -0
- package/dist/core/McpAppManager.js.map +1 -0
- package/dist/core/typeRegistration.d.ts +0 -14
- package/dist/core/typeRegistration.d.ts.map +1 -1
- package/dist/core/typeRegistration.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mcp.d.ts +0 -1
- package/dist/index.mcp.d.ts.map +1 -1
- package/dist/index.mcp.js +0 -1
- package/dist/index.mcp.js.map +1 -1
- package/dist/index.openai.d.ts +0 -1
- package/dist/index.openai.d.ts.map +1 -1
- package/dist/index.openai.js +0 -1
- package/dist/index.openai.js.map +1 -1
- package/dist/link/ToolCallLink.d.ts +6 -1
- package/dist/link/ToolCallLink.d.ts.map +1 -1
- package/dist/link/ToolCallLink.js +17 -4
- package/dist/link/ToolCallLink.js.map +1 -1
- package/dist/link/ToolHydrationLink.d.ts +21 -0
- package/dist/link/ToolHydrationLink.d.ts.map +1 -0
- package/dist/link/ToolHydrationLink.js +57 -0
- package/dist/link/ToolHydrationLink.js.map +1 -0
- package/dist/mcp/core/ApolloClient.d.ts +3 -20
- package/dist/mcp/core/ApolloClient.d.ts.map +1 -1
- package/dist/mcp/core/ApolloClient.js +20 -101
- package/dist/mcp/core/ApolloClient.js.map +1 -1
- package/dist/mcp/index.d.ts +0 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/openai/core/ApolloClient.d.ts +3 -20
- package/dist/openai/core/ApolloClient.d.ts.map +1 -1
- package/dist/openai/core/ApolloClient.js +36 -101
- package/dist/openai/core/ApolloClient.js.map +1 -1
- package/dist/openai/index.d.ts +0 -1
- package/dist/openai/index.d.ts.map +1 -1
- package/dist/openai/index.js +0 -1
- package/dist/openai/index.js.map +1 -1
- package/dist/openai/react/index.d.ts +0 -7
- package/dist/openai/react/index.d.ts.map +1 -1
- package/dist/openai/react/index.js +0 -7
- package/dist/openai/react/index.js.map +1 -1
- package/dist/react/ApolloProvider.d.ts.map +1 -1
- package/dist/react/ApolloProvider.js +1 -1
- package/dist/react/ApolloProvider.js.map +1 -1
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.d.ts +1 -1
- package/dist/react/createHydrationUtils.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react}/createHydrationUtils.js +7 -9
- package/dist/react/createHydrationUtils.js.map +1 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts +3 -0
- package/dist/react/hooks/internal/useApolloClient.d.ts.map +1 -0
- package/dist/{mcp/react/hooks → react/hooks/internal}/useApolloClient.js +3 -3
- package/dist/react/hooks/internal/useApolloClient.js.map +1 -0
- package/dist/react/hooks/useApp.d.ts.map +1 -0
- package/dist/react/hooks/useApp.js +5 -0
- package/dist/react/hooks/useApp.js.map +1 -0
- package/dist/react/hooks/useHostContext.d.ts.map +1 -0
- package/dist/{openai/react → react}/hooks/useHostContext.js +1 -1
- package/dist/react/hooks/useHostContext.js.map +1 -0
- package/dist/react/hooks/useToolInfo.d.ts +3 -0
- package/dist/react/hooks/useToolInfo.d.ts.map +1 -0
- package/dist/react/hooks/useToolInfo.js +5 -0
- package/dist/react/hooks/useToolInfo.js.map +1 -0
- package/dist/react/hooks/useToolMetadata.d.ts +2 -0
- package/dist/react/hooks/useToolMetadata.d.ts.map +1 -0
- package/dist/react/hooks/useToolMetadata.js +5 -0
- package/dist/react/hooks/useToolMetadata.js.map +1 -0
- package/dist/react/index.d.ts +5 -16
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +5 -19
- package/dist/react/index.js.map +1 -1
- package/dist/utilities/connectToHost.d.ts +3 -0
- package/dist/utilities/connectToHost.d.ts.map +1 -0
- package/dist/utilities/connectToHost.js +11 -0
- package/dist/utilities/connectToHost.js.map +1 -0
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.d.ts.map +1 -1
- package/dist/utilities/index.js +1 -0
- package/dist/utilities/index.js.map +1 -1
- package/package.json +17 -26
- package/src/core/AbstractApolloClient.ts +217 -0
- package/src/core/ApolloClient.ts +8 -10
- package/src/core/McpAppManager.ts +106 -0
- package/src/core/typeRegistration.ts +0 -15
- package/src/index.mcp.ts +0 -1
- package/src/index.openai.ts +0 -1
- package/src/index.ts +1 -6
- package/src/link/ToolCallLink.ts +27 -5
- package/src/link/ToolHydrationLink.ts +90 -0
- package/src/link/__tests__/ToolCallLink.test.ts +99 -0
- package/src/mcp/core/ApolloClient.ts +32 -170
- package/src/mcp/core/__tests__/ApolloClient.test.ts +398 -140
- package/src/mcp/index.ts +0 -1
- package/src/openai/core/ApolloClient.ts +48 -166
- package/src/openai/core/__tests__/ApolloClient.test.ts +680 -185
- package/src/openai/index.ts +0 -1
- package/src/openai/react/index.ts +0 -7
- package/src/react/ApolloProvider.tsx +1 -6
- package/src/react/__tests__/ApolloProvider/mcp.test.tsx +66 -29
- package/src/react/__tests__/ApolloProvider/openai.test.tsx +16 -41
- package/src/react/__tests__/createHydrationUtils.test.tsx +1260 -0
- package/src/{mcp/react/hooks → react}/createHydrationUtils.ts +7 -10
- package/src/react/hooks/__tests__/useApp.test.tsx +46 -0
- package/src/react/hooks/__tests__/useHostContext.test.tsx +99 -0
- package/src/react/hooks/__tests__/useToolInfo.test.tsx +98 -0
- package/src/react/hooks/__tests__/useToolMetadata.test.tsx +58 -0
- package/src/{mcp/react/hooks → react/hooks/internal}/useApolloClient.ts +3 -3
- package/src/{mcp/react → react}/hooks/useApp.ts +1 -1
- package/src/{openai/react → react}/hooks/useHostContext.ts +1 -1
- package/src/react/hooks/useToolInfo.ts +6 -0
- package/src/react/hooks/useToolMetadata.ts +5 -0
- package/src/react/index.ts +5 -36
- package/src/testing/internal/graphql/parseManifestOperation.ts +87 -0
- package/src/testing/internal/index.ts +3 -0
- package/src/testing/internal/matchers/index.ts +1 -0
- package/src/testing/internal/matchers/toEmitAnything.ts +43 -0
- package/src/testing/internal/matchers/types.ts +1 -0
- package/src/testing/internal/mcp/mockMcpHost.ts +25 -4
- package/src/testing/internal/tests/eachHostEnv.ts +22 -0
- package/src/testing/internal/utilities/createHostEnv.ts +117 -0
- package/src/utilities/connectToHost.ts +13 -0
- package/src/utilities/index.ts +1 -0
- package/tsconfig.vite.json +1 -1
- package/vitest.config.ts +13 -0
- package/dist/mcp/core/McpAppManager.d.ts.map +0 -1
- package/dist/mcp/core/McpAppManager.js +0 -88
- package/dist/mcp/core/McpAppManager.js.map +0 -1
- package/dist/mcp/link/ToolCallLink.d.ts +0 -28
- package/dist/mcp/link/ToolCallLink.d.ts.map +0 -1
- package/dist/mcp/link/ToolCallLink.js +0 -35
- package/dist/mcp/link/ToolCallLink.js.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/mcp/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.d.ts +0 -3
- package/dist/mcp/react/hooks/useApolloClient.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApolloClient.js.map +0 -1
- package/dist/mcp/react/hooks/useApp.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useApp.js +0 -5
- package/dist/mcp/react/hooks/useApp.js.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useHostContext.js +0 -7
- package/dist/mcp/react/hooks/useHostContext.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/mcp/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInfo.js +0 -10
- package/dist/mcp/react/hooks/useToolInfo.js.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolInput.js +0 -9
- package/dist/mcp/react/hooks/useToolInput.js.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/mcp/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolMetadata.js +0 -5
- package/dist/mcp/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/mcp/react/hooks/useToolName.d.ts +0 -7
- package/dist/mcp/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/mcp/react/hooks/useToolName.js +0 -9
- package/dist/mcp/react/hooks/useToolName.js.map +0 -1
- package/dist/mcp/react/index.d.ts +0 -8
- package/dist/mcp/react/index.d.ts.map +0 -1
- package/dist/mcp/react/index.js +0 -8
- package/dist/mcp/react/index.js.map +0 -1
- package/dist/openai/core/McpAppManager.d.ts +0 -37
- package/dist/openai/core/McpAppManager.d.ts.map +0 -1
- package/dist/openai/core/McpAppManager.js +0 -97
- package/dist/openai/core/McpAppManager.js.map +0 -1
- package/dist/openai/link/ToolCallLink.d.ts +0 -28
- package/dist/openai/link/ToolCallLink.d.ts.map +0 -1
- package/dist/openai/link/ToolCallLink.js +0 -35
- package/dist/openai/link/ToolCallLink.js.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.d.ts +0 -15
- package/dist/openai/react/hooks/createHydrationUtils.d.ts.map +0 -1
- package/dist/openai/react/hooks/createHydrationUtils.js +0 -113
- package/dist/openai/react/hooks/createHydrationUtils.js.map +0 -1
- package/dist/openai/react/hooks/useApp.d.ts +0 -2
- package/dist/openai/react/hooks/useApp.d.ts.map +0 -1
- package/dist/openai/react/hooks/useApp.js +0 -5
- package/dist/openai/react/hooks/useApp.js.map +0 -1
- package/dist/openai/react/hooks/useHostContext.d.ts +0 -2
- package/dist/openai/react/hooks/useHostContext.d.ts.map +0 -1
- package/dist/openai/react/hooks/useHostContext.js.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.d.ts +0 -3
- package/dist/openai/react/hooks/useToolInfo.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInfo.js +0 -10
- package/dist/openai/react/hooks/useToolInfo.js.map +0 -1
- package/dist/openai/react/hooks/useToolInput.d.ts +0 -7
- package/dist/openai/react/hooks/useToolInput.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolInput.js +0 -9
- package/dist/openai/react/hooks/useToolInput.js.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.d.ts +0 -2
- package/dist/openai/react/hooks/useToolMetadata.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolMetadata.js +0 -5
- package/dist/openai/react/hooks/useToolMetadata.js.map +0 -1
- package/dist/openai/react/hooks/useToolName.d.ts +0 -7
- package/dist/openai/react/hooks/useToolName.d.ts.map +0 -1
- package/dist/openai/react/hooks/useToolName.js +0 -9
- package/dist/openai/react/hooks/useToolName.js.map +0 -1
- package/dist/react/index.mcp.d.ts +0 -3
- package/dist/react/index.mcp.d.ts.map +0 -1
- package/dist/react/index.mcp.js +0 -3
- package/dist/react/index.mcp.js.map +0 -1
- package/dist/react/index.openai.d.ts +0 -3
- package/dist/react/index.openai.d.ts.map +0 -1
- package/dist/react/index.openai.js +0 -3
- package/dist/react/index.openai.js.map +0 -1
- package/dist/react/missingHook.d.ts +0 -2
- package/dist/react/missingHook.d.ts.map +0 -1
- package/dist/react/missingHook.js +0 -6
- package/dist/react/missingHook.js.map +0 -1
- package/src/mcp/core/McpAppManager.ts +0 -136
- package/src/mcp/link/ToolCallLink.ts +0 -40
- package/src/mcp/link/__tests__/ToolCallLink.test.ts +0 -113
- package/src/mcp/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1228
- package/src/mcp/react/hooks/__tests__/useApp.test.tsx +0 -46
- package/src/mcp/react/hooks/__tests__/useHostContext.test.tsx +0 -95
- package/src/mcp/react/hooks/__tests__/useToolInfo.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolInput.test.tsx +0 -50
- package/src/mcp/react/hooks/__tests__/useToolMetadata.test.tsx +0 -53
- package/src/mcp/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/mcp/react/hooks/useHostContext.ts +0 -14
- package/src/mcp/react/hooks/useToolInfo.ts +0 -13
- package/src/mcp/react/hooks/useToolInput.ts +0 -10
- package/src/mcp/react/hooks/useToolMetadata.ts +0 -5
- package/src/mcp/react/hooks/useToolName.ts +0 -10
- package/src/mcp/react/index.ts +0 -7
- package/src/openai/core/McpAppManager.ts +0 -148
- package/src/openai/link/ToolCallLink.ts +0 -40
- package/src/openai/react/hooks/__tests__/createHydrationUtils.test.tsx +0 -1333
- package/src/openai/react/hooks/__tests__/useToolInfo.test.tsx +0 -92
- package/src/openai/react/hooks/__tests__/useToolInput.test.tsx +0 -85
- package/src/openai/react/hooks/__tests__/useToolMetadata.test.tsx +0 -86
- package/src/openai/react/hooks/__tests__/useToolName.test.tsx +0 -50
- package/src/openai/react/hooks/createHydrationUtils.ts +0 -182
- package/src/openai/react/hooks/useApp.ts +0 -5
- package/src/openai/react/hooks/useToolInfo.ts +0 -13
- package/src/openai/react/hooks/useToolInput.ts +0 -10
- package/src/openai/react/hooks/useToolMetadata.ts +0 -5
- package/src/openai/react/hooks/useToolName.ts +0 -10
- package/src/react/index.mcp.ts +0 -10
- package/src/react/index.openai.ts +0 -10
- package/src/react/missingHook.ts +0 -9
- /package/dist/{mcp/react → react}/hooks/useApp.d.ts +0 -0
- /package/dist/{mcp/react → react}/hooks/useHostContext.d.ts +0 -0
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
import { expect, test, vi, describe } from "vitest";
|
|
2
2
|
import { ApolloClient } from "../ApolloClient.js";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ApolloLink,
|
|
5
|
+
HttpLink,
|
|
6
|
+
InMemoryCache,
|
|
7
|
+
NetworkStatus,
|
|
8
|
+
gql,
|
|
9
|
+
type DocumentNode,
|
|
10
|
+
} from "@apollo/client";
|
|
4
11
|
import { print } from "@apollo/client/utilities";
|
|
5
|
-
import { ToolCallLink } from "
|
|
12
|
+
import { ToolCallLink } from "../../../link/ToolCallLink.js";
|
|
6
13
|
import {
|
|
7
14
|
graphqlToolResult,
|
|
8
15
|
minimalHostContextWithToolName,
|
|
9
16
|
mockApplicationManifest,
|
|
10
17
|
mockMcpHost,
|
|
18
|
+
ObservableStream,
|
|
19
|
+
parseManifestOperation,
|
|
11
20
|
spyOnConsole,
|
|
12
21
|
} from "../../../testing/internal/index.js";
|
|
13
22
|
|
|
@@ -15,7 +24,8 @@ test("writes tool result data to cache", async () => {
|
|
|
15
24
|
using _ = spyOnConsole("debug");
|
|
16
25
|
|
|
17
26
|
const query = gql`
|
|
18
|
-
query Product($id: ID!)
|
|
27
|
+
query Product($id: ID!)
|
|
28
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
19
29
|
product(id: $id) {
|
|
20
30
|
id
|
|
21
31
|
title
|
|
@@ -24,27 +34,8 @@ test("writes tool result data to cache", async () => {
|
|
|
24
34
|
}
|
|
25
35
|
`;
|
|
26
36
|
|
|
27
|
-
const client =
|
|
28
|
-
|
|
29
|
-
manifest: mockApplicationManifest({
|
|
30
|
-
operations: [
|
|
31
|
-
{
|
|
32
|
-
id: "1",
|
|
33
|
-
name: "Product",
|
|
34
|
-
body: print(query),
|
|
35
|
-
type: "query",
|
|
36
|
-
prefetch: false,
|
|
37
|
-
variables: { id: "ID" },
|
|
38
|
-
tools: [{ name: "GetProduct", description: "Get a product" }],
|
|
39
|
-
},
|
|
40
|
-
],
|
|
41
|
-
}),
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
using host = await mockMcpHost({
|
|
45
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
46
|
-
});
|
|
47
|
-
host.onCleanup(() => client.stop());
|
|
37
|
+
const { client, host } = await setup({ query });
|
|
38
|
+
using _host = host;
|
|
48
39
|
|
|
49
40
|
host.sendToolResult({
|
|
50
41
|
content: [],
|
|
@@ -60,6 +51,12 @@ test("writes tool result data to cache", async () => {
|
|
|
60
51
|
|
|
61
52
|
await client.connect();
|
|
62
53
|
|
|
54
|
+
await expect(
|
|
55
|
+
client.query({ query, variables: { id: "1" } })
|
|
56
|
+
).resolves.toStrictEqual({
|
|
57
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
58
|
+
});
|
|
59
|
+
|
|
63
60
|
expect(client.extract()).toEqual({
|
|
64
61
|
"Product:1": {
|
|
65
62
|
__typename: "Product",
|
|
@@ -140,11 +137,11 @@ test("writes prefetch data to cache", async () => {
|
|
|
140
137
|
});
|
|
141
138
|
});
|
|
142
139
|
|
|
143
|
-
test("writes prefetch
|
|
140
|
+
test("writes prefetch response data to cache when both are provided", async () => {
|
|
144
141
|
using _ = spyOnConsole("debug");
|
|
145
142
|
|
|
146
143
|
const prefetchQuery = gql`
|
|
147
|
-
query TopProducts {
|
|
144
|
+
query TopProducts @tool(description: "Shows top products") @prefetch {
|
|
148
145
|
topProducts {
|
|
149
146
|
id
|
|
150
147
|
title
|
|
@@ -154,7 +151,7 @@ test("writes prefetch and tool response data to cache when both are provided", a
|
|
|
154
151
|
`;
|
|
155
152
|
|
|
156
153
|
const query = gql`
|
|
157
|
-
query Product($id: ID!) {
|
|
154
|
+
query Product($id: ID!) @tool(description: "Get a product by id") {
|
|
158
155
|
product(id: $id) {
|
|
159
156
|
id
|
|
160
157
|
title
|
|
@@ -167,25 +164,8 @@ test("writes prefetch and tool response data to cache when both are provided", a
|
|
|
167
164
|
cache: new InMemoryCache(),
|
|
168
165
|
manifest: mockApplicationManifest({
|
|
169
166
|
operations: [
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
name: "TopProducts",
|
|
173
|
-
body: print(prefetchQuery),
|
|
174
|
-
type: "query",
|
|
175
|
-
prefetch: true,
|
|
176
|
-
prefetchID: "__anonymous",
|
|
177
|
-
variables: {},
|
|
178
|
-
tools: [{ name: "TopProducts", description: "Shows top products" }],
|
|
179
|
-
},
|
|
180
|
-
{
|
|
181
|
-
id: "2",
|
|
182
|
-
name: "Product",
|
|
183
|
-
body: print(query),
|
|
184
|
-
type: "query",
|
|
185
|
-
prefetch: false,
|
|
186
|
-
variables: { id: "ID" },
|
|
187
|
-
tools: [{ name: "Product", description: "Get a product by id" }],
|
|
188
|
-
},
|
|
167
|
+
parseManifestOperation(prefetchQuery),
|
|
168
|
+
parseManifestOperation(query),
|
|
189
169
|
],
|
|
190
170
|
}),
|
|
191
171
|
});
|
|
@@ -196,7 +176,6 @@ test("writes prefetch and tool response data to cache when both are provided", a
|
|
|
196
176
|
host.onCleanup(() => client.stop());
|
|
197
177
|
|
|
198
178
|
host.sendToolResult({
|
|
199
|
-
content: [],
|
|
200
179
|
structuredContent: {
|
|
201
180
|
prefetch: {
|
|
202
181
|
__anonymous: {
|
|
@@ -216,6 +195,12 @@ test("writes prefetch and tool response data to cache when both are provided", a
|
|
|
216
195
|
|
|
217
196
|
await client.connect();
|
|
218
197
|
|
|
198
|
+
await expect(
|
|
199
|
+
client.query({ query, variables: { id: "2" } })
|
|
200
|
+
).resolves.toStrictEqual({
|
|
201
|
+
data: { product: { __typename: "Product", id: "2", title: "iPad" } },
|
|
202
|
+
});
|
|
203
|
+
|
|
219
204
|
expect(client.extract()).toEqual({
|
|
220
205
|
"Product:1": {
|
|
221
206
|
__typename: "Product",
|
|
@@ -239,7 +224,8 @@ test("excludes extra tool input variables not defined in the operation", async (
|
|
|
239
224
|
using _ = spyOnConsole("debug");
|
|
240
225
|
|
|
241
226
|
const query = gql`
|
|
242
|
-
query Product($id: ID!)
|
|
227
|
+
query Product($id: ID!)
|
|
228
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
243
229
|
product(id: $id) {
|
|
244
230
|
id
|
|
245
231
|
title
|
|
@@ -248,30 +234,10 @@ test("excludes extra tool input variables not defined in the operation", async (
|
|
|
248
234
|
}
|
|
249
235
|
`;
|
|
250
236
|
|
|
251
|
-
const client =
|
|
252
|
-
|
|
253
|
-
manifest: mockApplicationManifest({
|
|
254
|
-
operations: [
|
|
255
|
-
{
|
|
256
|
-
id: "1",
|
|
257
|
-
name: "Product",
|
|
258
|
-
body: print(query),
|
|
259
|
-
type: "query",
|
|
260
|
-
prefetch: false,
|
|
261
|
-
variables: { id: "ID" },
|
|
262
|
-
tools: [{ name: "GetProduct", description: "Get a product" }],
|
|
263
|
-
},
|
|
264
|
-
],
|
|
265
|
-
}),
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
using host = await mockMcpHost({
|
|
269
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
270
|
-
});
|
|
271
|
-
host.onCleanup(() => client.stop());
|
|
237
|
+
const { client, host } = await setup({ query });
|
|
238
|
+
using _host = host;
|
|
272
239
|
|
|
273
240
|
host.sendToolResult({
|
|
274
|
-
content: [],
|
|
275
241
|
structuredContent: {
|
|
276
242
|
result: {
|
|
277
243
|
data: {
|
|
@@ -284,7 +250,13 @@ test("excludes extra tool input variables not defined in the operation", async (
|
|
|
284
250
|
|
|
285
251
|
await client.connect();
|
|
286
252
|
|
|
287
|
-
expect(
|
|
253
|
+
await expect(
|
|
254
|
+
client.query({ query, variables: { id: "1" } })
|
|
255
|
+
).resolves.toStrictEqual({
|
|
256
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
expect(client.extract()).toStrictEqual({
|
|
288
260
|
"Product:1": {
|
|
289
261
|
__typename: "Product",
|
|
290
262
|
id: "1",
|
|
@@ -468,7 +440,8 @@ test("reads result data from _meta.structuredContent", async () => {
|
|
|
468
440
|
using _ = spyOnConsole("debug");
|
|
469
441
|
|
|
470
442
|
const query = gql`
|
|
471
|
-
query Product($id: ID!)
|
|
443
|
+
query Product($id: ID!)
|
|
444
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
472
445
|
product(id: $id) @private {
|
|
473
446
|
id
|
|
474
447
|
title
|
|
@@ -477,30 +450,10 @@ test("reads result data from _meta.structuredContent", async () => {
|
|
|
477
450
|
}
|
|
478
451
|
`;
|
|
479
452
|
|
|
480
|
-
const client =
|
|
481
|
-
|
|
482
|
-
manifest: mockApplicationManifest({
|
|
483
|
-
operations: [
|
|
484
|
-
{
|
|
485
|
-
id: "1",
|
|
486
|
-
name: "Product",
|
|
487
|
-
body: print(query),
|
|
488
|
-
type: "query",
|
|
489
|
-
prefetch: false,
|
|
490
|
-
variables: { id: "ID" },
|
|
491
|
-
tools: [{ name: "GetProduct", description: "Get a product" }],
|
|
492
|
-
},
|
|
493
|
-
],
|
|
494
|
-
}),
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
using host = await mockMcpHost({
|
|
498
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
499
|
-
});
|
|
500
|
-
host.onCleanup(() => client.stop());
|
|
453
|
+
const { client, host } = await setup({ query });
|
|
454
|
+
using _host = host;
|
|
501
455
|
|
|
502
456
|
host.sendToolResult({
|
|
503
|
-
content: [],
|
|
504
457
|
structuredContent: {},
|
|
505
458
|
_meta: {
|
|
506
459
|
toolName: "GetProduct",
|
|
@@ -517,6 +470,12 @@ test("reads result data from _meta.structuredContent", async () => {
|
|
|
517
470
|
|
|
518
471
|
await client.connect();
|
|
519
472
|
|
|
473
|
+
await expect(
|
|
474
|
+
client.query({ query, variables: { id: "1" } })
|
|
475
|
+
).resolves.toStrictEqual({
|
|
476
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
477
|
+
});
|
|
478
|
+
|
|
520
479
|
expect(client.extract()).toEqual({
|
|
521
480
|
"Product:1": {
|
|
522
481
|
__typename: "Product",
|
|
@@ -536,7 +495,7 @@ test("merges prefetch from structuredContent and result from _meta.structuredCon
|
|
|
536
495
|
using _ = spyOnConsole("debug");
|
|
537
496
|
|
|
538
497
|
const prefetchQuery = gql`
|
|
539
|
-
query TopProducts {
|
|
498
|
+
query TopProducts @tool(description: "Shows top products") @prefetch {
|
|
540
499
|
topProducts {
|
|
541
500
|
id
|
|
542
501
|
title
|
|
@@ -546,7 +505,8 @@ test("merges prefetch from structuredContent and result from _meta.structuredCon
|
|
|
546
505
|
`;
|
|
547
506
|
|
|
548
507
|
const query = gql`
|
|
549
|
-
query Product($id: ID!)
|
|
508
|
+
query Product($id: ID!)
|
|
509
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
550
510
|
product(id: $id) @private {
|
|
551
511
|
id
|
|
552
512
|
title
|
|
@@ -559,25 +519,8 @@ test("merges prefetch from structuredContent and result from _meta.structuredCon
|
|
|
559
519
|
cache: new InMemoryCache(),
|
|
560
520
|
manifest: mockApplicationManifest({
|
|
561
521
|
operations: [
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
name: "TopProducts",
|
|
565
|
-
body: print(prefetchQuery),
|
|
566
|
-
type: "query",
|
|
567
|
-
prefetch: true,
|
|
568
|
-
prefetchID: "__anonymous",
|
|
569
|
-
variables: {},
|
|
570
|
-
tools: [{ name: "TopProducts", description: "Shows top products" }],
|
|
571
|
-
},
|
|
572
|
-
{
|
|
573
|
-
id: "2",
|
|
574
|
-
name: "Product",
|
|
575
|
-
body: print(query),
|
|
576
|
-
type: "query",
|
|
577
|
-
prefetch: false,
|
|
578
|
-
variables: { id: "ID" },
|
|
579
|
-
tools: [{ name: "GetProduct", description: "Get a product" }],
|
|
580
|
-
},
|
|
522
|
+
parseManifestOperation(prefetchQuery),
|
|
523
|
+
parseManifestOperation(query),
|
|
581
524
|
],
|
|
582
525
|
}),
|
|
583
526
|
});
|
|
@@ -588,7 +531,6 @@ test("merges prefetch from structuredContent and result from _meta.structuredCon
|
|
|
588
531
|
host.onCleanup(() => client.stop());
|
|
589
532
|
|
|
590
533
|
host.sendToolResult({
|
|
591
|
-
content: [],
|
|
592
534
|
structuredContent: {
|
|
593
535
|
prefetch: {
|
|
594
536
|
__anonymous: {
|
|
@@ -613,7 +555,13 @@ test("merges prefetch from structuredContent and result from _meta.structuredCon
|
|
|
613
555
|
|
|
614
556
|
await client.connect();
|
|
615
557
|
|
|
616
|
-
expect(
|
|
558
|
+
await expect(
|
|
559
|
+
client.query({ query, variables: { id: "2" } })
|
|
560
|
+
).resolves.toStrictEqual({
|
|
561
|
+
data: { product: { id: "2", title: "iPad", __typename: "Product" } },
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
expect(client.extract()).toStrictEqual({
|
|
617
565
|
"Product:1": {
|
|
618
566
|
__typename: "Product",
|
|
619
567
|
id: "1",
|
|
@@ -637,7 +585,7 @@ test("_meta.structuredContent wins over structuredContent", async () => {
|
|
|
637
585
|
|
|
638
586
|
const query = gql`
|
|
639
587
|
query Product($id: ID!) {
|
|
640
|
-
product(id: $id) {
|
|
588
|
+
product(id: $id) @tool(name: "GetProduct", description: "Get a product") {
|
|
641
589
|
id
|
|
642
590
|
title @private
|
|
643
591
|
__typename
|
|
@@ -645,30 +593,10 @@ test("_meta.structuredContent wins over structuredContent", async () => {
|
|
|
645
593
|
}
|
|
646
594
|
`;
|
|
647
595
|
|
|
648
|
-
const client =
|
|
649
|
-
|
|
650
|
-
manifest: mockApplicationManifest({
|
|
651
|
-
operations: [
|
|
652
|
-
{
|
|
653
|
-
id: "1",
|
|
654
|
-
name: "Product",
|
|
655
|
-
body: print(query),
|
|
656
|
-
type: "query",
|
|
657
|
-
prefetch: false,
|
|
658
|
-
variables: { id: "ID" },
|
|
659
|
-
tools: [{ name: "GetProduct", description: "Get a product" }],
|
|
660
|
-
},
|
|
661
|
-
],
|
|
662
|
-
}),
|
|
663
|
-
});
|
|
664
|
-
|
|
665
|
-
using host = await mockMcpHost({
|
|
666
|
-
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
667
|
-
});
|
|
668
|
-
host.onCleanup(() => client.stop());
|
|
596
|
+
const { client, host } = await setup({ query });
|
|
597
|
+
using _host = host;
|
|
669
598
|
|
|
670
599
|
host.sendToolResult({
|
|
671
|
-
content: [],
|
|
672
600
|
structuredContent: {
|
|
673
601
|
result: {
|
|
674
602
|
data: {
|
|
@@ -691,6 +619,12 @@ test("_meta.structuredContent wins over structuredContent", async () => {
|
|
|
691
619
|
|
|
692
620
|
await client.connect();
|
|
693
621
|
|
|
622
|
+
await expect(
|
|
623
|
+
client.query({ query, variables: { id: "1" } })
|
|
624
|
+
).resolves.toStrictEqual({
|
|
625
|
+
data: { product: { id: "1", title: "Meta title", __typename: "Product" } },
|
|
626
|
+
});
|
|
627
|
+
|
|
694
628
|
expect(client.extract()).toEqual({
|
|
695
629
|
"Product:1": {
|
|
696
630
|
__typename: "Product",
|
|
@@ -706,6 +640,307 @@ test("_meta.structuredContent wins over structuredContent", async () => {
|
|
|
706
640
|
});
|
|
707
641
|
});
|
|
708
642
|
|
|
643
|
+
test("serves tool result data on network-only query without calling execute tool", async () => {
|
|
644
|
+
using _ = spyOnConsole("debug");
|
|
645
|
+
const query = gql`
|
|
646
|
+
query Product($id: ID!)
|
|
647
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
648
|
+
product(id: $id) {
|
|
649
|
+
id
|
|
650
|
+
title
|
|
651
|
+
__typename
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
`;
|
|
655
|
+
|
|
656
|
+
const data = {
|
|
657
|
+
product: { id: "1", title: "Pen", __typename: "Product" },
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
const { client, host } = await setup({ query });
|
|
661
|
+
using _host = host;
|
|
662
|
+
|
|
663
|
+
const execute = vi.fn();
|
|
664
|
+
host.mockToolCall("execute", execute);
|
|
665
|
+
|
|
666
|
+
host.sendToolResult({ structuredContent: { result: { data } } });
|
|
667
|
+
host.sendToolInput({ arguments: { id: "1" } });
|
|
668
|
+
|
|
669
|
+
await client.connect();
|
|
670
|
+
|
|
671
|
+
await expect(
|
|
672
|
+
client.query({
|
|
673
|
+
query,
|
|
674
|
+
variables: { id: "1" },
|
|
675
|
+
fetchPolicy: "network-only",
|
|
676
|
+
})
|
|
677
|
+
).resolves.toStrictEqual({ data });
|
|
678
|
+
expect(execute).not.toHaveBeenCalled();
|
|
679
|
+
});
|
|
680
|
+
|
|
681
|
+
test("calls execute tool on second network-only query after hydration is consumed", async () => {
|
|
682
|
+
using _ = spyOnConsole("debug");
|
|
683
|
+
const query = gql`
|
|
684
|
+
query Product($id: ID!)
|
|
685
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
686
|
+
product(id: $id) {
|
|
687
|
+
id
|
|
688
|
+
title
|
|
689
|
+
__typename
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
`;
|
|
693
|
+
|
|
694
|
+
const { client, host } = await setup({ query });
|
|
695
|
+
using _host = host;
|
|
696
|
+
|
|
697
|
+
host.mockToolCall("execute", () => ({
|
|
698
|
+
structuredContent: {
|
|
699
|
+
data: {
|
|
700
|
+
product: { id: "1", title: "Updated Pen", __typename: "Product" },
|
|
701
|
+
},
|
|
702
|
+
},
|
|
703
|
+
}));
|
|
704
|
+
|
|
705
|
+
host.sendToolResult({
|
|
706
|
+
structuredContent: {
|
|
707
|
+
result: {
|
|
708
|
+
data: {
|
|
709
|
+
product: { id: "1", title: "Pen", __typename: "Product" },
|
|
710
|
+
},
|
|
711
|
+
},
|
|
712
|
+
},
|
|
713
|
+
});
|
|
714
|
+
host.sendToolInput({ arguments: { id: "1" } });
|
|
715
|
+
|
|
716
|
+
await client.connect();
|
|
717
|
+
|
|
718
|
+
await client.query({
|
|
719
|
+
query,
|
|
720
|
+
variables: { id: "1" },
|
|
721
|
+
fetchPolicy: "network-only",
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
await expect(
|
|
725
|
+
client.query({
|
|
726
|
+
query,
|
|
727
|
+
variables: { id: "1" },
|
|
728
|
+
fetchPolicy: "network-only",
|
|
729
|
+
})
|
|
730
|
+
).resolves.toStrictEqual({
|
|
731
|
+
data: {
|
|
732
|
+
product: { id: "1", title: "Updated Pen", __typename: "Product" },
|
|
733
|
+
},
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
test("serves tool result data on cache-and-network query without calling execute tool", async () => {
|
|
738
|
+
using _ = spyOnConsole("debug");
|
|
739
|
+
const query = gql`
|
|
740
|
+
query Product($id: ID!)
|
|
741
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
742
|
+
product(id: $id) {
|
|
743
|
+
id
|
|
744
|
+
title
|
|
745
|
+
__typename
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
`;
|
|
749
|
+
|
|
750
|
+
const { client, host } = await setup({ query });
|
|
751
|
+
using _host = host;
|
|
752
|
+
|
|
753
|
+
const execute = vi.fn();
|
|
754
|
+
host.mockToolCall("execute", execute);
|
|
755
|
+
|
|
756
|
+
host.sendToolResult({
|
|
757
|
+
structuredContent: {
|
|
758
|
+
result: {
|
|
759
|
+
data: {
|
|
760
|
+
product: { id: "1", title: "Pen", __typename: "Product" },
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
});
|
|
765
|
+
host.sendToolInput({ arguments: { id: "1" } });
|
|
766
|
+
|
|
767
|
+
await client.connect();
|
|
768
|
+
|
|
769
|
+
const stream = new ObservableStream(
|
|
770
|
+
client.watchQuery({
|
|
771
|
+
query,
|
|
772
|
+
variables: { id: "1" },
|
|
773
|
+
fetchPolicy: "cache-and-network",
|
|
774
|
+
})
|
|
775
|
+
);
|
|
776
|
+
|
|
777
|
+
// The hydrated result is emitted synchronously so we won't observe a loading
|
|
778
|
+
// state like we normally would with `cache-and-network`
|
|
779
|
+
await expect(stream).toEmitValue({
|
|
780
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
781
|
+
dataState: "complete",
|
|
782
|
+
loading: false,
|
|
783
|
+
networkStatus: NetworkStatus.ready,
|
|
784
|
+
partial: false,
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
await expect(stream).not.toEmitAnything();
|
|
788
|
+
|
|
789
|
+
expect(execute).not.toHaveBeenCalled();
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
test("serves tool result data on no-cache query without calling execute tool and does not write to cache", async () => {
|
|
793
|
+
using _ = spyOnConsole("debug");
|
|
794
|
+
const query = gql`
|
|
795
|
+
query Product($id: ID!)
|
|
796
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
797
|
+
product(id: $id) {
|
|
798
|
+
id
|
|
799
|
+
title
|
|
800
|
+
__typename
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
`;
|
|
804
|
+
|
|
805
|
+
const data = {
|
|
806
|
+
product: { id: "1", title: "Pen", __typename: "Product" },
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
const { client, host } = await setup({ query });
|
|
810
|
+
using _host = host;
|
|
811
|
+
|
|
812
|
+
const execute = vi.fn();
|
|
813
|
+
host.mockToolCall("execute", execute);
|
|
814
|
+
|
|
815
|
+
host.sendToolInput({ arguments: { id: "1" } });
|
|
816
|
+
host.sendToolResult({ structuredContent: { result: { data } } });
|
|
817
|
+
|
|
818
|
+
await client.connect();
|
|
819
|
+
|
|
820
|
+
await expect(
|
|
821
|
+
client.query({ query, variables: { id: "1" }, fetchPolicy: "no-cache" })
|
|
822
|
+
).resolves.toStrictEqual({ data });
|
|
823
|
+
expect(execute).not.toHaveBeenCalled();
|
|
824
|
+
expect(client.extract()).toStrictEqual({});
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
test("serves hydrated query from tool result while other pending network-only queries call execute", async () => {
|
|
828
|
+
using _ = spyOnConsole("debug");
|
|
829
|
+
|
|
830
|
+
const productQuery = gql`
|
|
831
|
+
query Product($id: ID!)
|
|
832
|
+
@tool(name: "GetProduct", description: "Get a product") {
|
|
833
|
+
product(id: $id) {
|
|
834
|
+
id
|
|
835
|
+
title
|
|
836
|
+
__typename
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
`;
|
|
840
|
+
|
|
841
|
+
const cartQuery = gql`
|
|
842
|
+
query Cart @tool(name: "GetCart", description: "Get the cart") {
|
|
843
|
+
cart {
|
|
844
|
+
id
|
|
845
|
+
__typename
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
`;
|
|
849
|
+
|
|
850
|
+
const productOperation = parseManifestOperation(productQuery);
|
|
851
|
+
const cartOperation = parseManifestOperation(cartQuery);
|
|
852
|
+
|
|
853
|
+
const client = new ApolloClient({
|
|
854
|
+
cache: new InMemoryCache(),
|
|
855
|
+
manifest: mockApplicationManifest({
|
|
856
|
+
operations: [productOperation, cartOperation],
|
|
857
|
+
}),
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
using host = await mockMcpHost({
|
|
861
|
+
hostContext: minimalHostContextWithToolName("GetProduct"),
|
|
862
|
+
});
|
|
863
|
+
host.onCleanup(() => client.stop());
|
|
864
|
+
|
|
865
|
+
const execute = vi.fn(() => ({
|
|
866
|
+
structuredContent: {
|
|
867
|
+
data: { cart: { id: "1", __typename: "Cart" } },
|
|
868
|
+
},
|
|
869
|
+
}));
|
|
870
|
+
host.mockToolCall("execute", execute);
|
|
871
|
+
host.sendToolResult({
|
|
872
|
+
structuredContent: {
|
|
873
|
+
result: {
|
|
874
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
875
|
+
},
|
|
876
|
+
},
|
|
877
|
+
});
|
|
878
|
+
host.sendToolInput({ arguments: { id: "1" } });
|
|
879
|
+
|
|
880
|
+
await client.connect();
|
|
881
|
+
|
|
882
|
+
const productPromise = client.query({
|
|
883
|
+
query: productQuery,
|
|
884
|
+
variables: { id: "1" },
|
|
885
|
+
fetchPolicy: "network-only",
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
const cartPromise = client.query({
|
|
889
|
+
query: cartQuery,
|
|
890
|
+
fetchPolicy: "network-only",
|
|
891
|
+
});
|
|
892
|
+
|
|
893
|
+
await expect(productPromise).resolves.toStrictEqual({
|
|
894
|
+
data: { product: { id: "1", title: "Pen", __typename: "Product" } },
|
|
895
|
+
});
|
|
896
|
+
await expect(cartPromise).resolves.toStrictEqual({
|
|
897
|
+
data: { cart: { id: "1", __typename: "Cart" } },
|
|
898
|
+
});
|
|
899
|
+
expect(execute).toHaveBeenCalledOnce();
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
test("hydrates prefetch query with network-only fetch policy", async () => {
|
|
903
|
+
using _ = spyOnConsole("debug");
|
|
904
|
+
|
|
905
|
+
const query = gql`
|
|
906
|
+
query TopProducts @tool(description: "Shows top products") @prefetch {
|
|
907
|
+
topProducts {
|
|
908
|
+
id
|
|
909
|
+
title
|
|
910
|
+
__typename
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
`;
|
|
914
|
+
|
|
915
|
+
const data = {
|
|
916
|
+
topProducts: [{ id: "1", title: "iPhone", __typename: "Product" }],
|
|
917
|
+
};
|
|
918
|
+
|
|
919
|
+
const { client, host } = await setup({ query, toolName: "OtherTool" });
|
|
920
|
+
using _host = host;
|
|
921
|
+
|
|
922
|
+
const execute = vi.fn();
|
|
923
|
+
host.mockToolCall("execute", execute);
|
|
924
|
+
|
|
925
|
+
host.sendToolResult({
|
|
926
|
+
structuredContent: {
|
|
927
|
+
prefetch: { __anonymous: { data } },
|
|
928
|
+
},
|
|
929
|
+
});
|
|
930
|
+
host.sendToolInput({ arguments: {} });
|
|
931
|
+
|
|
932
|
+
await client.connect();
|
|
933
|
+
|
|
934
|
+
await expect(
|
|
935
|
+
client.query({ query, fetchPolicy: "network-only" })
|
|
936
|
+
).resolves.toStrictEqual({
|
|
937
|
+
data: {
|
|
938
|
+
topProducts: [{ id: "1", title: "iPhone", __typename: "Product" }],
|
|
939
|
+
},
|
|
940
|
+
});
|
|
941
|
+
expect(execute).not.toHaveBeenCalled();
|
|
942
|
+
});
|
|
943
|
+
|
|
709
944
|
describe("watchQuery dev warnings", () => {
|
|
710
945
|
const query = gql`
|
|
711
946
|
query Products($category: String!, $page: Int!, $sortBy: String!)
|
|
@@ -807,3 +1042,26 @@ describe("watchQuery dev warnings", () => {
|
|
|
807
1042
|
expect(console.warn).toHaveBeenCalledTimes(1);
|
|
808
1043
|
});
|
|
809
1044
|
});
|
|
1045
|
+
|
|
1046
|
+
async function setup({
|
|
1047
|
+
query,
|
|
1048
|
+
toolName,
|
|
1049
|
+
}: {
|
|
1050
|
+
query: DocumentNode;
|
|
1051
|
+
toolName?: string;
|
|
1052
|
+
}) {
|
|
1053
|
+
const operation = parseManifestOperation(query);
|
|
1054
|
+
const client = new ApolloClient({
|
|
1055
|
+
cache: new InMemoryCache(),
|
|
1056
|
+
manifest: mockApplicationManifest({ operations: [operation] }),
|
|
1057
|
+
});
|
|
1058
|
+
|
|
1059
|
+
const host = await mockMcpHost({
|
|
1060
|
+
hostContext: minimalHostContextWithToolName(
|
|
1061
|
+
toolName ?? operation.tools[0].name
|
|
1062
|
+
),
|
|
1063
|
+
});
|
|
1064
|
+
host.onCleanup(() => client.stop());
|
|
1065
|
+
|
|
1066
|
+
return { client, host };
|
|
1067
|
+
}
|
package/src/mcp/index.ts
CHANGED