@orpc/ai-sdk 2.0.0-beta.45 → 2.0.0-beta.46

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/README.md CHANGED
@@ -21,9 +21,40 @@
21
21
  </a>
22
22
  </div>
23
23
 
24
+ **oRPC** is a TypeScript framework for building end-to-end typesafe APIs. Write your API once as plain TypeScript functions, and oRPC gives you a fully typed client, a REST API with an OpenAPI document, and MCP tools for AI agents, with no code generation. It runs on Node.js, Bun, Deno, Cloudflare Workers, and more.
25
+
26
+ Define procedures on the server and serve them with an [RPC handler](https://orpc.dev/docs/rpc/handler):
27
+
28
+ ```ts
29
+ import { os } from '@orpc/server'
30
+ import * as z from 'zod'
31
+
32
+ export const router = {
33
+ planet: {
34
+ find: os
35
+ .input(z.object({ id: z.number() }))
36
+ .handler(({ input }) => ({ id: input.id, name: 'Earth' })),
37
+ },
38
+ }
39
+ ```
40
+
41
+ Then call them from a client that knows every input and output, without generating anything:
42
+
43
+ ```ts
44
+ import type { RouterClient } from '@orpc/server'
45
+ import type { router } from './router'
46
+ import { createORPCClient } from '@orpc/client'
47
+ import { RPCLink } from '@orpc/client/fetch'
48
+
49
+ const link = new RPCLink({ origin: 'http://localhost:3000', url: '/rpc' })
50
+ const client: RouterClient<typeof router> = createORPCClient(link)
51
+
52
+ const planet = await client.planet.find({ id: 1 }) // { id: number, name: string }
53
+ ```
54
+
24
55
  ## Documentation
25
56
 
26
- You can read the documentation [here](https://orpc.dev).
57
+ Read the full documentation at [orpc.dev](https://orpc.dev), starting with the [Getting Started guide](https://orpc.dev/docs/getting-started).
27
58
 
28
59
  ## Packages
29
60
 
@@ -56,21 +87,21 @@ You can read the documentation [here](https://orpc.dev).
56
87
 
57
88
  **Framework & ecosystem integrations**
58
89
 
59
- | Package | Purpose | Docs |
60
- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
- | [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
62
- | [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
63
- | [@orpc/mcp](https://www.npmjs.com/package/@orpc/mcp) | Expose procedures as [MCP](https://modelcontextprotocol.io/) tools. | [MCP](https://orpc.dev/docs/integrations/mcp) |
64
- | [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
65
- | [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
66
- | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
67
- | [@orpc/msw](https://www.npmjs.com/package/@orpc/msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
68
- | [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
69
- | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
70
- | [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
71
- | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock) |
72
- | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare Workers](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock), [Traces](https://orpc.dev/docs/integrations/cloudflare-traces) |
73
- | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
90
+ | Package | Purpose | Docs |
91
+ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
92
+ | [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
93
+ | [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
94
+ | [@orpc/mcp](https://www.npmjs.com/package/@orpc/mcp) | Expose procedures as [MCP](https://modelcontextprotocol.io/) tools. | [MCP](https://orpc.dev/docs/integrations/mcp) |
95
+ | [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
96
+ | [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
97
+ | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
98
+ | [@orpc/msw](https://www.npmjs.com/package/@orpc/msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
99
+ | [@orpc/effect](https://www.npmjs.com/package/@orpc/effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
100
+ | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
101
+ | [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
102
+ | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock) |
103
+ | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare Workers](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock), [Traces](https://orpc.dev/docs/integrations/cloudflare-traces) |
104
+ | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
74
105
 
75
106
  **Observability**
76
107
 
package/dist/index.d.mts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { ClientOptions } from '@orpc/client';
2
2
  import { AnySchema, ErrorMap, InferSchemaOutput, InferSchemaInput, MetaPlugin, AnyProcedureContract, Schema, ProcedureContract } from '@orpc/contract';
3
3
  import { Lazy, Context, ProcedureClientOptions, Procedure } from '@orpc/server';
4
- import { MaybeOptionalOptions } from '@orpc/shared';
4
+ import { Public, MaybeOptionalOptions } from '@orpc/shared';
5
5
  import { JSONValue, Tool } from 'ai';
6
+ import { OpenAPIJsonSerializer } from '@orpc/openapi';
6
7
 
7
8
  /**
8
9
  * The [function tool](https://ai-sdk.dev/docs/foundations/tools) member of the AI SDK `Tool` union,
@@ -66,6 +67,14 @@ declare function getAiSdkToolMeta(procedureOrLazy: AnyProcedureContract | Lazy<a
66
67
  */
67
68
  type ToolOutput<T> = T extends AsyncIteratorObject<infer TYield, any, any> ? TYield : T;
68
69
  interface ImplementToolFactoryOptions {
70
+ /**
71
+ * Serializes outputs for the default `toModelOutput`, converting types such as `Date`, `BigInt`, and `Set`
72
+ * the same way OpenAPI responses do.
73
+ *
74
+ * @default new OpenAPIJsonSerializer()
75
+ * @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-outputs | AI SDK Integration - Tool Outputs}
76
+ */
77
+ serializer?: Public<OpenAPIJsonSerializer> | undefined;
69
78
  }
70
79
  interface ToolImplementer {
71
80
  <TInputSchema extends AnySchema, TOutputSchema extends AnySchema>(contract: ProcedureContract<TInputSchema, TOutputSchema, any>, ...rest: MaybeOptionalOptions<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema'>>): Tool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>;
@@ -113,7 +122,7 @@ interface ToolImplementer {
113
122
  *
114
123
  * @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
115
124
  */
116
- declare function implementToolFactory(_options?: ImplementToolFactoryOptions): ToolImplementer;
125
+ declare function implementToolFactory(options?: ImplementToolFactoryOptions): ToolImplementer;
117
126
  type CreateToolFactoryOptions<TInitialContext extends Context> = ImplementToolFactoryOptions & ProcedureClientOptions<TInitialContext, Schema<unknown>, object, object> & Omit<ClientOptions<object>, 'context' | 'signal'>;
118
127
  interface ToolFactory<TInitialContext extends Context> {
119
128
  <TInputSchema extends AnySchema, TOutputSchema extends AnySchema>(procedure: Procedure<TInitialContext, any, TInputSchema, TOutputSchema, any>, ...rest: MaybeOptionalOptions<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema' | 'execute'>>): Tool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>;
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { ClientOptions } from '@orpc/client';
2
2
  import { AnySchema, ErrorMap, InferSchemaOutput, InferSchemaInput, MetaPlugin, AnyProcedureContract, Schema, ProcedureContract } from '@orpc/contract';
3
3
  import { Lazy, Context, ProcedureClientOptions, Procedure } from '@orpc/server';
4
- import { MaybeOptionalOptions } from '@orpc/shared';
4
+ import { Public, MaybeOptionalOptions } from '@orpc/shared';
5
5
  import { JSONValue, Tool } from 'ai';
6
+ import { OpenAPIJsonSerializer } from '@orpc/openapi';
6
7
 
7
8
  /**
8
9
  * The [function tool](https://ai-sdk.dev/docs/foundations/tools) member of the AI SDK `Tool` union,
@@ -66,6 +67,14 @@ declare function getAiSdkToolMeta(procedureOrLazy: AnyProcedureContract | Lazy<a
66
67
  */
67
68
  type ToolOutput<T> = T extends AsyncIteratorObject<infer TYield, any, any> ? TYield : T;
68
69
  interface ImplementToolFactoryOptions {
70
+ /**
71
+ * Serializes outputs for the default `toModelOutput`, converting types such as `Date`, `BigInt`, and `Set`
72
+ * the same way OpenAPI responses do.
73
+ *
74
+ * @default new OpenAPIJsonSerializer()
75
+ * @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-outputs | AI SDK Integration - Tool Outputs}
76
+ */
77
+ serializer?: Public<OpenAPIJsonSerializer> | undefined;
69
78
  }
70
79
  interface ToolImplementer {
71
80
  <TInputSchema extends AnySchema, TOutputSchema extends AnySchema>(contract: ProcedureContract<TInputSchema, TOutputSchema, any>, ...rest: MaybeOptionalOptions<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema'>>): Tool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>;
@@ -113,7 +122,7 @@ interface ToolImplementer {
113
122
  *
114
123
  * @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
115
124
  */
116
- declare function implementToolFactory(_options?: ImplementToolFactoryOptions): ToolImplementer;
125
+ declare function implementToolFactory(options?: ImplementToolFactoryOptions): ToolImplementer;
117
126
  type CreateToolFactoryOptions<TInitialContext extends Context> = ImplementToolFactoryOptions & ProcedureClientOptions<TInitialContext, Schema<unknown>, object, object> & Omit<ClientOptions<object>, 'context' | 'signal'>;
118
127
  interface ToolFactory<TInitialContext extends Context> {
119
128
  <TInputSchema extends AnySchema, TOutputSchema extends AnySchema>(procedure: Procedure<TInitialContext, any, TInputSchema, TOutputSchema, any>, ...rest: MaybeOptionalOptions<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema' | 'execute'>>): Tool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>;
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
1
  import { getAsyncIteratorObjectSchemasDetails } from '@orpc/contract';
2
2
  import { combineJsonSchemasWithComposition } from '@orpc/json-schema';
3
+ import { OpenAPIJsonSerializer } from '@orpc/openapi';
3
4
  import { Procedure, call } from '@orpc/server';
4
- import { resolveMaybeOptionalOptions, isAsyncGeneratorFunction, toArray, ORPC_NAME, mergeTwoLevels } from '@orpc/shared';
5
+ import { resolveMaybeOptionalOptions, isAsyncGeneratorFunction, toArray, ORPC_NAME, mergeTwoLevels, encodeBase64, loadBytes, stringifyJSON } from '@orpc/shared';
5
6
  import { tool } from 'ai';
6
7
 
7
8
  const aiSdkTool = (incoming) => ({
@@ -78,7 +79,30 @@ function combineOutputSchemas(outputSchemas) {
78
79
  const yieldSchemas = getAsyncIteratorObjectSchemasDetails(outputSchemas)?.yieldSchemas;
79
80
  return combineSchemas([...yieldSchemas ?? outputSchemas].reverse(), false);
80
81
  }
81
- function implementToolFactory(_options = {}) {
82
+ async function toModelOutput(serializer, output) {
83
+ const { json, maps, blobs } = serializer.serializeJson(output);
84
+ if (typeof json === "string") {
85
+ return { type: "text", value: json };
86
+ }
87
+ if (!blobs?.length) {
88
+ return { type: "json", value: json ?? null };
89
+ }
90
+ const files = await Promise.all(blobs.map(async (blob, i) => {
91
+ const path = maps[i];
92
+ const names = blob instanceof File && blob.name !== "" ? [...path, blob.name] : path;
93
+ return {
94
+ type: "file",
95
+ mediaType: blob.type || "application/octet-stream",
96
+ // base64 is encoded once, providers would otherwise re-encode the bytes on every step
97
+ data: { type: "data", data: encodeBase64(await loadBytes(blob)) },
98
+ ...names.length === 0 ? {} : { filename: names.join("/") }
99
+ };
100
+ }));
101
+ return { type: "content", value: json instanceof Blob ? files : [{ type: "text", text: stringifyJSON(json) }, ...files] };
102
+ }
103
+ function implementToolFactory(options = {}) {
104
+ const serializer = options.serializer ?? new OpenAPIJsonSerializer();
105
+ const defaultToModelOutput = ({ output }) => toModelOutput(serializer, output);
82
106
  const factory = (contract, ...rest) => {
83
107
  const toolOptions = resolveMaybeOptionalOptions(rest);
84
108
  const inputSchemas = toArray(contract["~orpc"].inputSchemas);
@@ -87,6 +111,7 @@ function implementToolFactory(_options = {}) {
87
111
  return tool({
88
112
  ...defaults,
89
113
  ...toolOptions,
114
+ toModelOutput: toolOptions.toModelOutput ?? defaults?.toModelOutput ?? defaultToModelOutput,
90
115
  inputSchema: combineSchemas(inputSchemas, true) ?? ANY_SCHEMA,
91
116
  outputSchema: combineOutputSchemas(outputSchemas)
92
117
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/ai-sdk",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.45",
4
+ "version": "2.0.0-beta.46",
5
5
  "description": "AI SDK integration for oRPC: turn contracts and procedures into typesafe AI SDK tools",
6
6
  "license": "MIT",
7
7
  "funding": [
@@ -40,11 +40,12 @@
40
40
  "ai": ">=7.0.31"
41
41
  },
42
42
  "dependencies": {
43
- "@orpc/client": "2.0.0-beta.45",
44
- "@orpc/contract": "2.0.0-beta.45",
45
- "@orpc/json-schema": "2.0.0-beta.45",
46
- "@orpc/server": "2.0.0-beta.45",
47
- "@orpc/shared": "2.0.0-beta.45"
43
+ "@orpc/client": "2.0.0-beta.46",
44
+ "@orpc/contract": "2.0.0-beta.46",
45
+ "@orpc/json-schema": "2.0.0-beta.46",
46
+ "@orpc/openapi": "2.0.0-beta.46",
47
+ "@orpc/server": "2.0.0-beta.46",
48
+ "@orpc/shared": "2.0.0-beta.46"
48
49
  },
49
50
  "devDependencies": {
50
51
  "ai": "^7.0.141",