diff --git a/.changeset/add-ai-search-type-generation.md b/.changeset/add-ai-search-type-generation.md new file mode 100644 index 0000000000..30c793a88d --- /dev/null +++ b/.changeset/add-ai-search-type-generation.md @@ -0,0 +1,27 @@ +--- +"wrangler": minor +--- + +Add type generation for AI Search bindings + +Running `wrangler types` now generates `AiSearchNamespace` and `AiSearchInstance` types for `ai_search_namespaces` and `ai_search` config bindings respectively. Both simple and per-environment modes are supported. + +```jsonc +// wrangler.json +{ + "ai_search_namespaces": [ + { "binding": "AI_SEARCH", "namespace": "production" }, + ], + "ai_search": [ + { "binding": "BLOG_SEARCH", "instance_name": "cloudflare-blog" }, + ], +} +``` + +```typescript +// Generated by `wrangler types` +interface Env { + AI_SEARCH: AiSearchNamespace; + BLOG_SEARCH: AiSearchInstance; +} +``` diff --git a/packages/wrangler/src/__tests__/type-generation.test.ts b/packages/wrangler/src/__tests__/type-generation.test.ts index adc043e42a..0ff6148a1e 100644 --- a/packages/wrangler/src/__tests__/type-generation.test.ts +++ b/packages/wrangler/src/__tests__/type-generation.test.ts @@ -440,7 +440,6 @@ const bindingsConfigMock: Omit< ], send_email: [{ name: "SEND_EMAIL_BINDING" }], vectorize: [{ binding: "VECTORIZE_BINDING", index_name: "VECTORIZE_NAME" }], - // AI Search and AI Search Namespace type generation is being done in a separate effort in ticket RAG-1028 ai_search_namespaces: [ { binding: "AI_SEARCH_NS_BINDING", namespace: "production" }, ], @@ -768,6 +767,8 @@ describe("generate types", () => { RATE_LIMITER: RateLimit; WORKER_LOADER_BINDING: WorkerLoader; VPC_SERVICE_BINDING: Fetcher; + AI_SEARCH_NS_BINDING: AiSearchNamespace; + AI_SEARCH_BINDING: AiSearchInstance; LOGFWDR_SCHEMA: any; BROWSER_BINDING: Fetcher; AI_BINDING: Ai; @@ -881,6 +882,8 @@ describe("generate types", () => { RATE_LIMITER: RateLimit; WORKER_LOADER_BINDING: WorkerLoader; VPC_SERVICE_BINDING: Fetcher; + AI_SEARCH_NS_BINDING: AiSearchNamespace; + AI_SEARCH_BINDING: AiSearchInstance; LOGFWDR_SCHEMA: any; BROWSER_BINDING: Fetcher; AI_BINDING: Ai; @@ -1057,6 +1060,8 @@ describe("generate types", () => { RATE_LIMITER: RateLimit; WORKER_LOADER_BINDING: WorkerLoader; VPC_SERVICE_BINDING: Fetcher; + AI_SEARCH_NS_BINDING: AiSearchNamespace; + AI_SEARCH_BINDING: AiSearchInstance; LOGFWDR_SCHEMA: any; BROWSER_BINDING: Fetcher; AI_BINDING: Ai; diff --git a/packages/wrangler/src/type-generation/index.ts b/packages/wrangler/src/type-generation/index.ts index 7ee780d896..744b13847b 100644 --- a/packages/wrangler/src/type-generation/index.ts +++ b/packages/wrangler/src/type-generation/index.ts @@ -1869,6 +1869,43 @@ function collectCoreBindings( addBinding(vpcService.binding, "Fetcher", "vpc_services", envName); } + for (const [index, aiSearchNamespace] of ( + env.ai_search_namespaces ?? [] + ).entries()) { + if (!aiSearchNamespace.binding) { + throwMissingBindingError({ + binding: aiSearchNamespace, + bindingType: "ai_search_namespaces", + configPath: args.config, + envName, + fieldName: "binding", + index, + }); + } + + addBinding( + aiSearchNamespace.binding, + "AiSearchNamespace", + "ai_search_namespaces", + envName + ); + } + + for (const [index, aiSearch] of (env.ai_search ?? []).entries()) { + if (!aiSearch.binding) { + throwMissingBindingError({ + binding: aiSearch, + bindingType: "ai_search", + configPath: args.config, + envName, + fieldName: "binding", + index, + }); + } + + addBinding(aiSearch.binding, "AiSearchInstance", "ai_search", envName); + } + // Pipelines handled separately for async schema fetching if (env.logfwdr?.bindings?.length) { @@ -2913,6 +2950,46 @@ function collectCoreBindingsPerEnvironment( }); } + for (const [index, aiSearchNamespace] of ( + env.ai_search_namespaces ?? [] + ).entries()) { + if (!aiSearchNamespace.binding) { + throwMissingBindingError({ + binding: aiSearchNamespace, + bindingType: "ai_search_namespaces", + configPath: args.config, + envName, + fieldName: "binding", + index, + }); + } + + bindings.push({ + bindingCategory: "ai_search_namespaces", + name: aiSearchNamespace.binding, + type: "AiSearchNamespace", + }); + } + + for (const [index, aiSearch] of (env.ai_search ?? []).entries()) { + if (!aiSearch.binding) { + throwMissingBindingError({ + binding: aiSearch, + bindingType: "ai_search", + configPath: args.config, + envName, + fieldName: "binding", + index, + }); + } + + bindings.push({ + bindingCategory: "ai_search", + name: aiSearch.binding, + type: "AiSearchInstance", + }); + } + return bindings; }