Skip to content

Commit 76ef059

Browse files
authored
Anthropic tools (#153)
1 parent 5d7489f commit 76ef059

File tree

8 files changed

+112
-80
lines changed

8 files changed

+112
-80
lines changed

.changeset/tasty-seas-shave.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@instructor-ai/instructor": minor
3+
---
4+
5+
updated client types to be more flexible - added tests for latest anthropic updates and llm-polyglot major

README.md

+8-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ The main class for creating an Instructor client.
8282

8383
**createInstructor**
8484
```typescript
85-
function createInstructor<C extends SupportedInstructorClient = OpenAI>(args: {
85+
function createInstructor<C extends GenericClient | OpenAI>(args: {
8686
client: OpenAILikeClient<C>;
8787
mode: Mode;
8888
debug?: boolean;
@@ -100,7 +100,13 @@ Returns the extended OpenAI-Like client.
100100

101101
**chat.completions.create**
102102
```typescript
103-
chat.completions.create<T extends z.AnyZodObject>(params: ChatCompletionCreateParamsWithModel<T>): Promise<z.infer<T> & { _meta?: CompletionMeta }>
103+
chat.completions.create<
104+
T extends z.AnyZodObject,
105+
P extends T extends z.AnyZodObject ? ChatCompletionCreateParamsWithModel<T>
106+
: ClientTypeChatCompletionParams<OpenAILikeClient<C>> & { response_model: never }
107+
>(
108+
params: P
109+
): Promise<ReturnTypeBasedOnParams<typeof this.client, P>>
104110
```
105111
When response_model is present in the params, creates a chat completion with structured extraction based on the provided schema - otherwise will proxy back to the provided client.
106112

bun.lockb

-46 Bytes
Binary file not shown.

package.json

+4-3
Original file line numberDiff line numberDiff line change
@@ -59,13 +59,14 @@
5959
"zod": ">=3.22.4"
6060
},
6161
"devDependencies": {
62+
"@anthropic-ai/sdk": "latest",
6263
"@changesets/changelog-github": "^0.5.0",
6364
"@changesets/cli": "^2.27.1",
6465
"@ianvs/prettier-plugin-sort-imports": "4.1.0",
6566
"@types/bun": "^1.0.0",
6667
"@types/node": "^20.10.6",
67-
"@typescript-eslint/eslint-plugin": "^6.11.0",
68-
"@typescript-eslint/parser": "^6.11.0",
68+
"@typescript-eslint/parser": "^7.5.0",
69+
"@typescript-eslint/eslint-plugin": "^7.5.0",
6970
"eslint-config": "^0.3.0",
7071
"eslint-config-prettier": "^9.0.0",
7172
"eslint-config-turbo": "^1.10.12",
@@ -74,7 +75,7 @@
7475
"eslint-plugin-only-warn": "^1.1.0",
7576
"eslint-plugin-prettier": "^5.1.2",
7677
"husky": "^8.0.3",
77-
"llm-polyglot": "^0.0.3",
78+
"llm-polyglot": "1.0.0",
7879
"prettier": "latest",
7980
"ts-inference-check": "^0.3.0",
8081
"tsup": "^8.0.1",

src/dsl/validator.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import { InstructorClient } from "@/instructor"
22
import OpenAI from "openai"
33
import { RefinementCtx, z } from "zod"
44

5+
import { GenericClient } from ".."
6+
57
type AsyncSuperRefineFunction = (data: string, ctx: RefinementCtx) => Promise<void>
68

7-
export const LLMValidator = (
8-
instructor: InstructorClient,
9+
export const LLMValidator = <C extends GenericClient | OpenAI>(
10+
instructor: InstructorClient<C>,
911
statement: string,
1012
params: Omit<OpenAI.ChatCompletionCreateParams, "messages">
1113
): AsyncSuperRefineFunction => {
@@ -42,7 +44,9 @@ export const LLMValidator = (
4244
}
4345
}
4446

45-
export const moderationValidator = (client: InstructorClient) => {
47+
export const moderationValidator = <C extends GenericClient | OpenAI>(
48+
client: InstructorClient<C>
49+
) => {
4650
return async (value: string, ctx: z.RefinementCtx) => {
4751
try {
4852
if (!(client instanceof OpenAI)) {

src/instructor.ts

+48-30
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import {
22
ChatCompletionCreateParamsWithModel,
33
GenericChatCompletion,
4+
GenericClient,
45
InstructorConfig,
56
LogLevel,
67
OpenAILikeClient,
7-
ReturnTypeBasedOnParams,
8-
SupportedInstructorClient
8+
ReturnTypeBasedOnParams
99
} from "@/types"
1010
import OpenAI from "openai"
1111
import { z } from "zod"
@@ -24,7 +24,7 @@ import { ClientTypeChatCompletionParams, CompletionMeta } from "./types"
2424

2525
const MAX_RETRIES_DEFAULT = 0
2626

27-
class Instructor<C extends SupportedInstructorClient> {
27+
class Instructor<C extends GenericClient | OpenAI> {
2828
readonly client: OpenAILikeClient<C>
2929
readonly mode: Mode
3030
readonly provider: Provider
@@ -41,10 +41,12 @@ class Instructor<C extends SupportedInstructorClient> {
4141
this.debug = debug
4242

4343
const provider =
44-
this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.ANYSCALE) ? PROVIDERS.ANYSCALE
45-
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.TOGETHER) ? PROVIDERS.TOGETHER
46-
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.OAI) ? PROVIDERS.OAI
47-
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.ANTHROPIC) ? PROVIDERS.ANTHROPIC
44+
typeof this.client?.baseURL === "string" ?
45+
this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.ANYSCALE) ? PROVIDERS.ANYSCALE
46+
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.TOGETHER) ? PROVIDERS.TOGETHER
47+
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.OAI) ? PROVIDERS.OAI
48+
: this.client?.baseURL.includes(NON_OAI_PROVIDER_URLS.ANTHROPIC) ? PROVIDERS.ANTHROPIC
49+
: PROVIDERS.OTHER
4850
: PROVIDERS.OTHER
4951

5052
this.provider = provider
@@ -114,8 +116,8 @@ class Instructor<C extends SupportedInstructorClient> {
114116
let completionParams = withResponseModel({
115117
params: {
116118
...params,
117-
stream: false
118-
},
119+
stream: params.stream ?? false
120+
} as OpenAI.ChatCompletionCreateParams,
119121
mode: this.mode,
120122
response_model
121123
})
@@ -141,12 +143,18 @@ class Instructor<C extends SupportedInstructorClient> {
141143
}
142144
}
143145

144-
let completion: GenericChatCompletion | null = null
146+
let completion
145147

146148
try {
147-
completion = (await this.client.chat.completions.create(
148-
resolvedParams
149-
)) as GenericChatCompletion
149+
if (this.client.chat?.completions?.create) {
150+
const result = await this.client.chat.completions.create({
151+
...resolvedParams,
152+
stream: false
153+
})
154+
completion = result as GenericChatCompletion<typeof result>
155+
} else {
156+
throw new Error("Unsupported client type")
157+
}
150158
this.log("debug", "raw standard completion response: ", completion)
151159
} catch (error) {
152160
this.log(
@@ -245,7 +253,7 @@ class Instructor<C extends SupportedInstructorClient> {
245253
params: {
246254
...params,
247255
stream: true
248-
},
256+
} as OpenAI.ChatCompletionCreateParams,
249257
response_model,
250258
mode: this.mode
251259
})
@@ -260,13 +268,19 @@ class Instructor<C extends SupportedInstructorClient> {
260268

261269
return streamClient.create({
262270
completionPromise: async () => {
263-
const completion = await this.client.chat.completions.create(completionParams)
264-
this.log("debug", "raw stream completion response: ", completion)
265-
266-
return OAIStream({
267-
//TODO: we need to move away from strict openai types - need to cast here but should update to be more flexible
268-
res: completion as AsyncIterable<OpenAI.ChatCompletionChunk>
269-
})
271+
if (this.client.chat?.completions?.create) {
272+
const completion = await this.client.chat.completions.create({
273+
...completionParams,
274+
stream: true
275+
})
276+
this.log("debug", "raw stream completion response: ", completion)
277+
278+
return OAIStream({
279+
res: completion as unknown as AsyncIterable<OpenAI.ChatCompletionChunk>
280+
})
281+
} else {
282+
throw new Error("Unsupported client type")
283+
}
270284
},
271285
response_model
272286
})
@@ -289,7 +303,7 @@ class Instructor<C extends SupportedInstructorClient> {
289303
create: async <
290304
T extends z.AnyZodObject,
291305
P extends T extends z.AnyZodObject ? ChatCompletionCreateParamsWithModel<T>
292-
: ClientTypeChatCompletionParams<typeof this.client> & { response_model: never }
306+
: ClientTypeChatCompletionParams<OpenAILikeClient<C>> & { response_model: never }
293307
>(
294308
params: P
295309
): Promise<ReturnTypeBasedOnParams<typeof this.client, P>> => {
@@ -308,20 +322,23 @@ class Instructor<C extends SupportedInstructorClient> {
308322
>
309323
}
310324
} else {
311-
const result =
312-
this.isStandardStream(params) ?
313-
await this.client.chat.completions.create(params)
314-
: await this.client.chat.completions.create(params)
325+
if (this.client.chat?.completions?.create) {
326+
const result =
327+
this.isStandardStream(params) ?
328+
await this.client.chat.completions.create(params)
329+
: await this.client.chat.completions.create(params)
315330

316-
return result as ReturnTypeBasedOnParams<typeof this.client, P>
331+
return result as unknown as ReturnTypeBasedOnParams<OpenAILikeClient<C>, P>
332+
} else {
333+
throw new Error("Completion method is undefined")
334+
}
317335
}
318336
}
319337
}
320338
}
321339
}
322340

323-
export type InstructorClient<C extends SupportedInstructorClient = OpenAI> = Instructor<C> &
324-
OpenAILikeClient<C>
341+
export type InstructorClient<C extends GenericClient | OpenAI> = Instructor<C> & OpenAILikeClient<C>
325342

326343
/**
327344
* Creates an instance of the `Instructor` class.
@@ -344,7 +361,7 @@ export type InstructorClient<C extends SupportedInstructorClient = OpenAI> = Ins
344361
* @param args
345362
* @returns
346363
*/
347-
export default function <C extends SupportedInstructorClient = OpenAI>(args: {
364+
export default function createInstructor<C extends GenericClient | OpenAI>(args: {
348365
client: OpenAILikeClient<C>
349366
mode: Mode
350367
debug?: boolean
@@ -355,6 +372,7 @@ export default function <C extends SupportedInstructorClient = OpenAI>(args: {
355372
if (prop in target) {
356373
return Reflect.get(target, prop, receiver)
357374
}
375+
358376
return Reflect.get(target.client, prop, receiver)
359377
}
360378
})

src/types/index.ts

+30-28
Original file line numberDiff line numberDiff line change
@@ -7,59 +7,62 @@ import {
77
type ResponseModel as ZResponseModel
88
} from "zod-stream"
99

10-
export type GenericCreateParams = Omit<Partial<OpenAI.ChatCompletionCreateParams>, "model"> & {
10+
export type GenericCreateParams<M = unknown> = Omit<
11+
Partial<OpenAI.ChatCompletionCreateParams>,
12+
"model" | "messages"
13+
> & {
1114
model: string
12-
messages: OpenAI.ChatCompletionCreateParams["messages"]
15+
messages: M[]
1316
stream?: boolean
1417
max_tokens?: number | null
18+
[key: string]: unknown
1519
}
1620

17-
export type GenericChatCompletion = Partial<OpenAI.Chat.Completions.ChatCompletion> & {
21+
export type GenericChatCompletion<T = unknown> = Partial<OpenAI.Chat.Completions.ChatCompletion> & {
1822
[key: string]: unknown
23+
choices?: T
1924
}
2025

21-
export type GenericChatCompletionStream = AsyncIterable<
22-
Partial<OpenAI.Chat.Completions.ChatCompletionChunk> & { [key: string]: unknown }
26+
export type GenericChatCompletionStream<T = unknown> = AsyncIterable<
27+
Partial<OpenAI.Chat.Completions.ChatCompletionChunk> & {
28+
[key: string]: unknown
29+
choices?: T
30+
}
2331
>
2432

25-
export type GenericClient<
26-
P extends GenericCreateParams = GenericCreateParams,
27-
Completion = GenericChatCompletion,
28-
Chunk = GenericChatCompletionStream
29-
> = {
30-
baseURL: string
31-
chat: {
32-
completions: {
33-
create: (params: P) => CreateMethodReturnType<P, Completion, Chunk>
33+
export type GenericClient = {
34+
[key: string]: unknown
35+
baseURL?: string
36+
chat?: {
37+
completions?: {
38+
create?: (params: GenericCreateParams) => Promise<unknown>
3439
}
3540
}
3641
}
3742

38-
export type CreateMethodReturnType<
39-
P extends GenericCreateParams,
40-
Completion = GenericChatCompletion,
41-
Chunk = GenericChatCompletionStream
42-
> = P extends { stream: true } ? Promise<Chunk> : Promise<Completion>
43-
44-
export type ClientTypeChatCompletionParams<C extends SupportedInstructorClient> =
43+
export type ClientTypeChatCompletionParams<C> =
4544
C extends OpenAI ? OpenAI.ChatCompletionCreateParams : GenericCreateParams
4645

47-
export type ClientType<C extends SupportedInstructorClient> =
48-
C extends OpenAI ? "openai" : "generic"
46+
export type ClientType<C> =
47+
C extends OpenAI ? "openai"
48+
: C extends GenericClient ? "generic"
49+
: never
4950

50-
export type OpenAILikeClient<C extends SupportedInstructorClient> =
51-
ClientType<C> extends "openai" ? OpenAI : C
51+
export type OpenAILikeClient<C> = C extends OpenAI ? OpenAI : C & GenericClient
5252

5353
export type SupportedInstructorClient = GenericClient | OpenAI
5454

5555
export type LogLevel = "debug" | "info" | "warn" | "error"
56+
5657
export type CompletionMeta = Partial<ZCompletionMeta> & {
5758
usage?: OpenAI.CompletionUsage
5859
}
60+
5961
export type Mode = ZMode
62+
6063
export type ResponseModel<T extends z.AnyZodObject> = ZResponseModel<T>
6164

62-
export interface InstructorConfig<C extends SupportedInstructorClient> {
65+
export interface InstructorConfig<C> {
6366
client: OpenAILikeClient<C>
6467
mode: Mode
6568
debug?: boolean
@@ -87,5 +90,4 @@ export type ReturnTypeBasedOnParams<C, P> =
8790
P extends { stream: true } ?
8891
Stream<OpenAI.Chat.Completions.ChatCompletionChunk>
8992
: OpenAI.Chat.Completions.ChatCompletion
90-
: P extends { stream: true } ? Promise<GenericChatCompletionStream>
91-
: Promise<GenericChatCompletion>
93+
: Promise<unknown>

0 commit comments

Comments
 (0)