@celljs/ai-anthropic 3.4.0

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.
Files changed (113) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +82 -0
  3. package/lib/common/api/anthropic-api.d.ts +16 -0
  4. package/lib/common/api/anthropic-api.d.ts.map +1 -0
  5. package/lib/common/api/anthropic-api.js +76 -0
  6. package/lib/common/api/anthropic-api.js.map +1 -0
  7. package/lib/common/api/anthropic-api.spec.d.ts +2 -0
  8. package/lib/common/api/anthropic-api.spec.d.ts.map +1 -0
  9. package/lib/common/api/anthropic-api.spec.js +146 -0
  10. package/lib/common/api/anthropic-api.spec.js.map +1 -0
  11. package/lib/common/api/anthropic-model.d.ts +34 -0
  12. package/lib/common/api/anthropic-model.d.ts.map +1 -0
  13. package/lib/common/api/anthropic-model.js +39 -0
  14. package/lib/common/api/anthropic-model.js.map +1 -0
  15. package/lib/common/api/api-protocol.d.ts +40 -0
  16. package/lib/common/api/api-protocol.d.ts.map +1 -0
  17. package/lib/common/api/api-protocol.js +6 -0
  18. package/lib/common/api/api-protocol.js.map +1 -0
  19. package/lib/common/api/chat-request.d.ts +144 -0
  20. package/lib/common/api/chat-request.d.ts.map +1 -0
  21. package/lib/common/api/chat-request.js +151 -0
  22. package/lib/common/api/chat-request.js.map +1 -0
  23. package/lib/common/api/chat-response.d.ts +72 -0
  24. package/lib/common/api/chat-response.d.ts.map +1 -0
  25. package/lib/common/api/chat-response.js +96 -0
  26. package/lib/common/api/chat-response.js.map +1 -0
  27. package/lib/common/api/content-block.d.ts +100 -0
  28. package/lib/common/api/content-block.d.ts.map +1 -0
  29. package/lib/common/api/content-block.js +84 -0
  30. package/lib/common/api/content-block.js.map +1 -0
  31. package/lib/common/api/event.d.ts +188 -0
  32. package/lib/common/api/event.d.ts.map +1 -0
  33. package/lib/common/api/event.js +249 -0
  34. package/lib/common/api/event.js.map +1 -0
  35. package/lib/common/api/index.d.ts +10 -0
  36. package/lib/common/api/index.d.ts.map +1 -0
  37. package/lib/common/api/index.js +13 -0
  38. package/lib/common/api/index.js.map +1 -0
  39. package/lib/common/api/message.d.ts +41 -0
  40. package/lib/common/api/message.d.ts.map +1 -0
  41. package/lib/common/api/message.js +45 -0
  42. package/lib/common/api/message.js.map +1 -0
  43. package/lib/common/api/usage.d.ts +15 -0
  44. package/lib/common/api/usage.d.ts.map +1 -0
  45. package/lib/common/api/usage.js +24 -0
  46. package/lib/common/api/usage.js.map +1 -0
  47. package/lib/common/index.d.ts +3 -0
  48. package/lib/common/index.d.ts.map +1 -0
  49. package/lib/common/index.js +6 -0
  50. package/lib/common/index.js.map +1 -0
  51. package/lib/common/model/anthropic-chat-model.d.ts +20 -0
  52. package/lib/common/model/anthropic-chat-model.d.ts.map +1 -0
  53. package/lib/common/model/anthropic-chat-model.js +161 -0
  54. package/lib/common/model/anthropic-chat-model.js.map +1 -0
  55. package/lib/common/model/anthropic-chat-model.spec.d.ts +2 -0
  56. package/lib/common/model/anthropic-chat-model.spec.d.ts.map +1 -0
  57. package/lib/common/model/anthropic-chat-model.spec.js +64 -0
  58. package/lib/common/model/anthropic-chat-model.spec.js.map +1 -0
  59. package/lib/common/model/anthropic-chat-options.d.ts +55 -0
  60. package/lib/common/model/anthropic-chat-options.d.ts.map +1 -0
  61. package/lib/common/model/anthropic-chat-options.js +157 -0
  62. package/lib/common/model/anthropic-chat-options.js.map +1 -0
  63. package/lib/common/model/index.d.ts +3 -0
  64. package/lib/common/model/index.d.ts.map +1 -0
  65. package/lib/common/model/index.js +6 -0
  66. package/lib/common/model/index.js.map +1 -0
  67. package/lib/common/module.d.ts +4 -0
  68. package/lib/common/module.d.ts.map +1 -0
  69. package/lib/common/module.js +6 -0
  70. package/lib/common/module.js.map +1 -0
  71. package/lib/common/test/mock-anthropic-api.d.ts +9 -0
  72. package/lib/common/test/mock-anthropic-api.d.ts.map +1 -0
  73. package/lib/common/test/mock-anthropic-api.js +46 -0
  74. package/lib/common/test/mock-anthropic-api.js.map +1 -0
  75. package/lib/common/test/test-container.d.ts +3 -0
  76. package/lib/common/test/test-container.d.ts.map +1 -0
  77. package/lib/common/test/test-container.js +15 -0
  78. package/lib/common/test/test-container.js.map +1 -0
  79. package/lib/common/utils/index.d.ts +2 -0
  80. package/lib/common/utils/index.d.ts.map +1 -0
  81. package/lib/common/utils/index.js +5 -0
  82. package/lib/common/utils/index.js.map +1 -0
  83. package/lib/common/utils/stream-util.d.ts +9 -0
  84. package/lib/common/utils/stream-util.d.ts.map +1 -0
  85. package/lib/common/utils/stream-util.js +114 -0
  86. package/lib/common/utils/stream-util.js.map +1 -0
  87. package/lib/package.spec.d.ts +1 -0
  88. package/lib/package.spec.d.ts.map +1 -0
  89. package/lib/package.spec.js +4 -0
  90. package/lib/package.spec.js.map +1 -0
  91. package/package.json +46 -0
  92. package/src/common/api/anthropic-api.spec.ts +165 -0
  93. package/src/common/api/anthropic-api.ts +90 -0
  94. package/src/common/api/anthropic-model.ts +42 -0
  95. package/src/common/api/api-protocol.ts +45 -0
  96. package/src/common/api/chat-request.ts +280 -0
  97. package/src/common/api/chat-response.ts +161 -0
  98. package/src/common/api/content-block.ts +155 -0
  99. package/src/common/api/event.ts +376 -0
  100. package/src/common/api/index.ts +9 -0
  101. package/src/common/api/message.ts +49 -0
  102. package/src/common/api/usage.ts +24 -0
  103. package/src/common/index.ts +2 -0
  104. package/src/common/model/anthropic-chat-model.spec.ts +67 -0
  105. package/src/common/model/anthropic-chat-model.ts +187 -0
  106. package/src/common/model/anthropic-chat-options.ts +152 -0
  107. package/src/common/model/index.ts +2 -0
  108. package/src/common/module.ts +4 -0
  109. package/src/common/test/mock-anthropic-api.ts +62 -0
  110. package/src/common/test/test-container.ts +12 -0
  111. package/src/common/utils/index.ts +1 -0
  112. package/src/common/utils/stream-util.ts +142 -0
  113. package/src/package.spec.ts +4 -0
@@ -0,0 +1,376 @@
1
+ import { Type } from 'class-transformer';
2
+ import { ChatResponse } from './chat-response';
3
+ import { StreamEvent } from '@celljs/ai-core';
4
+ import { ContentBlockType } from './content-block';
5
+
6
+ /**
7
+ * The event type of the streamed chunk.
8
+ */
9
+ export enum EventType {
10
+ /**
11
+ * Message start event. Contains a Message object with empty content.
12
+ */
13
+ MESSAGE_START = 'message_start',
14
+
15
+ /**
16
+ * Message delta event, indicating top-level changes to the final Message object.
17
+ */
18
+ MESSAGE_DELTA = 'message_delta',
19
+
20
+ /**
21
+ * A final message stop event.
22
+ */
23
+ MESSAGE_STOP = 'message_stop',
24
+
25
+ /**
26
+ * Content block start event.
27
+ */
28
+ CONTENT_BLOCK_START = 'content_block_start',
29
+
30
+ /**
31
+ * Content block delta event.
32
+ */
33
+ CONTENT_BLOCK_DELTA = 'content_block_delta',
34
+
35
+ /**
36
+ * A final content block stop event.
37
+ */
38
+ CONTENT_BLOCK_STOP = 'content_block_stop',
39
+
40
+ /**
41
+ * Error event.
42
+ */
43
+ ERROR = 'error',
44
+
45
+ /**
46
+ * Ping event.
47
+ */
48
+ PING = 'ping',
49
+
50
+ /**
51
+ * Artificially created event to aggregate tool use events.
52
+ */
53
+ TOOL_USE_AGGREGATE = 'tool_use_aggregate'
54
+
55
+ }
56
+
57
+ /**
58
+ * Anthropic event.
59
+ */
60
+ export class AnthropicEvent {
61
+ type: EventType;
62
+ }
63
+
64
+ /**
65
+ * Content block body.
66
+ */
67
+ export class ContentBlockBody {
68
+ /**
69
+ * The type of the content block. e.g. "text", "tool_use".
70
+ */
71
+ type: string;
72
+ }
73
+
74
+ /**
75
+ * Text content block delta.
76
+ */
77
+ export class ContentBlockText extends ContentBlockBody {
78
+
79
+ /*
80
+ * The text of the message. Applicable for "text" types only.
81
+ */
82
+ text: string;
83
+ }
84
+
85
+ /**
86
+ * Tool use content block.
87
+ */
88
+ export class ContentBlockToolUse extends ContentBlockBody {
89
+ /*
90
+ * The id of the tool use. Applicable only for tool_use response.
91
+ */
92
+ id: string;
93
+
94
+ /*
95
+ * The name of the tool use. Applicable only for tool_use response.
96
+ */
97
+ name: string;
98
+
99
+ /*
100
+ * The input of the tool use. Applicable only for tool_use response.
101
+ */
102
+ input: Record<string, any>;
103
+
104
+ constructor(type: ContentBlockType, id: string, name: string, input: Record<string, any>) {
105
+ super();
106
+ this.type = type;
107
+ this.id = id;
108
+ this.name = name;
109
+ this.input = input;
110
+ }
111
+ }
112
+
113
+ export class AnthropicEventWithContentBlock extends AnthropicEvent {
114
+ /**
115
+ * The content block body.
116
+ */
117
+ @Type(() => ContentBlockBody, {
118
+ discriminator: {
119
+ property: 'type',
120
+ subTypes: [
121
+ { value: ContentBlockText, name: ContentBlockType.TEXT },
122
+ { value: ContentBlockToolUse, name: ContentBlockType.TOOL_USE }
123
+ ]
124
+ }
125
+ })
126
+ contentBlock: ContentBlockBody;
127
+ }
128
+
129
+ /**
130
+ * Special event used to aggregate multiple tool use events into a single event with
131
+ * list of aggregated ContentBlockToolUse.
132
+ */
133
+ export class ToolUseAggregationEvent extends AnthropicEvent {
134
+ /*
135
+ * The index of the content block. Applicable only for streaming responses.
136
+ */
137
+ index?: number;
138
+
139
+ /*
140
+ * The id of the tool use. Applicable only for tool_use response.
141
+ */
142
+ id?: string;
143
+
144
+ /*
145
+ * The name of the tool use. Applicable only for tool_use response.
146
+ */
147
+ name?: string;
148
+
149
+ /*
150
+ * The partial JSON content.
151
+ */
152
+ partialJson: string = '';
153
+
154
+ /*
155
+ * The tool content blocks.
156
+ */
157
+ toolContentBlocks: ContentBlockToolUse[] = [];
158
+
159
+ isEmpty(): boolean {
160
+ return (this.index === undefined || !this.id || !this.name || !this.partialJson);
161
+ }
162
+
163
+ appendPartialJson(partialJson: string): ToolUseAggregationEvent {
164
+ this.partialJson = this.partialJson + partialJson;
165
+ return this;
166
+ }
167
+
168
+ squashIntoContentBlock(): void {
169
+ const map = (this.partialJson) ? JSON.parse(this.partialJson) : {};
170
+ this.toolContentBlocks.push(new ContentBlockToolUse(ContentBlockType.TOOL_USE, this.id!, this.name!, map));
171
+ this.index = undefined;
172
+ this.id = undefined;
173
+ this.name = undefined;
174
+ this.partialJson = '';
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Content block delta body.
180
+ */
181
+ export class ContentBlockDeltaBody {
182
+ /*
183
+ * The type of the content block. e.g. "text", "input_json".
184
+ */
185
+ type: string;
186
+ }
187
+
188
+ /**
189
+ * Text content block delta.
190
+ */
191
+ export class ContentBlockDeltaText extends ContentBlockDeltaBody {
192
+ /*
193
+ * The text of the message. Applicable for "text" types only.
194
+ */
195
+ text: string;
196
+ }
197
+
198
+ /**
199
+ * JSON content block delta.
200
+ */
201
+ export class ContentBlockDeltaJson extends ContentBlockDeltaBody {
202
+ /*
203
+ * The partial JSON content.
204
+ */
205
+ partialJson: string;
206
+ }
207
+
208
+ /**
209
+ * Content block stop event.
210
+ */
211
+ export class ContentBlockStopEvent extends AnthropicEvent {
212
+ /*
213
+ * The index of the content block. Applicable only for streaming responses.
214
+ */
215
+ index: number;
216
+ }
217
+
218
+ /**
219
+ * Content block start event.
220
+ */
221
+ export class ContentBlockStartEvent extends AnthropicEventWithContentBlock {
222
+
223
+ /*
224
+ * The index of the content block. Applicable only for streaming responses.
225
+ */
226
+ index: number;
227
+ }
228
+
229
+ /**
230
+ * Content block delta event.
231
+ */
232
+ export class ContentBlockDeltaEvent extends AnthropicEvent {
233
+
234
+ /*
235
+ * The index of the content block. Applicable only for streaming responses.
236
+ */
237
+ index: number;
238
+
239
+ /*
240
+ * The content block delta body.
241
+ */
242
+ @Type(() => ContentBlockDeltaBody, {
243
+ discriminator: {
244
+ property: 'type',
245
+ subTypes: [
246
+ { value: ContentBlockDeltaText, name: ContentBlockType.TEXT_DELTA },
247
+ { value: ContentBlockDeltaJson, name: ContentBlockType.INPUT_JSON_DELTA }
248
+ ]
249
+ }
250
+ })
251
+ delta: ContentBlockDeltaBody;
252
+
253
+ }
254
+
255
+ /**
256
+ * Message start event.
257
+ */
258
+ export class MessageStartEvent {
259
+ /*
260
+ * The event type.
261
+ */
262
+ type: EventType;
263
+
264
+ /*
265
+ * The message body.
266
+ */
267
+ message: ChatResponse;
268
+
269
+ constructor(type: EventType, message: ChatResponse) {
270
+ this.type = type;
271
+ this.message = message;
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Message delta event.
277
+ */
278
+ export class MessageDeltaEvent extends AnthropicEvent {
279
+
280
+ /*
281
+ * The message delta body.
282
+ */
283
+ delta: MessageDelta;
284
+
285
+ /*
286
+ * The message delta usage.
287
+ */
288
+ usage: MessageDeltaUsage;
289
+
290
+ }
291
+
292
+ /**
293
+ * Message delta.
294
+ */
295
+ export class MessageDelta {
296
+ /*
297
+ * The stop reason.
298
+ */
299
+ stopReason: string;
300
+
301
+ /*
302
+ * The stop sequence.
303
+ */
304
+ stopSequence: string;
305
+ }
306
+
307
+ /**
308
+ * Message delta usage.
309
+ */
310
+ export class MessageDeltaUsage {
311
+ /*
312
+ * The output tokens.
313
+ */
314
+ outputTokens: number;
315
+ }
316
+
317
+ /**
318
+ * Message stop event.
319
+ */
320
+ export class MessageStopEvent extends AnthropicEvent {
321
+
322
+ }
323
+
324
+ /**
325
+ * Error event.
326
+ */
327
+ export class ErrorEvent extends AnthropicEvent {
328
+
329
+ /*
330
+ * The error body.
331
+ */
332
+ error: Error;
333
+ }
334
+
335
+ /**
336
+ * Error body.
337
+ */
338
+ export class Error {
339
+ /*
340
+ * The error type.
341
+ */
342
+ type: string;
343
+
344
+ /*
345
+ * The error message.
346
+ */
347
+ message: string;
348
+ }
349
+
350
+ /**
351
+ * Ping event.
352
+ */
353
+ export class PingEvent extends AnthropicEvent {
354
+
355
+ }
356
+
357
+ export class AnthropicStreamEvent implements StreamEvent<AnthropicEvent> {
358
+ event?: EventType;
359
+ @Type(() => AnthropicEvent, {
360
+ discriminator: {
361
+ property: 'type',
362
+ subTypes: [
363
+ { value: ContentBlockStartEvent, name: EventType.CONTENT_BLOCK_START },
364
+ { value: ContentBlockDeltaEvent, name: EventType.CONTENT_BLOCK_DELTA },
365
+ { value: ContentBlockStopEvent, name: EventType.CONTENT_BLOCK_STOP },
366
+ { value: PingEvent, name: EventType.PING },
367
+ { value: ErrorEvent, name: EventType.ERROR },
368
+ { value: MessageStartEvent, name: EventType.MESSAGE_START },
369
+ { value: MessageDeltaEvent, name: EventType.MESSAGE_DELTA },
370
+ { value: MessageStopEvent, name: EventType.MESSAGE_STOP }
371
+ ]
372
+ }
373
+ })
374
+ data: AnthropicEvent;
375
+ raw: string[];
376
+ }
@@ -0,0 +1,9 @@
1
+ export * from './api-protocol';
2
+ export * from './chat-request';
3
+ export * from './chat-response';
4
+ export * from './anthropic-api';
5
+ export * from './event';
6
+ export * from './message';
7
+ export * from './usage';
8
+ export * from './content-block';
9
+ export * from './anthropic-model';
@@ -0,0 +1,49 @@
1
+ import { Type } from 'class-transformer';
2
+ import { ContentBlock } from './content-block';
3
+
4
+ /**
5
+ * The role of the message in the conversation.
6
+ */
7
+ export enum Role {
8
+ /**
9
+ * User message type.
10
+ */
11
+ USER = 'user',
12
+ /**
13
+ * Assistant message type. Usually the response from the model.
14
+ */
15
+ ASSISTANT = 'assistant',
16
+ }
17
+
18
+ /**
19
+ * Input messages.
20
+ *
21
+ * Our models are trained to operate on alternating user and assistant conversational
22
+ * turns. When creating a new Message, you specify the prior conversational turns with
23
+ * the messages parameter, and the model then generates the next Message in the
24
+ * conversation. Each input message must be an object with a role and content. You can
25
+ * specify a single user-role message, or you can include multiple user and assistant
26
+ * messages. The first message must always use the user role. If the final message
27
+ * uses the assistant role, the response content will continue immediately from the
28
+ * content in that message. This can be used to constrain part of the model's
29
+ * response.
30
+ */
31
+ export class AnthropicMessage {
32
+ /**
33
+ * The contents of the message. Can be of one of String or MultiModalContent
34
+ * types.
35
+ */
36
+ @Type(() => ContentBlock)
37
+ content: ContentBlock[];
38
+
39
+ /**
40
+ * The role of the messages author. Could be one of the {@link Role}
41
+ * types.
42
+ */
43
+ role: Role;
44
+
45
+ constructor(content: ContentBlock[], role: Role) {
46
+ this.content = content;
47
+ this.role = role;
48
+ }
49
+ }
@@ -0,0 +1,24 @@
1
+ import { Expose } from 'class-transformer';
2
+
3
+ /**
4
+ * Usage statistics.
5
+ */
6
+ export class Usage {
7
+
8
+ /**
9
+ * The number of input tokens which were used.
10
+ */
11
+ @Expose({ name: 'input_tokens' })
12
+ inputTokens: number;
13
+
14
+ /**
15
+ * The number of output tokens which were used.
16
+ */
17
+ @Expose({ name: 'output_tokens' })
18
+ outputTokens: number;
19
+
20
+ constructor(inputTokens: number, outputTokens: number) {
21
+ this.inputTokens = inputTokens;
22
+ this.outputTokens = outputTokens;
23
+ }
24
+ }
@@ -0,0 +1,2 @@
1
+ export * from './api';
2
+ export * from './model';
@@ -0,0 +1,67 @@
1
+ import { expect } from 'chai';
2
+ import '../index';
3
+ import { AnthropicChatModel } from './anthropic-chat-model';
4
+ import { AssistantMessage, PromptTemplate } from '@celljs/ai-core';
5
+ import { createContainer } from '../test/test-container';
6
+ import { AnthropicModel } from '../api/anthropic-model';
7
+ import { MockAnthropicAPI } from '../test/mock-anthropic-api';
8
+ import { AnthropicAPI } from '../api/api-protocol';
9
+
10
+ const container = createContainer();
11
+
12
+ describe('AnthropicChatModel', () => {
13
+ let anthropicChatModel: AnthropicChatModel;
14
+ let promptTemplate: PromptTemplate;
15
+
16
+ before(() => {
17
+ container.rebind(AnthropicAPI).to(MockAnthropicAPI).inSingletonScope();
18
+ anthropicChatModel = container.get(AnthropicChatModel);
19
+ promptTemplate = container.get(PromptTemplate);
20
+ });
21
+
22
+ describe('call', () => {
23
+ it('should return a ChatResponse for a given prompt', async () => {
24
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: AnthropicModel.CLAUDE_3_5_SONNET } });
25
+ const response = await anthropicChatModel.call(prompt);
26
+ expect(response).to.have.property('result');
27
+ expect(response.result.output).to.be.instanceOf(AssistantMessage);
28
+ });
29
+
30
+ it('should throw an error if the model is not set', async () => {
31
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: '' } });
32
+ try {
33
+ await anthropicChatModel.call(prompt);
34
+ } catch (e) {
35
+ expect(e).to.be.instanceOf(Error);
36
+ expect(e.message).to.equal('Model is not set!');
37
+ }
38
+ });
39
+ });
40
+
41
+ describe('stream', () => {
42
+ it('should return an Observable of ChatResponse for a given prompt', done => {
43
+ (async () => {
44
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: AnthropicModel.CLAUDE_3_5_SONNET } });
45
+ const response$ = await anthropicChatModel.stream(prompt);
46
+ response$.subscribe({
47
+ next: response => {
48
+ expect(response).to.have.property('result');
49
+ expect(response.result.output).to.be.instanceOf(AssistantMessage);
50
+ },
51
+ complete: () => done()
52
+ });
53
+ })();
54
+ });
55
+
56
+ it('should throw an error if the model is not set', async () => {
57
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: '' } });
58
+ try {
59
+ await anthropicChatModel.stream(prompt);
60
+ } catch (e) {
61
+ expect(e).to.be.instanceOf(Error);
62
+ expect(e.message).to.equal('Model is not set!');
63
+ }
64
+ });
65
+
66
+ });
67
+ });