@orpc/ai-sdk 2.0.0-beta.47 → 2.0.0-beta.48
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 +2 -3
- package/dist/index.d.mts +2 -172
- package/dist/index.mjs +2 -148
- package/dist/tool-meta.d.mts +68 -0
- package/dist/tool-meta.mjs +18 -0
- package/dist/tool.d.mts +125 -0
- package/dist/tool.mjs +154 -0
- package/package.json +8 -8
- package/dist/index.d.ts +0 -172
package/README.md
CHANGED
|
@@ -191,15 +191,14 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
|
|
|
191
191
|
<td align="center"><a href="https://kellychan.im/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Kelly Peilin Chan"><img src="https://avatars.githubusercontent.com/u/520852?u=6b0f7105f694e7b5cacf410a3f04c7044b469dc8&v=4" width="139" alt="Kelly Peilin Chan"/><br />Kelly Peilin Chan</a></td>
|
|
192
192
|
<td align="center"><a href="https://guyariely.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guy Ariely"><img src="https://avatars.githubusercontent.com/u/42813496?u=edb6b7f563bf28e160a290832e7da57c0506f8ca&v=4" width="139" alt="Guy Ariely"/><br />Guy Ariely</a></td>
|
|
193
193
|
<td align="center"><a href="https://paulsenon.com/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="PaulSenon"><img src="https://avatars.githubusercontent.com/u/19531087?u=6385741eb91d200b8c513ec6045482e301767ca6&v=4" width="139" alt="PaulSenon"/><br />PaulSenon</a></td>
|
|
194
|
-
<td align="center"><a href="https://
|
|
194
|
+
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="139" alt="Alex"/><br />Alex</a></td>
|
|
195
195
|
</tr>
|
|
196
196
|
<tr>
|
|
197
|
-
<td align="center"><a href="https://piscis.dev/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Alex"><img src="https://avatars.githubusercontent.com/u/326163?u=b245f368bd940cf51d08c0b6bf55f8257f359437&v=4" width="139" alt="Alex"/><br />Alex</a></td>
|
|
198
197
|
<td align="center"><a href="https://opensource.gubanov.eu/?ref=middleapi&utm_source=middleapi&utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Andrey Gubanov"><img src="https://avatars.githubusercontent.com/u/1082083?u=c5f2daf7ebece498e85c83367bb37b4e10e2649d&v=4" width="139" alt="Andrey Gubanov"/><br />Andrey Gubanov</a></td>
|
|
199
198
|
</tr>
|
|
200
199
|
</table>
|
|
201
200
|
|
|
202
|
-
With thanks to [
|
|
201
|
+
With thanks to [40 past sponsors](https://orpc.dev/sponsors#past-sponsors) who helped get oRPC here.
|
|
203
202
|
|
|
204
203
|
## Open Source Programs
|
|
205
204
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,172 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { Lazy, Context, ProcedureClientOptions, Procedure } from '@orpc/server';
|
|
4
|
-
import { Public, MaybeOptionalOptions } from '@orpc/shared';
|
|
5
|
-
import { JSONValue, Tool } from 'ai';
|
|
6
|
-
import { OpenAPIJsonSerializer } from '@orpc/openapi';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The [function tool](https://ai-sdk.dev/docs/foundations/tools) member of the AI SDK `Tool` union,
|
|
10
|
-
* which is the kind of tool this package produces.
|
|
11
|
-
*/
|
|
12
|
-
type FunctionTool<INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any> = Extract<Tool<INPUT, OUTPUT>, {
|
|
13
|
-
type?: 'function' | undefined;
|
|
14
|
-
}>;
|
|
15
|
-
/**
|
|
16
|
-
* Base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options attached to a procedure/contract,
|
|
17
|
-
* used as defaults when creating tools from it.
|
|
18
|
-
*
|
|
19
|
-
* @remarks
|
|
20
|
-
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
21
|
-
*
|
|
22
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
23
|
-
*/
|
|
24
|
-
type AiSdkToolMeta<TInputSchema extends AnySchema = AnySchema, TOutputSchema extends AnySchema = AnySchema> = Partial<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema' | 'execute'>>;
|
|
25
|
-
interface AiSdkToolMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
26
|
-
name: '~ai-sdk/tool';
|
|
27
|
-
}
|
|
28
|
-
interface AiSdkToolFunction {
|
|
29
|
-
<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap>(meta: AiSdkToolMeta<TInputSchema, TOutputSchema>): AiSdkToolMetaPlugin<TInputSchema, TOutputSchema, TErrorMap>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Attaches base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options to a procedure/contract,
|
|
33
|
-
* used as defaults when creating tools from it.
|
|
34
|
-
*
|
|
35
|
-
* @remarks
|
|
36
|
-
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* const getWeatherContract = oc
|
|
41
|
-
* .meta(aiSdkTool({
|
|
42
|
-
* description: 'Get the weather in a location',
|
|
43
|
-
* metadata: { source: 'weather-service' },
|
|
44
|
-
* }))
|
|
45
|
-
* .input(z.object({ location: z.string() }))
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
49
|
-
*/
|
|
50
|
-
declare const aiSdkTool: AiSdkToolFunction;
|
|
51
|
-
/**
|
|
52
|
-
* Reads the base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options
|
|
53
|
-
* attached to a procedure/contract by {@link aiSdkTool}.
|
|
54
|
-
*
|
|
55
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
56
|
-
*/
|
|
57
|
-
declare function getAiSdkToolMeta(procedureOrLazy: AnyProcedureContract | Lazy<any>): AiSdkToolMeta | undefined;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Infers the value an AI SDK tool outputs for a given oRPC output type.
|
|
61
|
-
*
|
|
62
|
-
* For [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object) outputs, the tool streams
|
|
63
|
-
* each yielded event as a [preliminary result](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#preliminary-tool-results)
|
|
64
|
-
* and the last event becomes the final result, so the tool output is the yield type.
|
|
65
|
-
*
|
|
66
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#streaming-tool-outputs | AI SDK Integration - Streaming Tool Outputs}
|
|
67
|
-
*/
|
|
68
|
-
type ToolOutput<T> = T extends AsyncIteratorObject<infer TYield, any, any> ? TYield : T;
|
|
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;
|
|
78
|
-
}
|
|
79
|
-
interface ToolImplementer {
|
|
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>>>;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Creates a builder that implements [procedure contracts](https://orpc.dev/docs/contract/procedure)
|
|
84
|
-
* as [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing contract definitions.
|
|
85
|
-
*
|
|
86
|
-
* The factory accepts oRPC related options, and the resulting builder
|
|
87
|
-
* accepts a contract alongside AI SDK tool options.
|
|
88
|
-
*
|
|
89
|
-
* @remarks
|
|
90
|
-
* **Note**: [Procedures](https://orpc.dev/docs/procedure) are also compatible with [procedure contracts](https://orpc.dev/docs/contract/procedure).
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```ts
|
|
94
|
-
* import { aiSdkTool, implementToolFactory } from '@orpc/ai-sdk'
|
|
95
|
-
* import { oc } from '@orpc/contract'
|
|
96
|
-
*
|
|
97
|
-
* const getWeatherContract = oc
|
|
98
|
-
* .meta(
|
|
99
|
-
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
100
|
-
* )
|
|
101
|
-
* .input(
|
|
102
|
-
* z.object({
|
|
103
|
-
* location: z.string().describe('The location to get the weather for'),
|
|
104
|
-
* }),
|
|
105
|
-
* )
|
|
106
|
-
* .output(
|
|
107
|
-
* z.object({
|
|
108
|
-
* location: z.string().describe('The location the weather is for'),
|
|
109
|
-
* temperature: z.number().describe('The temperature in Celsius'),
|
|
110
|
-
* }),
|
|
111
|
-
* )
|
|
112
|
-
*
|
|
113
|
-
* const implementTool = implementToolFactory()
|
|
114
|
-
*
|
|
115
|
-
* const getWeatherTool = implementTool(getWeatherContract, {
|
|
116
|
-
* execute: async ({ location }) => ({
|
|
117
|
-
* location,
|
|
118
|
-
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
119
|
-
* }),
|
|
120
|
-
* })
|
|
121
|
-
* ```
|
|
122
|
-
*
|
|
123
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
124
|
-
*/
|
|
125
|
-
declare function implementToolFactory(options?: ImplementToolFactoryOptions): ToolImplementer;
|
|
126
|
-
type CreateToolFactoryOptions<TInitialContext extends Context> = ImplementToolFactoryOptions & ProcedureClientOptions<TInitialContext, Schema<unknown>, object, object> & Omit<ClientOptions<object>, 'context' | 'signal'>;
|
|
127
|
-
interface ToolFactory<TInitialContext extends Context> {
|
|
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>>>;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Creates a builder that converts [procedures](https://orpc.dev/docs/procedure)
|
|
132
|
-
* into [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing procedure definitions.
|
|
133
|
-
*
|
|
134
|
-
* The factory accepts oRPC related options, and the resulting builder
|
|
135
|
-
* accepts a procedure alongside AI SDK tool options.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* import { aiSdkTool, createToolFactory } from '@orpc/ai-sdk'
|
|
140
|
-
* import { os } from '@orpc/server'
|
|
141
|
-
*
|
|
142
|
-
* const getWeatherProcedure = os
|
|
143
|
-
* .meta(
|
|
144
|
-
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
145
|
-
* )
|
|
146
|
-
* .input(z.object({
|
|
147
|
-
* location: z.string().describe('The location to get the weather for'),
|
|
148
|
-
* }))
|
|
149
|
-
* .output(z.object({
|
|
150
|
-
* location: z.string().describe('The location the weather is for'),
|
|
151
|
-
* temperature: z.number().describe('The temperature in Celsius'),
|
|
152
|
-
* }))
|
|
153
|
-
* .handler(async ({ input }) => ({
|
|
154
|
-
* location: input.location,
|
|
155
|
-
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
156
|
-
* }))
|
|
157
|
-
*
|
|
158
|
-
* const createTool = createToolFactory({
|
|
159
|
-
* context: {}, // provide initial context if needed
|
|
160
|
-
* })
|
|
161
|
-
*
|
|
162
|
-
* const getWeatherTool = createTool(getWeatherProcedure, {
|
|
163
|
-
* // ...AI SDK tool options/overrides here if needed
|
|
164
|
-
* })
|
|
165
|
-
* ```
|
|
166
|
-
*
|
|
167
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-factory | AI SDK Integration - Tool Factory}
|
|
168
|
-
*/
|
|
169
|
-
declare function createToolFactory<TInitialContext extends Context = object>(...rest: MaybeOptionalOptions<CreateToolFactoryOptions<TInitialContext>>): ToolFactory<TInitialContext>;
|
|
170
|
-
|
|
171
|
-
export { aiSdkTool, createToolFactory, getAiSdkToolMeta, implementToolFactory };
|
|
172
|
-
export type { AiSdkToolFunction, AiSdkToolMeta, AiSdkToolMetaPlugin, CreateToolFactoryOptions, FunctionTool, ImplementToolFactoryOptions, ToolFactory, ToolImplementer, ToolOutput };
|
|
1
|
+
export * from "./tool.mjs";
|
|
2
|
+
export * from "./tool-meta.mjs";
|
package/dist/index.mjs
CHANGED
|
@@ -1,148 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { OpenAPIJsonSerializer } from '@orpc/openapi';
|
|
4
|
-
import { Procedure, call } from '@orpc/server';
|
|
5
|
-
import { resolveMaybeOptionalOptions, isAsyncGeneratorFunction, toArray, ORPC_NAME, mergeTwoLevels, encodeBase64, loadBytes, stringifyJSON } from '@orpc/shared';
|
|
6
|
-
import { tool } from 'ai';
|
|
7
|
-
|
|
8
|
-
const aiSdkTool = (incoming) => ({
|
|
9
|
-
name: "~ai-sdk/tool",
|
|
10
|
-
init(meta) {
|
|
11
|
-
const existing = meta["~ai-sdk/tool"];
|
|
12
|
-
return {
|
|
13
|
-
...meta,
|
|
14
|
-
"~ai-sdk/tool": { ...existing, ...incoming }
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
function getAiSdkToolMeta(procedureOrLazy) {
|
|
19
|
-
return procedureOrLazy["~orpc"].meta["~ai-sdk/tool"];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const ANY_SCHEMA = {
|
|
23
|
-
"~standard": {
|
|
24
|
-
vendor: ORPC_NAME,
|
|
25
|
-
version: 1,
|
|
26
|
-
validate: (value) => ({ value }),
|
|
27
|
-
jsonSchema: {
|
|
28
|
-
input: () => ({}),
|
|
29
|
-
output: () => ({})
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
};
|
|
33
|
-
function combineJsonSchemas(jsonSchemas) {
|
|
34
|
-
let $schema;
|
|
35
|
-
const branches = jsonSchemas.map((jsonSchema) => {
|
|
36
|
-
if ("$schema" in jsonSchema) {
|
|
37
|
-
const { $schema: branch$schema, ...rest } = jsonSchema;
|
|
38
|
-
$schema ??= branch$schema;
|
|
39
|
-
return rest;
|
|
40
|
-
}
|
|
41
|
-
return jsonSchema;
|
|
42
|
-
});
|
|
43
|
-
const combined = combineJsonSchemasWithComposition("allOf", branches);
|
|
44
|
-
return { $schema, ...combined };
|
|
45
|
-
}
|
|
46
|
-
function combineSchemas(schemas, merge) {
|
|
47
|
-
if (schemas.length === 0) {
|
|
48
|
-
return void 0;
|
|
49
|
-
}
|
|
50
|
-
if (schemas.length === 1) {
|
|
51
|
-
return schemas[0];
|
|
52
|
-
}
|
|
53
|
-
const standardJsonSchemas = schemas.filter((schema) => schema["~standard"].jsonSchema);
|
|
54
|
-
const jsonSchema = standardJsonSchemas.length ? {
|
|
55
|
-
input: (options) => combineJsonSchemas(standardJsonSchemas.map((schema) => schema["~standard"].jsonSchema.input(options))),
|
|
56
|
-
output: (options) => combineJsonSchemas(standardJsonSchemas.map((schema) => schema["~standard"].jsonSchema.output(options)))
|
|
57
|
-
} : void 0;
|
|
58
|
-
return {
|
|
59
|
-
"~standard": {
|
|
60
|
-
vendor: ORPC_NAME,
|
|
61
|
-
version: 1,
|
|
62
|
-
async validate(value) {
|
|
63
|
-
let current = value;
|
|
64
|
-
for (const [index, schema] of schemas.entries()) {
|
|
65
|
-
const merging = merge && index !== 0;
|
|
66
|
-
const result = await schema["~standard"].validate(merging ? mergeTwoLevels(value, current) : current);
|
|
67
|
-
if (result.issues) {
|
|
68
|
-
return result;
|
|
69
|
-
}
|
|
70
|
-
current = merging ? mergeTwoLevels(current, result.value) : result.value;
|
|
71
|
-
}
|
|
72
|
-
return { value: current };
|
|
73
|
-
},
|
|
74
|
-
jsonSchema
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
function combineOutputSchemas(outputSchemas) {
|
|
79
|
-
const yieldSchemas = getAsyncIteratorObjectSchemasDetails(outputSchemas)?.yieldSchemas;
|
|
80
|
-
return combineSchemas([...yieldSchemas ?? outputSchemas].reverse(), false);
|
|
81
|
-
}
|
|
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);
|
|
106
|
-
const factory = (contract, ...rest) => {
|
|
107
|
-
const toolOptions = resolveMaybeOptionalOptions(rest);
|
|
108
|
-
const inputSchemas = toArray(contract["~orpc"].inputSchemas);
|
|
109
|
-
const outputSchemas = toArray(contract["~orpc"].outputSchemas);
|
|
110
|
-
const defaults = getAiSdkToolMeta(contract);
|
|
111
|
-
return tool({
|
|
112
|
-
...defaults,
|
|
113
|
-
...toolOptions,
|
|
114
|
-
toModelOutput: toolOptions.toModelOutput ?? defaults?.toModelOutput ?? defaultToModelOutput,
|
|
115
|
-
inputSchema: combineSchemas(inputSchemas, true) ?? ANY_SCHEMA,
|
|
116
|
-
outputSchema: combineOutputSchemas(outputSchemas)
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
return factory;
|
|
120
|
-
}
|
|
121
|
-
function createToolFactory(...rest) {
|
|
122
|
-
const options = resolveMaybeOptionalOptions(rest);
|
|
123
|
-
const implementTool = implementToolFactory(options);
|
|
124
|
-
const factory = (procedure, ...rest2) => {
|
|
125
|
-
const toolOptions = resolveMaybeOptionalOptions(rest2);
|
|
126
|
-
const disabledValidation = new Procedure({
|
|
127
|
-
...procedure["~orpc"],
|
|
128
|
-
disableInputValidation: true
|
|
129
|
-
});
|
|
130
|
-
const isIteratorOutput = getAsyncIteratorObjectSchemasDetails(procedure["~orpc"].outputSchemas) !== void 0 || isAsyncGeneratorFunction(procedure["~orpc"].handler);
|
|
131
|
-
return implementTool(procedure, {
|
|
132
|
-
...toolOptions,
|
|
133
|
-
/**
|
|
134
|
-
* For async iterator outputs, the tool streams each event as a
|
|
135
|
-
* [preliminary result](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#preliminary-tool-results),
|
|
136
|
-
* and the last event becomes the final result.
|
|
137
|
-
*/
|
|
138
|
-
execute: isIteratorOutput ? async function* (input, callingOptions) {
|
|
139
|
-
yield* await call(disabledValidation, input, { ...options, signal: callingOptions.abortSignal });
|
|
140
|
-
} : (input, callingOptions) => {
|
|
141
|
-
return call(disabledValidation, input, { ...options, signal: callingOptions.abortSignal });
|
|
142
|
-
}
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
return factory;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export { aiSdkTool, createToolFactory, getAiSdkToolMeta, implementToolFactory };
|
|
1
|
+
export * from "./tool.mjs";
|
|
2
|
+
export * from "./tool-meta.mjs";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { AnyProcedureContract, AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, MetaPlugin } from "@orpc/contract";
|
|
2
|
+
import type { Lazy } from "@orpc/server";
|
|
3
|
+
import type { JSONValue, Tool } from "ai";
|
|
4
|
+
import type { ToolOutput } from "./tool.mjs";
|
|
5
|
+
/**
|
|
6
|
+
* The [function tool](https://ai-sdk.dev/docs/foundations/tools) member of the AI SDK `Tool` union,
|
|
7
|
+
* which is the kind of tool this package produces.
|
|
8
|
+
*/
|
|
9
|
+
export type FunctionTool<
|
|
10
|
+
INPUT extends JSONValue | unknown | never = any,
|
|
11
|
+
OUTPUT extends JSONValue | unknown | never = any
|
|
12
|
+
> = Extract<Tool<INPUT, OUTPUT>, {
|
|
13
|
+
type?: "function" | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options attached to a procedure/contract,
|
|
17
|
+
* used as defaults when creating tools from it.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
21
|
+
*
|
|
22
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
23
|
+
*/
|
|
24
|
+
export type AiSdkToolMeta<
|
|
25
|
+
TInputSchema extends AnySchema = AnySchema,
|
|
26
|
+
TOutputSchema extends AnySchema = AnySchema
|
|
27
|
+
> = Partial<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, "inputSchema" | "outputSchema" | "execute">>;
|
|
28
|
+
export interface AiSdkToolMetaPlugin<
|
|
29
|
+
TInputSchema extends AnySchema,
|
|
30
|
+
TOutputSchema extends AnySchema,
|
|
31
|
+
TErrorMap extends ErrorMap
|
|
32
|
+
> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
33
|
+
name: "~ai-sdk/tool";
|
|
34
|
+
}
|
|
35
|
+
export interface AiSdkToolFunction {
|
|
36
|
+
<
|
|
37
|
+
TInputSchema extends AnySchema,
|
|
38
|
+
TOutputSchema extends AnySchema,
|
|
39
|
+
TErrorMap extends ErrorMap
|
|
40
|
+
>(meta: AiSdkToolMeta<TInputSchema, TOutputSchema>): AiSdkToolMetaPlugin<TInputSchema, TOutputSchema, TErrorMap>;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Attaches base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options to a procedure/contract,
|
|
44
|
+
* used as defaults when creating tools from it.
|
|
45
|
+
*
|
|
46
|
+
* @remarks
|
|
47
|
+
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* const getWeatherContract = oc
|
|
52
|
+
* .meta(aiSdkTool({
|
|
53
|
+
* description: 'Get the weather in a location',
|
|
54
|
+
* metadata: { source: 'weather-service' },
|
|
55
|
+
* }))
|
|
56
|
+
* .input(z.object({ location: z.string() }))
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
60
|
+
*/
|
|
61
|
+
export declare const aiSdkTool: AiSdkToolFunction;
|
|
62
|
+
/**
|
|
63
|
+
* Reads the base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options
|
|
64
|
+
* attached to a procedure/contract by {@link aiSdkTool}.
|
|
65
|
+
*
|
|
66
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
67
|
+
*/
|
|
68
|
+
export declare function getAiSdkToolMeta(procedureOrLazy: AnyProcedureContract | Lazy<any>): AiSdkToolMeta | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
export const aiSdkTool = (incoming) => ({
|
|
3
|
+
name: "~ai-sdk/tool",
|
|
4
|
+
init(meta) {
|
|
5
|
+
const existing = meta["~ai-sdk/tool"];
|
|
6
|
+
return {
|
|
7
|
+
...meta,
|
|
8
|
+
"~ai-sdk/tool": {
|
|
9
|
+
...existing,
|
|
10
|
+
...incoming
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export function getAiSdkToolMeta(procedureOrLazy) {
|
|
17
|
+
return procedureOrLazy["~orpc"].meta["~ai-sdk/tool"];
|
|
18
|
+
}
|
package/dist/tool.d.mts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { ClientOptions } from "@orpc/client";
|
|
2
|
+
import type { AnySchema, InferSchemaInput, InferSchemaOutput, ProcedureContract, Schema } from "@orpc/contract";
|
|
3
|
+
import type { Context, ProcedureClientOptions } from "@orpc/server";
|
|
4
|
+
import type { MaybeOptionalOptions, Public } from "@orpc/shared";
|
|
5
|
+
import type { Tool } from "ai";
|
|
6
|
+
import type { FunctionTool } from "./tool-meta.mjs";
|
|
7
|
+
import { OpenAPIJsonSerializer } from "@orpc/openapi";
|
|
8
|
+
import { Procedure } from "@orpc/server";
|
|
9
|
+
/**
|
|
10
|
+
* Infers the value an AI SDK tool outputs for a given oRPC output type.
|
|
11
|
+
*
|
|
12
|
+
* For [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object) outputs, the tool streams
|
|
13
|
+
* each yielded event as a [preliminary result](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#preliminary-tool-results)
|
|
14
|
+
* and the last event becomes the final result, so the tool output is the yield type.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#streaming-tool-outputs | AI SDK Integration - Streaming Tool Outputs}
|
|
17
|
+
*/
|
|
18
|
+
export type ToolOutput<T> = T extends AsyncIteratorObject<infer TYield, any, any> ? TYield : T;
|
|
19
|
+
export interface ImplementToolFactoryOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Serializes outputs for the default `toModelOutput`, converting types such as `Date`, `BigInt`, and `Set`
|
|
22
|
+
* the same way OpenAPI responses do.
|
|
23
|
+
*
|
|
24
|
+
* @default new OpenAPIJsonSerializer()
|
|
25
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-outputs | AI SDK Integration - Tool Outputs}
|
|
26
|
+
*/
|
|
27
|
+
serializer?: Public<OpenAPIJsonSerializer> | undefined;
|
|
28
|
+
}
|
|
29
|
+
export interface ToolImplementer {
|
|
30
|
+
<
|
|
31
|
+
TInputSchema extends AnySchema,
|
|
32
|
+
TOutputSchema extends AnySchema
|
|
33
|
+
>(contract: ProcedureContract<TInputSchema, TOutputSchema, any>, ...rest: MaybeOptionalOptions<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, "inputSchema" | "outputSchema">>): Tool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a builder that implements [procedure contracts](https://orpc.dev/docs/contract/procedure)
|
|
37
|
+
* as [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing contract definitions.
|
|
38
|
+
*
|
|
39
|
+
* The factory accepts oRPC related options, and the resulting builder
|
|
40
|
+
* accepts a contract alongside AI SDK tool options.
|
|
41
|
+
*
|
|
42
|
+
* @remarks
|
|
43
|
+
* **Note**: [Procedures](https://orpc.dev/docs/procedure) are also compatible with [procedure contracts](https://orpc.dev/docs/contract/procedure).
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { aiSdkTool, implementToolFactory } from '@orpc/ai-sdk'
|
|
48
|
+
* import { oc } from '@orpc/contract'
|
|
49
|
+
*
|
|
50
|
+
* const getWeatherContract = oc
|
|
51
|
+
* .meta(
|
|
52
|
+
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
53
|
+
* )
|
|
54
|
+
* .input(
|
|
55
|
+
* z.object({
|
|
56
|
+
* location: z.string().describe('The location to get the weather for'),
|
|
57
|
+
* }),
|
|
58
|
+
* )
|
|
59
|
+
* .output(
|
|
60
|
+
* z.object({
|
|
61
|
+
* location: z.string().describe('The location the weather is for'),
|
|
62
|
+
* temperature: z.number().describe('The temperature in Celsius'),
|
|
63
|
+
* }),
|
|
64
|
+
* )
|
|
65
|
+
*
|
|
66
|
+
* const implementTool = implementToolFactory()
|
|
67
|
+
*
|
|
68
|
+
* const getWeatherTool = implementTool(getWeatherContract, {
|
|
69
|
+
* execute: async ({ location }) => ({
|
|
70
|
+
* location,
|
|
71
|
+
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
72
|
+
* }),
|
|
73
|
+
* })
|
|
74
|
+
* ```
|
|
75
|
+
*
|
|
76
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
77
|
+
*/
|
|
78
|
+
export declare function implementToolFactory(options?: ImplementToolFactoryOptions): ToolImplementer;
|
|
79
|
+
export type CreateToolFactoryOptions<TInitialContext extends Context> = ImplementToolFactoryOptions & ProcedureClientOptions<TInitialContext, Schema<unknown>, object, object> & Omit<ClientOptions<object>, "context" | "signal">;
|
|
80
|
+
export interface ToolFactory<TInitialContext extends Context> {
|
|
81
|
+
<
|
|
82
|
+
TInputSchema extends AnySchema,
|
|
83
|
+
TOutputSchema extends AnySchema
|
|
84
|
+
>(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>>>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Creates a builder that converts [procedures](https://orpc.dev/docs/procedure)
|
|
88
|
+
* into [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing procedure definitions.
|
|
89
|
+
*
|
|
90
|
+
* The factory accepts oRPC related options, and the resulting builder
|
|
91
|
+
* accepts a procedure alongside AI SDK tool options.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { aiSdkTool, createToolFactory } from '@orpc/ai-sdk'
|
|
96
|
+
* import { os } from '@orpc/server'
|
|
97
|
+
*
|
|
98
|
+
* const getWeatherProcedure = os
|
|
99
|
+
* .meta(
|
|
100
|
+
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
101
|
+
* )
|
|
102
|
+
* .input(z.object({
|
|
103
|
+
* location: z.string().describe('The location to get the weather for'),
|
|
104
|
+
* }))
|
|
105
|
+
* .output(z.object({
|
|
106
|
+
* location: z.string().describe('The location the weather is for'),
|
|
107
|
+
* temperature: z.number().describe('The temperature in Celsius'),
|
|
108
|
+
* }))
|
|
109
|
+
* .handler(async ({ input }) => ({
|
|
110
|
+
* location: input.location,
|
|
111
|
+
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
112
|
+
* }))
|
|
113
|
+
*
|
|
114
|
+
* const createTool = createToolFactory({
|
|
115
|
+
* context: {}, // provide initial context if needed
|
|
116
|
+
* })
|
|
117
|
+
*
|
|
118
|
+
* const getWeatherTool = createTool(getWeatherProcedure, {
|
|
119
|
+
* // ...AI SDK tool options/overrides here if needed
|
|
120
|
+
* })
|
|
121
|
+
* ```
|
|
122
|
+
*
|
|
123
|
+
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-factory | AI SDK Integration - Tool Factory}
|
|
124
|
+
*/
|
|
125
|
+
export declare function createToolFactory<TInitialContext extends Context = object>(...rest: MaybeOptionalOptions<CreateToolFactoryOptions<TInitialContext>>): ToolFactory<TInitialContext>;
|
package/dist/tool.mjs
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { getAsyncIteratorObjectSchemasDetails } from "@orpc/contract";
|
|
2
|
+
import { combineJsonSchemasWithComposition } from "@orpc/json-schema";
|
|
3
|
+
import { OpenAPIJsonSerializer } from "@orpc/openapi";
|
|
4
|
+
import { call, Procedure } from "@orpc/server";
|
|
5
|
+
import { encodeBase64, isAsyncGeneratorFunction, loadBytes, mergeTwoLevels, ORPC_NAME, resolveMaybeOptionalOptions, stringifyJSON, toArray } from "@orpc/shared";
|
|
6
|
+
import { tool } from "ai";
|
|
7
|
+
import { getAiSdkToolMeta } from "./tool-meta.mjs";
|
|
8
|
+
const ANY_SCHEMA = { "~standard": {
|
|
9
|
+
vendor: ORPC_NAME,
|
|
10
|
+
version: 1,
|
|
11
|
+
validate: (value) => ({ value }),
|
|
12
|
+
jsonSchema: {
|
|
13
|
+
input: () => ({}),
|
|
14
|
+
output: () => ({})
|
|
15
|
+
}
|
|
16
|
+
} };
|
|
17
|
+
function combineJsonSchemas(jsonSchemas) {
|
|
18
|
+
let $schema;
|
|
19
|
+
const branches = jsonSchemas.map((jsonSchema) => {
|
|
20
|
+
if ("$schema" in jsonSchema) {
|
|
21
|
+
const { $schema: branch$schema, ...rest } = jsonSchema;
|
|
22
|
+
$schema ??= branch$schema;
|
|
23
|
+
return rest;
|
|
24
|
+
}
|
|
25
|
+
return jsonSchema;
|
|
26
|
+
});
|
|
27
|
+
const combined = combineJsonSchemasWithComposition("allOf", branches);
|
|
28
|
+
return {
|
|
29
|
+
$schema,
|
|
30
|
+
...combined
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function combineSchemas(schemas, merge) {
|
|
34
|
+
if (schemas.length === 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
if (schemas.length === 1) {
|
|
38
|
+
return schemas[0];
|
|
39
|
+
}
|
|
40
|
+
const standardJsonSchemas = schemas.filter((schema) => schema["~standard"].jsonSchema);
|
|
41
|
+
const jsonSchema = standardJsonSchemas.length ? {
|
|
42
|
+
input: (options) => combineJsonSchemas(standardJsonSchemas.map((schema) => schema["~standard"].jsonSchema.input(options))),
|
|
43
|
+
output: (options) => combineJsonSchemas(standardJsonSchemas.map((schema) => schema["~standard"].jsonSchema.output(options)))
|
|
44
|
+
} : undefined;
|
|
45
|
+
return { "~standard": {
|
|
46
|
+
vendor: ORPC_NAME,
|
|
47
|
+
version: 1,
|
|
48
|
+
async validate(value) {
|
|
49
|
+
let current = value;
|
|
50
|
+
|
|
51
|
+
for (const [index, schema] of schemas.entries()) {
|
|
52
|
+
const merging = merge && index !== 0;
|
|
53
|
+
const result = await schema["~standard"].validate(merging ? mergeTwoLevels(value, current) : current);
|
|
54
|
+
if (result.issues) {
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
current = merging ? mergeTwoLevels(current, result.value) : result.value;
|
|
58
|
+
}
|
|
59
|
+
return { value: current };
|
|
60
|
+
},
|
|
61
|
+
jsonSchema
|
|
62
|
+
} };
|
|
63
|
+
}
|
|
64
|
+
function combineOutputSchemas(outputSchemas) {
|
|
65
|
+
const yieldSchemas = getAsyncIteratorObjectSchemasDetails(outputSchemas)?.yieldSchemas;
|
|
66
|
+
return combineSchemas([...yieldSchemas ?? outputSchemas].reverse(), false);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async function toModelOutput(serializer, output) {
|
|
70
|
+
const { json, maps, blobs } = serializer.serializeJson(output);
|
|
71
|
+
if (typeof json === "string") {
|
|
72
|
+
return {
|
|
73
|
+
type: "text",
|
|
74
|
+
value: json
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
if (!blobs?.length) {
|
|
78
|
+
return {
|
|
79
|
+
type: "json",
|
|
80
|
+
value: json ?? null
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const files = await Promise.all(blobs.map(async (blob, i) => {
|
|
84
|
+
const path = maps[i];
|
|
85
|
+
const names = blob instanceof File && blob.name !== "" ? [...path, blob.name] : path;
|
|
86
|
+
return {
|
|
87
|
+
type: "file",
|
|
88
|
+
mediaType: blob.type || "application/octet-stream",
|
|
89
|
+
|
|
90
|
+
data: {
|
|
91
|
+
type: "data",
|
|
92
|
+
data: encodeBase64(await loadBytes(blob))
|
|
93
|
+
},
|
|
94
|
+
...names.length === 0 ? {} : { filename: names.join("/") }
|
|
95
|
+
};
|
|
96
|
+
}));
|
|
97
|
+
return {
|
|
98
|
+
type: "content",
|
|
99
|
+
value: json instanceof Blob ? files : [{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: stringifyJSON(json)
|
|
102
|
+
}, ...files]
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function implementToolFactory(options = {}) {
|
|
107
|
+
const serializer = options.serializer ?? new OpenAPIJsonSerializer();
|
|
108
|
+
const defaultToModelOutput = ({ output }) => toModelOutput(serializer, output);
|
|
109
|
+
const factory = (contract, ...rest) => {
|
|
110
|
+
const toolOptions = resolveMaybeOptionalOptions(rest);
|
|
111
|
+
const inputSchemas = toArray(contract["~orpc"].inputSchemas);
|
|
112
|
+
const outputSchemas = toArray(contract["~orpc"].outputSchemas);
|
|
113
|
+
const defaults = getAiSdkToolMeta(contract);
|
|
114
|
+
return tool({
|
|
115
|
+
...defaults,
|
|
116
|
+
...toolOptions,
|
|
117
|
+
toModelOutput: toolOptions.toModelOutput ?? defaults?.toModelOutput ?? defaultToModelOutput,
|
|
118
|
+
inputSchema: combineSchemas(inputSchemas, true) ?? ANY_SCHEMA,
|
|
119
|
+
outputSchema: combineOutputSchemas(outputSchemas)
|
|
120
|
+
});
|
|
121
|
+
};
|
|
122
|
+
return factory;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function createToolFactory(...rest) {
|
|
126
|
+
const options = resolveMaybeOptionalOptions(rest);
|
|
127
|
+
const implementTool = implementToolFactory(options);
|
|
128
|
+
const factory = (procedure, ...rest) => {
|
|
129
|
+
const toolOptions = resolveMaybeOptionalOptions(rest);
|
|
130
|
+
|
|
131
|
+
const disabledValidation = new Procedure({
|
|
132
|
+
...procedure["~orpc"],
|
|
133
|
+
disableInputValidation: true
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const isIteratorOutput = getAsyncIteratorObjectSchemasDetails(procedure["~orpc"].outputSchemas) !== undefined || isAsyncGeneratorFunction(procedure["~orpc"].handler);
|
|
137
|
+
return implementTool(procedure, {
|
|
138
|
+
...toolOptions,
|
|
139
|
+
|
|
140
|
+
execute: isIteratorOutput ? async function* (input, callingOptions) {
|
|
141
|
+
yield* await call(disabledValidation, input, {
|
|
142
|
+
...options,
|
|
143
|
+
signal: callingOptions.abortSignal
|
|
144
|
+
});
|
|
145
|
+
} : (input, callingOptions) => {
|
|
146
|
+
return call(disabledValidation, input, {
|
|
147
|
+
...options,
|
|
148
|
+
signal: callingOptions.abortSignal
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
};
|
|
153
|
+
return factory;
|
|
154
|
+
}
|
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.
|
|
4
|
+
"version": "2.0.0-beta.48",
|
|
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,15 +40,15 @@
|
|
|
40
40
|
"ai": ">=7.0.31"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@orpc/client": "2.0.0-beta.
|
|
44
|
-
"@orpc/contract": "2.0.0-beta.
|
|
45
|
-
"@orpc/json-schema": "2.0.0-beta.
|
|
46
|
-
"@orpc/openapi": "2.0.0-beta.
|
|
47
|
-
"@orpc/server": "2.0.0-beta.
|
|
48
|
-
"@orpc/shared": "2.0.0-beta.
|
|
43
|
+
"@orpc/client": "2.0.0-beta.48",
|
|
44
|
+
"@orpc/contract": "2.0.0-beta.48",
|
|
45
|
+
"@orpc/json-schema": "2.0.0-beta.48",
|
|
46
|
+
"@orpc/openapi": "2.0.0-beta.48",
|
|
47
|
+
"@orpc/server": "2.0.0-beta.48",
|
|
48
|
+
"@orpc/shared": "2.0.0-beta.48"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"ai": "^7.0.
|
|
51
|
+
"ai": "^7.0.157",
|
|
52
52
|
"zod": "^4.6.7"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
package/dist/index.d.ts
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
import { ClientOptions } from '@orpc/client';
|
|
2
|
-
import { AnySchema, ErrorMap, InferSchemaOutput, InferSchemaInput, MetaPlugin, AnyProcedureContract, Schema, ProcedureContract } from '@orpc/contract';
|
|
3
|
-
import { Lazy, Context, ProcedureClientOptions, Procedure } from '@orpc/server';
|
|
4
|
-
import { Public, MaybeOptionalOptions } from '@orpc/shared';
|
|
5
|
-
import { JSONValue, Tool } from 'ai';
|
|
6
|
-
import { OpenAPIJsonSerializer } from '@orpc/openapi';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* The [function tool](https://ai-sdk.dev/docs/foundations/tools) member of the AI SDK `Tool` union,
|
|
10
|
-
* which is the kind of tool this package produces.
|
|
11
|
-
*/
|
|
12
|
-
type FunctionTool<INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any> = Extract<Tool<INPUT, OUTPUT>, {
|
|
13
|
-
type?: 'function' | undefined;
|
|
14
|
-
}>;
|
|
15
|
-
/**
|
|
16
|
-
* Base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options attached to a procedure/contract,
|
|
17
|
-
* used as defaults when creating tools from it.
|
|
18
|
-
*
|
|
19
|
-
* @remarks
|
|
20
|
-
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
21
|
-
*
|
|
22
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
23
|
-
*/
|
|
24
|
-
type AiSdkToolMeta<TInputSchema extends AnySchema = AnySchema, TOutputSchema extends AnySchema = AnySchema> = Partial<Omit<FunctionTool<InferSchemaOutput<TInputSchema>, ToolOutput<InferSchemaInput<TOutputSchema>>>, 'inputSchema' | 'outputSchema' | 'execute'>>;
|
|
25
|
-
interface AiSdkToolMetaPlugin<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> extends MetaPlugin<TInputSchema, TOutputSchema, TErrorMap> {
|
|
26
|
-
name: '~ai-sdk/tool';
|
|
27
|
-
}
|
|
28
|
-
interface AiSdkToolFunction {
|
|
29
|
-
<TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap>(meta: AiSdkToolMeta<TInputSchema, TOutputSchema>): AiSdkToolMetaPlugin<TInputSchema, TOutputSchema, TErrorMap>;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Attaches base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options to a procedure/contract,
|
|
33
|
-
* used as defaults when creating tools from it.
|
|
34
|
-
*
|
|
35
|
-
* @remarks
|
|
36
|
-
* **Note**: When defined multiple times, options are overridden by the most recent call.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```ts
|
|
40
|
-
* const getWeatherContract = oc
|
|
41
|
-
* .meta(aiSdkTool({
|
|
42
|
-
* description: 'Get the weather in a location',
|
|
43
|
-
* metadata: { source: 'weather-service' },
|
|
44
|
-
* }))
|
|
45
|
-
* .input(z.object({ location: z.string() }))
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
49
|
-
*/
|
|
50
|
-
declare const aiSdkTool: AiSdkToolFunction;
|
|
51
|
-
/**
|
|
52
|
-
* Reads the base [AI SDK Tool](https://ai-sdk.dev/docs/foundations/tools) options
|
|
53
|
-
* attached to a procedure/contract by {@link aiSdkTool}.
|
|
54
|
-
*
|
|
55
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
56
|
-
*/
|
|
57
|
-
declare function getAiSdkToolMeta(procedureOrLazy: AnyProcedureContract | Lazy<any>): AiSdkToolMeta | undefined;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Infers the value an AI SDK tool outputs for a given oRPC output type.
|
|
61
|
-
*
|
|
62
|
-
* For [AsyncIteratorObject](https://orpc.dev/docs/async-iterator-object) outputs, the tool streams
|
|
63
|
-
* each yielded event as a [preliminary result](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#preliminary-tool-results)
|
|
64
|
-
* and the last event becomes the final result, so the tool output is the yield type.
|
|
65
|
-
*
|
|
66
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#streaming-tool-outputs | AI SDK Integration - Streaming Tool Outputs}
|
|
67
|
-
*/
|
|
68
|
-
type ToolOutput<T> = T extends AsyncIteratorObject<infer TYield, any, any> ? TYield : T;
|
|
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;
|
|
78
|
-
}
|
|
79
|
-
interface ToolImplementer {
|
|
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>>>;
|
|
81
|
-
}
|
|
82
|
-
/**
|
|
83
|
-
* Creates a builder that implements [procedure contracts](https://orpc.dev/docs/contract/procedure)
|
|
84
|
-
* as [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing contract definitions.
|
|
85
|
-
*
|
|
86
|
-
* The factory accepts oRPC related options, and the resulting builder
|
|
87
|
-
* accepts a contract alongside AI SDK tool options.
|
|
88
|
-
*
|
|
89
|
-
* @remarks
|
|
90
|
-
* **Note**: [Procedures](https://orpc.dev/docs/procedure) are also compatible with [procedure contracts](https://orpc.dev/docs/contract/procedure).
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* ```ts
|
|
94
|
-
* import { aiSdkTool, implementToolFactory } from '@orpc/ai-sdk'
|
|
95
|
-
* import { oc } from '@orpc/contract'
|
|
96
|
-
*
|
|
97
|
-
* const getWeatherContract = oc
|
|
98
|
-
* .meta(
|
|
99
|
-
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
100
|
-
* )
|
|
101
|
-
* .input(
|
|
102
|
-
* z.object({
|
|
103
|
-
* location: z.string().describe('The location to get the weather for'),
|
|
104
|
-
* }),
|
|
105
|
-
* )
|
|
106
|
-
* .output(
|
|
107
|
-
* z.object({
|
|
108
|
-
* location: z.string().describe('The location the weather is for'),
|
|
109
|
-
* temperature: z.number().describe('The temperature in Celsius'),
|
|
110
|
-
* }),
|
|
111
|
-
* )
|
|
112
|
-
*
|
|
113
|
-
* const implementTool = implementToolFactory()
|
|
114
|
-
*
|
|
115
|
-
* const getWeatherTool = implementTool(getWeatherContract, {
|
|
116
|
-
* execute: async ({ location }) => ({
|
|
117
|
-
* location,
|
|
118
|
-
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
119
|
-
* }),
|
|
120
|
-
* })
|
|
121
|
-
* ```
|
|
122
|
-
*
|
|
123
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-implementer | AI SDK Integration - Tool Implementer}
|
|
124
|
-
*/
|
|
125
|
-
declare function implementToolFactory(options?: ImplementToolFactoryOptions): ToolImplementer;
|
|
126
|
-
type CreateToolFactoryOptions<TInitialContext extends Context> = ImplementToolFactoryOptions & ProcedureClientOptions<TInitialContext, Schema<unknown>, object, object> & Omit<ClientOptions<object>, 'context' | 'signal'>;
|
|
127
|
-
interface ToolFactory<TInitialContext extends Context> {
|
|
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>>>;
|
|
129
|
-
}
|
|
130
|
-
/**
|
|
131
|
-
* Creates a builder that converts [procedures](https://orpc.dev/docs/procedure)
|
|
132
|
-
* into [AI SDK Tools](https://ai-sdk.dev/docs/foundations/tools) by leveraging existing procedure definitions.
|
|
133
|
-
*
|
|
134
|
-
* The factory accepts oRPC related options, and the resulting builder
|
|
135
|
-
* accepts a procedure alongside AI SDK tool options.
|
|
136
|
-
*
|
|
137
|
-
* @example
|
|
138
|
-
* ```ts
|
|
139
|
-
* import { aiSdkTool, createToolFactory } from '@orpc/ai-sdk'
|
|
140
|
-
* import { os } from '@orpc/server'
|
|
141
|
-
*
|
|
142
|
-
* const getWeatherProcedure = os
|
|
143
|
-
* .meta(
|
|
144
|
-
* aiSdkTool({ description: 'Get the weather in a location' }), // default AI SDK tool options
|
|
145
|
-
* )
|
|
146
|
-
* .input(z.object({
|
|
147
|
-
* location: z.string().describe('The location to get the weather for'),
|
|
148
|
-
* }))
|
|
149
|
-
* .output(z.object({
|
|
150
|
-
* location: z.string().describe('The location the weather is for'),
|
|
151
|
-
* temperature: z.number().describe('The temperature in Celsius'),
|
|
152
|
-
* }))
|
|
153
|
-
* .handler(async ({ input }) => ({
|
|
154
|
-
* location: input.location,
|
|
155
|
-
* temperature: 72 + Math.floor(Math.random() * 21) - 10,
|
|
156
|
-
* }))
|
|
157
|
-
*
|
|
158
|
-
* const createTool = createToolFactory({
|
|
159
|
-
* context: {}, // provide initial context if needed
|
|
160
|
-
* })
|
|
161
|
-
*
|
|
162
|
-
* const getWeatherTool = createTool(getWeatherProcedure, {
|
|
163
|
-
* // ...AI SDK tool options/overrides here if needed
|
|
164
|
-
* })
|
|
165
|
-
* ```
|
|
166
|
-
*
|
|
167
|
-
* @see {@link https://orpc.dev/docs/integrations/ai-sdk#tool-factory | AI SDK Integration - Tool Factory}
|
|
168
|
-
*/
|
|
169
|
-
declare function createToolFactory<TInitialContext extends Context = object>(...rest: MaybeOptionalOptions<CreateToolFactoryOptions<TInitialContext>>): ToolFactory<TInitialContext>;
|
|
170
|
-
|
|
171
|
-
export { aiSdkTool, createToolFactory, getAiSdkToolMeta, implementToolFactory };
|
|
172
|
-
export type { AiSdkToolFunction, AiSdkToolMeta, AiSdkToolMetaPlugin, CreateToolFactoryOptions, FunctionTool, ImplementToolFactoryOptions, ToolFactory, ToolImplementer, ToolOutput };
|