Skip to content

Commit d68c288

Browse files
committed
feat(anthropic): add support for Genkit v2 streaming API
- Update streaming callback interface to use v2 API format with streamingRequested, sendChunk, and abortSignal - Add apiVersion: 'v2' to model definition for compatibility - Pass AbortSignal to Anthropic SDK client calls for proper request cancellation - Update tests to reflect the new API changes - Fix code indentation for better consistency BREAKING CHANGE: This updates the plugin to work with Genkit v2 API which changes the streaming callback interface
1 parent 4db4bd2 commit d68c288

8 files changed

Lines changed: 1959 additions & 105 deletions

File tree

package-lock.json

Lines changed: 1874 additions & 79 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/anthropic/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
"author": "TheFireCo",
2727
"license": "Apache-2.0",
2828
"peerDependencies": {
29-
"genkit": "^0.9.0 || ^1.0.0"
29+
"genkit": "^1.15.0"
3030
},
3131
"dependencies": {
3232
"@anthropic-ai/sdk": "^0.39.0"

plugins/anthropic/src/claude.test.ts

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -915,11 +915,20 @@ describe('claudeRunner', () => {
915915
'claude-3-5-haiku',
916916
anthropicClient as unknown as Anthropic
917917
);
918-
await runner({ messages: [] });
919-
expect(anthropicClient.messages.create).toHaveBeenCalledWith({
920-
model: 'claude-3-5-haiku-latest',
921-
max_tokens: 4096,
922-
});
918+
const abortSignal = new AbortController().signal;
919+
await runner(
920+
{ messages: [] },
921+
{ streamingRequested: false, sendChunk: () => {}, abortSignal }
922+
);
923+
expect(anthropicClient.messages.create).toHaveBeenCalledWith(
924+
{
925+
model: 'claude-3-5-haiku-latest',
926+
max_tokens: 4096,
927+
},
928+
{
929+
signal: abortSignal,
930+
}
931+
);
923932
});
924933

925934
it('should correctly run streaming requests', async () => {
@@ -968,12 +977,21 @@ describe('claudeRunner', () => {
968977
'claude-3-5-haiku',
969978
anthropicClient as unknown as Anthropic
970979
);
971-
await runner({ messages: [] }, streamingCallback);
972-
expect(anthropicClient.messages.stream).toHaveBeenCalledWith({
973-
model: 'claude-3-5-haiku-latest',
974-
max_tokens: 4096,
975-
stream: true,
976-
});
980+
const abortSignal = new AbortController().signal;
981+
await runner(
982+
{ messages: [] },
983+
{ streamingRequested: true, sendChunk: streamingCallback, abortSignal }
984+
);
985+
expect(anthropicClient.messages.stream).toHaveBeenCalledWith(
986+
{
987+
model: 'claude-3-5-haiku-latest',
988+
max_tokens: 4096,
989+
stream: true,
990+
},
991+
{
992+
signal: abortSignal,
993+
}
994+
);
977995
});
978996
});
979997

@@ -995,6 +1013,7 @@ describe('claudeModel', () => {
9951013
claudeModel(ai, 'claude-3-5-haiku', {} as Anthropic);
9961014
expect(ai.defineModel).toHaveBeenCalledWith(
9971015
{
1016+
apiVersion: 'v2',
9981017
name: claude35Haiku.name,
9991018
...claude35Haiku.info,
10001019
configSchema: claude35Haiku.configSchema,

plugins/anthropic/src/claude.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -569,29 +569,40 @@ export function claudeRunner(
569569
) {
570570
return async (
571571
request: GenerateRequest<typeof AnthropicConfigSchema>,
572-
streamingCallback?: StreamingCallback<GenerateResponseChunkData>
572+
{
573+
streamingRequested,
574+
sendChunk,
575+
abortSignal,
576+
}: {
577+
streamingRequested: boolean;
578+
sendChunk: StreamingCallback<GenerateResponseChunkData>;
579+
abortSignal: AbortSignal;
580+
}
573581
): Promise<GenerateResponseData> => {
574582
let response: Message;
575583
const body = toAnthropicRequestBody(
576584
name,
577585
request,
578-
!!streamingCallback,
586+
streamingRequested,
579587
cacheSystemPrompt
580588
);
581-
if (streamingCallback) {
582-
const stream = client.messages.stream(body);
589+
590+
if (streamingRequested) {
591+
const stream = client.messages.stream(body, { signal: abortSignal });
583592
for await (const chunk of stream) {
584593
const c = fromAnthropicContentBlockChunk(chunk);
585594
if (c) {
586-
streamingCallback({
595+
sendChunk({
587596
index: 0,
588597
content: [c],
589598
});
590599
}
591600
}
592601
response = await stream.finalMessage();
593602
} else {
594-
response = (await client.messages.create(body)) as Message;
603+
response = (await client.messages.create(body, {
604+
signal: abortSignal,
605+
})) as Message;
595606
}
596607
return fromAnthropicResponse(response);
597608
};
@@ -612,6 +623,7 @@ export function claudeModel(
612623

613624
return ai.defineModel(
614625
{
626+
apiVersion: 'v2',
615627
name: modelId,
616628
...model.info,
617629
configSchema: model.configSchema,

plugins/azure-openai/src/gpt.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,15 @@ import type {
2121
MessageData,
2222
Part,
2323
Role,
24+
StreamingCallback,
2425
ToolRequestPart,
2526
} from 'genkit';
26-
import { CandidateData, modelRef, ToolDefinition } from 'genkit/model';
27+
import {
28+
CandidateData,
29+
GenerateResponseChunkData,
30+
modelRef,
31+
ToolDefinition,
32+
} from 'genkit/model';
2733
import { AzureOpenAI } from 'openai';
2834
import {
2935
type ChatCompletion,
@@ -633,7 +639,10 @@ export function gptModel(ai: Genkit, name: string, client: AzureOpenAI) {
633639
...model.info,
634640
configSchema: SUPPORTED_GPT_MODELS[name].configSchema,
635641
},
636-
async (request, streamingCallback) => {
642+
async (
643+
request,
644+
streamingCallback?: StreamingCallback<GenerateResponseChunkData>
645+
) => {
637646
let response: ChatCompletion;
638647
const body = toOpenAiRequestBody(name, request);
639648
if (streamingCallback) {

plugins/cohere/src/command.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,15 @@ import type {
2020
GenerateRequest,
2121
MessageData,
2222
Role,
23+
StreamingCallback,
2324
ToolRequestPart,
2425
} from 'genkit';
25-
import type { ModelAction, ToolDefinition, CandidateData } from 'genkit/model';
26+
import type {
27+
ModelAction,
28+
ToolDefinition,
29+
CandidateData,
30+
GenerateResponseChunkData,
31+
} from 'genkit/model';
2632
import { modelRef } from 'genkit/model';
2733
import type { CohereClient } from 'cohere-ai';
2834
import { Cohere } from 'cohere-ai';
@@ -466,7 +472,7 @@ export function commandModel(
466472
},
467473
async (
468474
request,
469-
streamingCallback
475+
streamingCallback?: StreamingCallback<GenerateResponseChunkData>
470476
): Promise<{
471477
candidates: CandidateData[];
472478
usage: {

plugins/groq/src/groq_models.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,16 @@ import {
3030
MessageData,
3131
Part,
3232
Role,
33+
StreamingCallback,
3334
ToolRequestPart,
3435
z,
3536
} from 'genkit';
36-
import { CandidateData, modelRef, ToolDefinition } from 'genkit/model';
37+
import {
38+
CandidateData,
39+
GenerateResponseChunkData,
40+
modelRef,
41+
ToolDefinition,
42+
} from 'genkit/model';
3743

3844
export const GroqConfigSchema = GenerationCommonConfigSchema.extend({
3945
stream: z.boolean().optional(),
@@ -583,7 +589,10 @@ export function groqModel(ai: Genkit, name: string, client: Groq) {
583589
...model.info,
584590
configSchema: model.configSchema,
585591
},
586-
async (request, streamingCallback) => {
592+
async (
593+
request,
594+
streamingCallback?: StreamingCallback<GenerateResponseChunkData>
595+
) => {
587596
let response: ChatCompletion;
588597
const body = toGroqRequestBody(name, request);
589598
if (streamingCallback) {

plugins/mistral/src/mistral_llms.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { Message, Part } from 'genkit';
17+
import { Message, Part, StreamingCallback } from 'genkit';
1818
import {
1919
CandidateData,
2020
GenerateRequest,
21+
GenerateResponseChunkData,
2122
MessageData,
2223
ModelAction,
2324
Role,
@@ -499,7 +500,10 @@ export function mistralModel(
499500
...model.info,
500501
configSchema: SUPPORTED_MISTRAL_MODELS[name].configSchema,
501502
},
502-
async (request, streamingCallback) => {
503+
async (
504+
request,
505+
streamingCallback?: StreamingCallback<GenerateResponseChunkData>
506+
) => {
503507
let response: ChatCompletionResponse | CompletionChunk;
504508
const body = toMistralRequestBody(name, request);
505509
if (streamingCallback) {

0 commit comments

Comments
 (0)