@celljs/ai-openai 3.4.4

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 (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/lib/common/api/api-protocol.d.ts +47 -0
  4. package/lib/common/api/api-protocol.d.ts.map +1 -0
  5. package/lib/common/api/api-protocol.js +6 -0
  6. package/lib/common/api/api-protocol.js.map +1 -0
  7. package/lib/common/api/chat-request.d.ts +198 -0
  8. package/lib/common/api/chat-request.d.ts.map +1 -0
  9. package/lib/common/api/chat-request.js +145 -0
  10. package/lib/common/api/chat-request.js.map +1 -0
  11. package/lib/common/api/chat-response.d.ts +193 -0
  12. package/lib/common/api/chat-response.d.ts.map +1 -0
  13. package/lib/common/api/chat-response.js +124 -0
  14. package/lib/common/api/chat-response.js.map +1 -0
  15. package/lib/common/api/embeddings-request.d.ts +59 -0
  16. package/lib/common/api/embeddings-request.d.ts.map +1 -0
  17. package/lib/common/api/embeddings-request.js +49 -0
  18. package/lib/common/api/embeddings-request.js.map +1 -0
  19. package/lib/common/api/embeddings-response.d.ts +27 -0
  20. package/lib/common/api/embeddings-response.d.ts.map +1 -0
  21. package/lib/common/api/embeddings-response.js +30 -0
  22. package/lib/common/api/embeddings-response.js.map +1 -0
  23. package/lib/common/api/index.d.ts +10 -0
  24. package/lib/common/api/index.d.ts.map +1 -0
  25. package/lib/common/api/index.js +13 -0
  26. package/lib/common/api/index.js.map +1 -0
  27. package/lib/common/api/message.d.ts +216 -0
  28. package/lib/common/api/message.d.ts.map +1 -0
  29. package/lib/common/api/message.js +179 -0
  30. package/lib/common/api/message.js.map +1 -0
  31. package/lib/common/api/openai-api.d.ts +18 -0
  32. package/lib/common/api/openai-api.d.ts.map +1 -0
  33. package/lib/common/api/openai-api.js +99 -0
  34. package/lib/common/api/openai-api.js.map +1 -0
  35. package/lib/common/api/openai-api.spec.d.ts +2 -0
  36. package/lib/common/api/openai-api.spec.d.ts.map +1 -0
  37. package/lib/common/api/openai-api.spec.js +162 -0
  38. package/lib/common/api/openai-api.spec.js.map +1 -0
  39. package/lib/common/api/openai-model.d.ts +117 -0
  40. package/lib/common/api/openai-model.d.ts.map +1 -0
  41. package/lib/common/api/openai-model.js +121 -0
  42. package/lib/common/api/openai-model.js.map +1 -0
  43. package/lib/common/api/response-format.d.ts +60 -0
  44. package/lib/common/api/response-format.d.ts.map +1 -0
  45. package/lib/common/api/response-format.js +79 -0
  46. package/lib/common/api/response-format.js.map +1 -0
  47. package/lib/common/api/usage.d.ts +79 -0
  48. package/lib/common/api/usage.d.ts.map +1 -0
  49. package/lib/common/api/usage.js +95 -0
  50. package/lib/common/api/usage.js.map +1 -0
  51. package/lib/common/index.d.ts +4 -0
  52. package/lib/common/index.d.ts.map +1 -0
  53. package/lib/common/index.js +7 -0
  54. package/lib/common/index.js.map +1 -0
  55. package/lib/common/model/index.d.ts +5 -0
  56. package/lib/common/model/index.d.ts.map +1 -0
  57. package/lib/common/model/index.js +8 -0
  58. package/lib/common/model/index.js.map +1 -0
  59. package/lib/common/model/openai-chat-model.d.ts +37 -0
  60. package/lib/common/model/openai-chat-model.d.ts.map +1 -0
  61. package/lib/common/model/openai-chat-model.js +357 -0
  62. package/lib/common/model/openai-chat-model.js.map +1 -0
  63. package/lib/common/model/openai-chat-model.spec.d.ts +2 -0
  64. package/lib/common/model/openai-chat-model.spec.d.ts.map +1 -0
  65. package/lib/common/model/openai-chat-model.spec.js +82 -0
  66. package/lib/common/model/openai-chat-model.spec.js.map +1 -0
  67. package/lib/common/model/openai-chat-options.d.ts +159 -0
  68. package/lib/common/model/openai-chat-options.d.ts.map +1 -0
  69. package/lib/common/model/openai-chat-options.js +231 -0
  70. package/lib/common/model/openai-chat-options.js.map +1 -0
  71. package/lib/common/model/openai-embedding-model.d.ts +15 -0
  72. package/lib/common/model/openai-embedding-model.d.ts.map +1 -0
  73. package/lib/common/model/openai-embedding-model.js +64 -0
  74. package/lib/common/model/openai-embedding-model.js.map +1 -0
  75. package/lib/common/model/openai-embedding-model.spec.d.ts +2 -0
  76. package/lib/common/model/openai-embedding-model.spec.d.ts.map +1 -0
  77. package/lib/common/model/openai-embedding-model.spec.js +100 -0
  78. package/lib/common/model/openai-embedding-model.spec.js.map +1 -0
  79. package/lib/common/model/openai-embedding-options.d.ts +35 -0
  80. package/lib/common/model/openai-embedding-options.d.ts.map +1 -0
  81. package/lib/common/model/openai-embedding-options.js +56 -0
  82. package/lib/common/model/openai-embedding-options.js.map +1 -0
  83. package/lib/common/module.d.ts +4 -0
  84. package/lib/common/module.d.ts.map +1 -0
  85. package/lib/common/module.js +6 -0
  86. package/lib/common/module.js.map +1 -0
  87. package/lib/common/support/index.d.ts +3 -0
  88. package/lib/common/support/index.d.ts.map +1 -0
  89. package/lib/common/support/index.js +6 -0
  90. package/lib/common/support/index.js.map +1 -0
  91. package/lib/common/support/openai-api-response-headers.d.ts +34 -0
  92. package/lib/common/support/openai-api-response-headers.d.ts.map +1 -0
  93. package/lib/common/support/openai-api-response-headers.js +45 -0
  94. package/lib/common/support/openai-api-response-headers.js.map +1 -0
  95. package/lib/common/support/openai-response-header-extractor.d.ts +12 -0
  96. package/lib/common/support/openai-response-header-extractor.d.ts.map +1 -0
  97. package/lib/common/support/openai-response-header-extractor.js +131 -0
  98. package/lib/common/support/openai-response-header-extractor.js.map +1 -0
  99. package/lib/common/test/mock-openai-api.d.ts +13 -0
  100. package/lib/common/test/mock-openai-api.d.ts.map +1 -0
  101. package/lib/common/test/mock-openai-api.js +57 -0
  102. package/lib/common/test/mock-openai-api.js.map +1 -0
  103. package/lib/common/test/test-container.d.ts +3 -0
  104. package/lib/common/test/test-container.d.ts.map +1 -0
  105. package/lib/common/test/test-container.js +16 -0
  106. package/lib/common/test/test-container.js.map +1 -0
  107. package/lib/package.spec.d.ts +1 -0
  108. package/lib/package.spec.d.ts.map +1 -0
  109. package/lib/package.spec.js +4 -0
  110. package/lib/package.spec.js.map +1 -0
  111. package/package.json +46 -0
  112. package/src/common/api/api-protocol.ts +51 -0
  113. package/src/common/api/chat-request.ts +258 -0
  114. package/src/common/api/chat-response.ts +218 -0
  115. package/src/common/api/embeddings-request.ts +92 -0
  116. package/src/common/api/embeddings-response.ts +44 -0
  117. package/src/common/api/index.ts +9 -0
  118. package/src/common/api/message.ts +273 -0
  119. package/src/common/api/openai-api.spec.ts +175 -0
  120. package/src/common/api/openai-api.ts +111 -0
  121. package/src/common/api/openai-model.ts +137 -0
  122. package/src/common/api/response-format.ts +109 -0
  123. package/src/common/api/usage.ts +135 -0
  124. package/src/common/index.ts +3 -0
  125. package/src/common/model/index.ts +4 -0
  126. package/src/common/model/openai-chat-model.spec.ts +85 -0
  127. package/src/common/model/openai-chat-model.ts +399 -0
  128. package/src/common/model/openai-chat-options.ts +326 -0
  129. package/src/common/model/openai-embedding-model.spec.ts +112 -0
  130. package/src/common/model/openai-embedding-model.ts +83 -0
  131. package/src/common/model/openai-embedding-options.ts +72 -0
  132. package/src/common/module.ts +4 -0
  133. package/src/common/support/index.ts +2 -0
  134. package/src/common/support/openai-api-response-headers.ts +46 -0
  135. package/src/common/support/openai-response-header-extractor.ts +141 -0
  136. package/src/common/test/mock-openai-api.ts +70 -0
  137. package/src/common/test/test-container.ts +13 -0
  138. package/src/package.spec.ts +4 -0
@@ -0,0 +1,109 @@
1
+ export enum ResponseFormatType {
2
+ TEXT = 'text',
3
+ JSON_OBJECT = 'json_object',
4
+ JSON_SCHEMA = 'json_schema'
5
+ }
6
+
7
+ export class JsonSchema {
8
+ name: string;
9
+ schema: Map<string, any>;
10
+ strict: boolean;
11
+ constructor(name: string, schema: Map<string, any>, strict: boolean) {
12
+ this.name = name;
13
+ this.schema = schema;
14
+ this.strict = strict;
15
+ }
16
+
17
+ static builder() {
18
+ return new JsonSchemaBuilder();
19
+ }
20
+ }
21
+
22
+ export class JsonSchemaBuilder {
23
+ private name: string;
24
+ private schema: Map<string, any>;
25
+ private strict: boolean;
26
+
27
+ withName(name: string) {
28
+ this.name = name;
29
+ return this;
30
+ }
31
+
32
+ withSchema(schema: Map<string, any>) {
33
+ this.schema = schema;
34
+ return this;
35
+ }
36
+
37
+ withStrict(strict: boolean) {
38
+ this.strict = strict;
39
+ return this;
40
+ }
41
+
42
+ build() {
43
+ return new JsonSchema(this.name, this.schema, this.strict);
44
+ }
45
+ }
46
+
47
+ /**
48
+ * An object specifying the format that the model must output.
49
+ *
50
+ * Setting the type to JSON_SCHEMA, enables Structured Outputs which ensures the model
51
+ * will match your supplied JSON schema. Learn more in the
52
+ * [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs).
53
+ *
54
+ * References: [OpenAi API - ResponseFormat](https://platform.openai.com/docs/api-reference/chat/create#chat-create-response_format),
55
+ * [JSON Mode](https://platform.openai.com/docs/guides/structured-outputs#json-mode),
56
+ * [Structured Outputs vs JSON mode](https://platform.openai.com/docs/guides/structured-outputs#structured-outputs-vs-json-mode)
57
+ */
58
+ export class ResponseFormat {
59
+ /**
60
+ * Type Must be one of 'text', 'json_object' or 'json_schema'.
61
+ */
62
+ type: ResponseFormatType;
63
+
64
+ /**
65
+ * JSON schema object that describes the format of the JSON object. Only applicable
66
+ * when type is 'json_schema'.
67
+ */
68
+ schema?: JsonSchema;
69
+
70
+ /**
71
+ * Whether the model must strictly adhere to the schema. Only applicable when type is
72
+ * 'json_schema'.
73
+ */
74
+ strict?: boolean;
75
+
76
+ constructor(type: ResponseFormatType, schema?: JsonSchema, strict?: boolean) {
77
+ this.type = type;
78
+ this.schema = schema;
79
+ this.strict = strict;
80
+ }
81
+
82
+ static builder() {
83
+ return new ResponseFormatBuilder();
84
+ }
85
+ }
86
+
87
+ export class ResponseFormatBuilder {
88
+ private type: ResponseFormatType;
89
+ private schema?: JsonSchema;
90
+ private strict?: boolean;
91
+
92
+ withType(type: ResponseFormatType) {
93
+ this.type = type;
94
+ return this;
95
+ }
96
+
97
+ withSchema(schema: JsonSchema) {
98
+ this.schema = schema;
99
+ return this;
100
+ }
101
+
102
+ withStrict(strict: boolean) {
103
+ this.strict = strict;
104
+ return this;
105
+ }
106
+ build() {
107
+ return new ResponseFormat(this.type, this.schema, this.strict);
108
+ }
109
+ }
@@ -0,0 +1,135 @@
1
+ import { Usage as IUsage } from '@celljs/ai-core';
2
+ import { Expose } from 'class-transformer';
3
+
4
+ /**
5
+ * Breakdown of tokens used in the prompt.
6
+ */
7
+ export class PromptTokensDetails {
8
+ /**
9
+ * Audio input tokens present in the prompt.
10
+ */
11
+ @Expose({ name: 'audio_tokens' })
12
+ audioTokens?: number;
13
+
14
+ /**
15
+ * Cached tokens present in the prompt.
16
+ */
17
+ @Expose({ name: 'cached_tokens' })
18
+ cachedTokens?: number;
19
+
20
+ constructor(audioTokens?: number, cachedTokens?: number) {
21
+ this.audioTokens = audioTokens;
22
+ this.cachedTokens = cachedTokens;
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Breakdown of tokens used in a completion.
28
+ */
29
+ export class CompletionTokenDetails {
30
+ /**
31
+ * Number of tokens generated by the model for reasoning.
32
+ */
33
+ @Expose({ name: 'reasoning_tokens' })
34
+ reasoningTokens?: number;
35
+
36
+ /**
37
+ * Number of tokens generated by the model for accepted predictions.
38
+ */
39
+ @Expose({ name: 'accepted_prediction_tokens' })
40
+ acceptedPredictionTokens?: number;
41
+
42
+ /**
43
+ * Number of tokens generated by the model for audio.
44
+ */
45
+ @Expose({ name: 'audio_tokens' })
46
+ audioTokens?: number;
47
+
48
+ /**
49
+ * Number of tokens generated by the model for rejected predictions.
50
+ */
51
+ @Expose({ name: 'rejected_prediction_tokens' })
52
+ rejectedPredictionTokens?: number;
53
+
54
+ constructor(
55
+ reasoningTokens?: number,
56
+ acceptedPredictionTokens?: number,
57
+ audioTokens?: number,
58
+ rejectedPredictionTokens?: number
59
+ ) {
60
+ this.reasoningTokens = reasoningTokens;
61
+ this.acceptedPredictionTokens = acceptedPredictionTokens;
62
+ this.audioTokens = audioTokens;
63
+ this.rejectedPredictionTokens = rejectedPredictionTokens;
64
+ }
65
+ }
66
+
67
+ /**
68
+ * The response object returned from the /embedding endpoint.
69
+ */
70
+ export class EmbeddingsResponse {
71
+ /**
72
+ * The model used for generating the embeddings.
73
+ */
74
+ model: string;
75
+
76
+ /**
77
+ * The list of embeddings generated from the model.
78
+ * Each embedding (list of doubles) corresponds to a single input text.
79
+ */
80
+ embeddings: number[][];
81
+
82
+ constructor(model: string, embeddings: number[][]) {
83
+ this.model = model;
84
+ this.embeddings = embeddings;
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Usage statistics for the completion request.
90
+ */
91
+ export class Usage implements IUsage {
92
+ /**
93
+ * Number of tokens in the generated completion. Only applicable for completion requests.
94
+ */
95
+ @Expose({ name: 'completion_tokens' })
96
+ completionTokens?: number;
97
+
98
+ /**
99
+ * Number of tokens in the prompt.
100
+ */
101
+ @Expose({ name: 'prompt_tokens' })
102
+ promptTokens?: number;
103
+
104
+ /**
105
+ * Total number of tokens used in the request (prompt + completion).
106
+ */
107
+ @Expose({ name: 'total_tokens' })
108
+ totalTokens?: number;
109
+
110
+ /**
111
+ * Breakdown of tokens used in the prompt.
112
+ */
113
+ @Expose({ name: 'prompt_tokens_details' })
114
+ promptTokensDetails?: PromptTokensDetails;
115
+
116
+ /**
117
+ * Breakdown of tokens used in a completion.
118
+ */
119
+ @Expose({ name: 'completion_tokens_details' })
120
+ completionTokenDetails?: CompletionTokenDetails;
121
+
122
+ constructor(
123
+ completionTokens?: number,
124
+ promptTokens?: number,
125
+ totalTokens?: number,
126
+ promptTokensDetails?: PromptTokensDetails,
127
+ completionTokenDetails?: CompletionTokenDetails
128
+ ) {
129
+ this.completionTokens = completionTokens;
130
+ this.promptTokens = promptTokens;
131
+ this.totalTokens = totalTokens;
132
+ this.promptTokensDetails = promptTokensDetails;
133
+ this.completionTokenDetails = completionTokenDetails;
134
+ }
135
+ }
@@ -0,0 +1,3 @@
1
+ export * from './api';
2
+ export * from './model';
3
+ export * from './support';
@@ -0,0 +1,4 @@
1
+ export * from './openai-chat-model';
2
+ export * from './openai-chat-options';
3
+ export * from './openai-embedding-model';
4
+ export * from './openai-embedding-options';
@@ -0,0 +1,85 @@
1
+ import { expect } from 'chai';
2
+ import '../index';
3
+ import { OpenAIChatModel } from './openai-chat-model';
4
+ import { AssistantMessage, ChatOptions, FunctionCallbackRegister, PromptTemplate } from '@celljs/ai-core';
5
+ import { createContainer } from '../test/test-container';
6
+ import { OpenAIAPI } from '../api/api-protocol';
7
+ import { MockOpenAIAPI } from '../test/mock-openai-api';
8
+
9
+ const container = createContainer();
10
+
11
+ describe('OpenAIChatModel', () => {
12
+ let openAIChatModel: OpenAIChatModel;
13
+ let promptTemplate: PromptTemplate;
14
+
15
+ before(() => {
16
+ container.rebind(OpenAIAPI).to(MockOpenAIAPI).inSingletonScope();
17
+ openAIChatModel = container.get(OpenAIChatModel);
18
+ promptTemplate = container.get(PromptTemplate);
19
+ const functionCallbackRegister = container.get<FunctionCallbackRegister>(FunctionCallbackRegister);
20
+ functionCallbackRegister.register({
21
+ name: 'getWeather',
22
+ description: '',
23
+ inputTypeSchema: '{}',
24
+ call: async () => ''
25
+ });
26
+ });
27
+
28
+ describe('call', () => {
29
+ it('should return a ChatResponse for a given prompt', async () => {
30
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: 'gpt-4' } });
31
+ const response = await openAIChatModel.call(prompt);
32
+ expect(response).to.have.property('results');
33
+ expect(response.results.length).to.be.greaterThan(0);
34
+ expect(response.results[0].output).to.be.instanceOf(AssistantMessage);
35
+ });
36
+
37
+ it('should handle tool calls correctly', async () => {
38
+ const prompt = await promptTemplate.create('What is the weather today?', {
39
+ chatOptions: {
40
+ model: 'gpt-4',
41
+ isProxyToolCalls: true,
42
+ functions: new Set(['getWeather'])
43
+ } as ChatOptions
44
+ });
45
+ const response = await openAIChatModel.call(prompt);
46
+ expect(response).to.have.property('results');
47
+ expect(response.results.length).to.be.greaterThan(0);
48
+ expect(response.metadata).to.have.property('model');
49
+ expect(response.metadata).to.have.property('usage');
50
+ });
51
+ });
52
+
53
+ describe('stream', () => {
54
+ it('should return an Observable of ChatResponse for a given prompt', done => {
55
+ (async () => {
56
+ const prompt = await promptTemplate.create('Hello', { chatOptions: { model: 'gpt-4' } });
57
+ const response$ = await openAIChatModel.stream(prompt);
58
+ response$.subscribe({
59
+ next: response => {
60
+ expect(response).to.have.property('results');
61
+ expect(response.results.length).to.be.greaterThan(0);
62
+ expect(response.results[0].output).to.be.instanceOf(AssistantMessage);
63
+ },
64
+ complete: () => done()
65
+ });
66
+ })();
67
+ });
68
+
69
+ it('should throw an error when trying to stream with audio output', async () => {
70
+ const prompt = await promptTemplate.create('Hello', {
71
+ chatOptions: {
72
+ model: 'gpt-4',
73
+ outputModalities: ['audio']
74
+ } as ChatOptions
75
+ });
76
+ try {
77
+ await openAIChatModel.stream(prompt);
78
+ expect.fail('Should have thrown an error');
79
+ } catch (e) {
80
+ expect(e).to.be.instanceOf(Error);
81
+ expect(e.message).to.include('Audio output is not supported');
82
+ }
83
+ });
84
+ });
85
+ });