@purista/harness-openai 1.2.6 → 1.5.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.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +114 -84
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseModelProvider, ModelError } from '@purista/harness';
|
|
1
|
+
import { BaseModelProvider, ModelError, accumulateStreamToolCallDeltas, createStreamToolCallState, finalizeStreamToolCalls, malformedResponseError, parseProviderJson, safePartialJson, sanitizeProviderMessage, toTokenUsage } from '@purista/harness';
|
|
2
2
|
import OpenAI, {} from 'openai';
|
|
3
3
|
/**
|
|
4
4
|
* Creates an OpenAI-backed harness `ModelProvider`.
|
|
@@ -32,6 +32,7 @@ import OpenAI, {} from 'openai';
|
|
|
32
32
|
* summarize: {
|
|
33
33
|
* input: z.string(),
|
|
34
34
|
* output: z.string(),
|
|
35
|
+
* delegation: { agents: ['assistant'] },
|
|
35
36
|
* handler: (ctx) => ctx.agents.assistant(ctx.input)
|
|
36
37
|
* }
|
|
37
38
|
* })
|
|
@@ -62,6 +63,7 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
62
63
|
req.signal.throwIfAborted();
|
|
63
64
|
if (this.options.api === 'responses') {
|
|
64
65
|
const response = await createResponse(this.client, req, false);
|
|
66
|
+
throwIfResponsesFailure(response, req, 'text');
|
|
65
67
|
return mapResponsesTextResponse(response, req);
|
|
66
68
|
}
|
|
67
69
|
const response = await createChatCompletion(this.client, req, false, this.getLogger());
|
|
@@ -76,12 +78,13 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
76
78
|
const stream = await createChatCompletion(this.client, req, true, this.getLogger());
|
|
77
79
|
let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
78
80
|
let finishReason = 'stop';
|
|
79
|
-
|
|
81
|
+
let providerFinishReason;
|
|
82
|
+
const toolState = createStreamToolCallState();
|
|
80
83
|
for await (const chunk of stream) {
|
|
81
84
|
req.signal.throwIfAborted();
|
|
82
85
|
// The usage chunk arrives with an empty choices array, so read it first.
|
|
83
86
|
if (chunk.usage) {
|
|
84
|
-
usage =
|
|
87
|
+
usage = toTokenUsage(chunk.usage.prompt_tokens, chunk.usage.completion_tokens);
|
|
85
88
|
}
|
|
86
89
|
const choice = chunk.choices?.[0];
|
|
87
90
|
if (!choice)
|
|
@@ -90,21 +93,23 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
90
93
|
yield { kind: 'delta', text: choice.delta.content };
|
|
91
94
|
}
|
|
92
95
|
if (choice.delta?.tool_calls) {
|
|
93
|
-
|
|
96
|
+
accumulateStreamToolCallDeltas(toolState, choice.delta.tool_calls);
|
|
94
97
|
}
|
|
95
98
|
if (choice.finish_reason) {
|
|
96
|
-
|
|
99
|
+
providerFinishReason = choice.finish_reason;
|
|
100
|
+
finishReason = toFinishReason(providerFinishReason);
|
|
97
101
|
}
|
|
98
102
|
}
|
|
99
|
-
for (const call of finalizeStreamToolCalls(toolState, req, 'textStream')) {
|
|
103
|
+
for (const call of finalizeStreamToolCalls(toolState, callContext(req, 'textStream'), MALFORMED_TOOL_ARGS_MESSAGE)) {
|
|
100
104
|
yield { kind: 'tool_call', call };
|
|
101
105
|
}
|
|
102
|
-
yield { kind: 'finish', usage, finishReason };
|
|
106
|
+
yield { kind: 'finish', usage, finishReason, outcome: toOutcome(finishReason, providerFinishReason) };
|
|
103
107
|
}
|
|
104
108
|
async doObject(req) {
|
|
105
109
|
req.signal.throwIfAborted();
|
|
106
110
|
if (this.options.api === 'responses') {
|
|
107
111
|
const response = await createResponse(this.client, req, false);
|
|
112
|
+
throwIfResponsesFailure(response, req, 'object');
|
|
108
113
|
const content = extractResponsesText(response);
|
|
109
114
|
const toolCalls = extractResponsesToolCalls(response, req, 'object');
|
|
110
115
|
const providerItems = toResponsesProviderItems(response.output, toolCalls);
|
|
@@ -114,6 +119,7 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
114
119
|
...(providerItems ? { providerItems } : {}),
|
|
115
120
|
usage: toResponsesUsage(response.usage),
|
|
116
121
|
finishReason: toResponsesFinishReason(response),
|
|
122
|
+
outcome: toResponsesOutcome(response),
|
|
117
123
|
raw: response
|
|
118
124
|
};
|
|
119
125
|
}
|
|
@@ -123,8 +129,9 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
123
129
|
return {
|
|
124
130
|
object: parseJson(textContent, req, 'object'),
|
|
125
131
|
...(toolCalls ? { toolCalls } : {}),
|
|
126
|
-
usage:
|
|
132
|
+
usage: toTokenUsage(response.usage?.prompt_tokens, response.usage?.completion_tokens),
|
|
127
133
|
finishReason: toFinishReason(response.choices[0]?.finish_reason),
|
|
134
|
+
outcome: toOutcome(toFinishReason(response.choices[0]?.finish_reason), response.choices[0]?.finish_reason),
|
|
128
135
|
raw: response
|
|
129
136
|
};
|
|
130
137
|
}
|
|
@@ -133,7 +140,8 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
133
140
|
let partial = '';
|
|
134
141
|
let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
135
142
|
let finishReason = 'stop';
|
|
136
|
-
|
|
143
|
+
let providerFinishReason;
|
|
144
|
+
const toolState = createStreamToolCallState();
|
|
137
145
|
if (this.options.api === 'responses') {
|
|
138
146
|
yield* streamResponsesObject(this.client, req);
|
|
139
147
|
return;
|
|
@@ -142,7 +150,7 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
142
150
|
for await (const chunk of stream) {
|
|
143
151
|
req.signal.throwIfAborted();
|
|
144
152
|
if (chunk.usage) {
|
|
145
|
-
usage =
|
|
153
|
+
usage = toTokenUsage(chunk.usage.prompt_tokens, chunk.usage.completion_tokens);
|
|
146
154
|
}
|
|
147
155
|
const choice = chunk.choices?.[0];
|
|
148
156
|
if (!choice)
|
|
@@ -152,17 +160,18 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
152
160
|
yield { kind: 'partial', partial: safePartialJson(partial) };
|
|
153
161
|
}
|
|
154
162
|
if (choice.delta?.tool_calls) {
|
|
155
|
-
|
|
163
|
+
accumulateStreamToolCallDeltas(toolState, choice.delta.tool_calls);
|
|
156
164
|
}
|
|
157
165
|
if (choice.finish_reason) {
|
|
158
|
-
|
|
166
|
+
providerFinishReason = choice.finish_reason;
|
|
167
|
+
finishReason = toFinishReason(providerFinishReason);
|
|
159
168
|
}
|
|
160
169
|
}
|
|
161
|
-
for (const call of finalizeStreamToolCalls(toolState, req, 'objectStream')) {
|
|
170
|
+
for (const call of finalizeStreamToolCalls(toolState, callContext(req, 'objectStream'), MALFORMED_TOOL_ARGS_MESSAGE)) {
|
|
162
171
|
yield { kind: 'tool_call', call };
|
|
163
172
|
}
|
|
164
173
|
const object = parseJson(partial || '{}', req, 'objectStream');
|
|
165
|
-
yield { kind: 'finish', object, usage, finishReason };
|
|
174
|
+
yield { kind: 'finish', object, usage, finishReason, outcome: toOutcome(finishReason, providerFinishReason) };
|
|
166
175
|
}
|
|
167
176
|
async doEmbed(req) {
|
|
168
177
|
req.signal.throwIfAborted();
|
|
@@ -178,22 +187,25 @@ class OpenAiModelProvider extends BaseModelProvider {
|
|
|
178
187
|
}, { ...requestOptions, signal: req.signal });
|
|
179
188
|
return {
|
|
180
189
|
embeddings: response.data.map((item) => ({ index: item.index, vector: item.embedding })),
|
|
181
|
-
usage:
|
|
190
|
+
usage: toTokenUsage(response.usage?.prompt_tokens, 0),
|
|
182
191
|
raw: response
|
|
183
192
|
};
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
function toClientOptions(options) {
|
|
187
196
|
const { api: _api, client: _client, harnessLogger: _harnessLogger, telemetry: _telemetry, harnessTimeoutMs: _harnessTimeoutMs, ...clientOptions } = options;
|
|
188
|
-
return clientOptions;
|
|
197
|
+
return { maxRetries: 0, ...clientOptions };
|
|
189
198
|
}
|
|
190
199
|
function mapChatTextResponse(response, req) {
|
|
191
200
|
const toolCalls = extractChatToolCalls(response, req, 'text');
|
|
201
|
+
const providerFinishReason = response.choices[0]?.finish_reason;
|
|
202
|
+
const finishReason = toFinishReason(providerFinishReason);
|
|
192
203
|
return {
|
|
193
204
|
content: response.choices[0]?.message?.content ?? '',
|
|
194
205
|
...(toolCalls ? { toolCalls } : {}),
|
|
195
|
-
usage:
|
|
196
|
-
finishReason
|
|
206
|
+
usage: toTokenUsage(response.usage?.prompt_tokens, response.usage?.completion_tokens),
|
|
207
|
+
finishReason,
|
|
208
|
+
outcome: toOutcome(finishReason, providerFinishReason),
|
|
197
209
|
raw: response
|
|
198
210
|
};
|
|
199
211
|
}
|
|
@@ -463,6 +475,7 @@ function mapResponsesTextResponse(response, req) {
|
|
|
463
475
|
...(providerItems ? { providerItems } : {}),
|
|
464
476
|
usage: toResponsesUsage(response.usage),
|
|
465
477
|
finishReason: toResponsesFinishReason(response),
|
|
478
|
+
outcome: toResponsesOutcome(response),
|
|
466
479
|
raw: response
|
|
467
480
|
};
|
|
468
481
|
}
|
|
@@ -484,6 +497,7 @@ async function* streamResponsesText(client, req) {
|
|
|
484
497
|
const stream = await createResponse(client, req, true);
|
|
485
498
|
let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
486
499
|
let finishReason = 'stop';
|
|
500
|
+
let outcome = toOutcome('stop');
|
|
487
501
|
let completedOutput;
|
|
488
502
|
const toolState = new Map();
|
|
489
503
|
for await (const event of stream) {
|
|
@@ -503,10 +517,18 @@ async function* streamResponsesText(client, req) {
|
|
|
503
517
|
else if (event.type === 'response.completed') {
|
|
504
518
|
usage = toResponsesUsage(event.response?.usage);
|
|
505
519
|
finishReason = toResponsesFinishReason(event.response);
|
|
520
|
+
outcome = toResponsesOutcome(event.response);
|
|
506
521
|
completedOutput = event.response?.output;
|
|
507
522
|
}
|
|
508
|
-
else if (event.type === 'response.failed'
|
|
509
|
-
|
|
523
|
+
else if (event.type === 'response.failed') {
|
|
524
|
+
// A genuine provider failure must surface as an error so base retry and
|
|
525
|
+
// normalization apply, matching the chat-completions path.
|
|
526
|
+
throw responsesFailureError(event.response, req, 'textStream');
|
|
527
|
+
}
|
|
528
|
+
else if (event.type === 'response.incomplete') {
|
|
529
|
+
usage = toResponsesUsage(event.response?.usage);
|
|
530
|
+
finishReason = toResponsesFinishReason(event.response);
|
|
531
|
+
outcome = toResponsesOutcome(event.response);
|
|
510
532
|
}
|
|
511
533
|
}
|
|
512
534
|
const toolCalls = finalizeResponsesStreamToolCalls(toolState, req, 'textStream');
|
|
@@ -514,13 +536,14 @@ async function* streamResponsesText(client, req) {
|
|
|
514
536
|
yield { kind: 'tool_call', call };
|
|
515
537
|
}
|
|
516
538
|
const providerItems = toResponsesProviderItems(completedOutput, toolCalls);
|
|
517
|
-
yield { kind: 'finish', usage, finishReason, ...(providerItems ? { providerItems } : {}) };
|
|
539
|
+
yield { kind: 'finish', usage, finishReason, outcome, ...(providerItems ? { providerItems } : {}) };
|
|
518
540
|
}
|
|
519
541
|
async function* streamResponsesObject(client, req) {
|
|
520
542
|
const stream = await createResponse(client, req, true);
|
|
521
543
|
let partial = '';
|
|
522
544
|
let usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
|
|
523
545
|
let finishReason = 'stop';
|
|
546
|
+
let outcome = toOutcome('stop');
|
|
524
547
|
let completedOutput;
|
|
525
548
|
const toolState = new Map();
|
|
526
549
|
for await (const event of stream) {
|
|
@@ -541,10 +564,18 @@ async function* streamResponsesObject(client, req) {
|
|
|
541
564
|
else if (event.type === 'response.completed') {
|
|
542
565
|
usage = toResponsesUsage(event.response?.usage);
|
|
543
566
|
finishReason = toResponsesFinishReason(event.response);
|
|
567
|
+
outcome = toResponsesOutcome(event.response);
|
|
544
568
|
completedOutput = event.response?.output;
|
|
545
569
|
}
|
|
546
|
-
else if (event.type === 'response.failed'
|
|
547
|
-
|
|
570
|
+
else if (event.type === 'response.failed') {
|
|
571
|
+
// A genuine provider failure must surface as an error so base retry and
|
|
572
|
+
// normalization apply, matching the chat-completions path.
|
|
573
|
+
throw responsesFailureError(event.response, req, 'objectStream');
|
|
574
|
+
}
|
|
575
|
+
else if (event.type === 'response.incomplete') {
|
|
576
|
+
usage = toResponsesUsage(event.response?.usage);
|
|
577
|
+
finishReason = toResponsesFinishReason(event.response);
|
|
578
|
+
outcome = toResponsesOutcome(event.response);
|
|
548
579
|
}
|
|
549
580
|
}
|
|
550
581
|
const toolCalls = finalizeResponsesStreamToolCalls(toolState, req, 'objectStream');
|
|
@@ -553,7 +584,7 @@ async function* streamResponsesObject(client, req) {
|
|
|
553
584
|
}
|
|
554
585
|
const object = parseJson(partial || '{}', req, 'objectStream');
|
|
555
586
|
const providerItems = toResponsesProviderItems(completedOutput, toolCalls);
|
|
556
|
-
yield { kind: 'finish', object, usage, finishReason, ...(providerItems ? { providerItems } : {}) };
|
|
587
|
+
yield { kind: 'finish', object, usage, finishReason, outcome, ...(providerItems ? { providerItems } : {}) };
|
|
557
588
|
}
|
|
558
589
|
function extractResponsesText(response) {
|
|
559
590
|
if (typeof response.output_text === 'string')
|
|
@@ -618,7 +649,7 @@ function finalizeResponsesStreamToolCalls(state, req, method) {
|
|
|
618
649
|
.filter(([, call]) => call.name)
|
|
619
650
|
.map(([, call]) => {
|
|
620
651
|
if (!call.id) {
|
|
621
|
-
throw malformedResponseError(req, method, 'OpenAI streamed a function call without a call_id.', call, undefined);
|
|
652
|
+
throw malformedResponseError(callContext(req, method), 'OpenAI streamed a function call without a call_id.', call, undefined);
|
|
622
653
|
}
|
|
623
654
|
return {
|
|
624
655
|
id: call.id,
|
|
@@ -627,75 +658,46 @@ function finalizeResponsesStreamToolCalls(state, req, method) {
|
|
|
627
658
|
};
|
|
628
659
|
});
|
|
629
660
|
}
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if (delta?.id)
|
|
635
|
-
existing.id = String(delta.id);
|
|
636
|
-
if (delta?.function?.name)
|
|
637
|
-
existing.name = String(delta.function.name);
|
|
638
|
-
if (typeof delta?.function?.arguments === 'string')
|
|
639
|
-
existing.args += delta.function.arguments;
|
|
640
|
-
state.set(index, existing);
|
|
641
|
-
}
|
|
661
|
+
const MALFORMED_TOOL_ARGS_MESSAGE = 'OpenAI returned malformed tool-call argument JSON.';
|
|
662
|
+
const MALFORMED_OBJECT_MESSAGE = 'OpenAI returned malformed structured object JSON.';
|
|
663
|
+
function callContext(req, method) {
|
|
664
|
+
return { provider: 'openai', model: req.model, method };
|
|
642
665
|
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
.map(([, call]) => ({
|
|
648
|
-
id: call.id,
|
|
649
|
-
name: call.name,
|
|
650
|
-
arguments: parseToolArgs(call.args || undefined, req, method)
|
|
651
|
-
}));
|
|
652
|
-
}
|
|
653
|
-
function parseToolArgs(argumentsText, req, method) {
|
|
654
|
-
if (!argumentsText)
|
|
655
|
-
return {};
|
|
656
|
-
try {
|
|
657
|
-
return JSON.parse(argumentsText);
|
|
658
|
-
}
|
|
659
|
-
catch (error) {
|
|
660
|
-
throw malformedResponseError(req, method, 'OpenAI returned malformed tool-call argument JSON.', argumentsText, error);
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
function parseJson(content, req, method) {
|
|
664
|
-
try {
|
|
665
|
-
return JSON.parse(content);
|
|
666
|
-
}
|
|
667
|
-
catch (error) {
|
|
668
|
-
throw malformedResponseError(req, method, 'OpenAI returned malformed structured object JSON.', content, error);
|
|
666
|
+
/** Throws when a non-streaming Responses result reports a provider failure. */
|
|
667
|
+
function throwIfResponsesFailure(response, req, method) {
|
|
668
|
+
if (response?.status === 'failed' || response?.error) {
|
|
669
|
+
throw responsesFailureError(response, req, method);
|
|
669
670
|
}
|
|
670
671
|
}
|
|
671
|
-
|
|
672
|
-
|
|
672
|
+
/**
|
|
673
|
+
* Maps a failed Responses-API result into a `ModelError` so the base
|
|
674
|
+
* provider's retry classification and normalization apply.
|
|
675
|
+
*/
|
|
676
|
+
function responsesFailureError(response, req, method) {
|
|
677
|
+
const providerCode = typeof response?.error?.code === 'string' ? response.error.code : undefined;
|
|
678
|
+
const rawMessage = typeof response?.error?.message === 'string' ? response.error.message : undefined;
|
|
679
|
+
const reason = providerCode === 'rate_limit_exceeded'
|
|
680
|
+
? 'rate_limited'
|
|
681
|
+
: providerCode === 'server_error'
|
|
682
|
+
? 'provider_unavailable'
|
|
683
|
+
: 'http_error';
|
|
684
|
+
return new ModelError('OpenAI reported a failed response.', {
|
|
673
685
|
provider: 'openai',
|
|
674
686
|
model: req.model,
|
|
675
687
|
method,
|
|
676
|
-
reason
|
|
677
|
-
|
|
678
|
-
|
|
688
|
+
reason,
|
|
689
|
+
...(providerCode ? { providerCode } : {}),
|
|
690
|
+
...(rawMessage ? { providerMessage: sanitizeProviderMessage(rawMessage) } : {})
|
|
691
|
+
});
|
|
679
692
|
}
|
|
680
|
-
function
|
|
681
|
-
|
|
682
|
-
return JSON.parse(content);
|
|
683
|
-
}
|
|
684
|
-
catch {
|
|
685
|
-
return { _partial: content };
|
|
686
|
-
}
|
|
693
|
+
function parseToolArgs(argumentsText, req, method) {
|
|
694
|
+
return parseProviderJson(argumentsText || '{}', callContext(req, method), MALFORMED_TOOL_ARGS_MESSAGE);
|
|
687
695
|
}
|
|
688
|
-
function
|
|
689
|
-
|
|
690
|
-
const output = outputTokens ?? 0;
|
|
691
|
-
return {
|
|
692
|
-
inputTokens: input,
|
|
693
|
-
outputTokens: output,
|
|
694
|
-
totalTokens: input + output
|
|
695
|
-
};
|
|
696
|
+
function parseJson(content, req, method) {
|
|
697
|
+
return parseProviderJson(content, callContext(req, method), MALFORMED_OBJECT_MESSAGE);
|
|
696
698
|
}
|
|
697
699
|
function toResponsesUsage(usage) {
|
|
698
|
-
return
|
|
700
|
+
return toTokenUsage(usage?.input_tokens, usage?.output_tokens);
|
|
699
701
|
}
|
|
700
702
|
function toFinishReason(value) {
|
|
701
703
|
switch (value) {
|
|
@@ -704,6 +706,8 @@ function toFinishReason(value) {
|
|
|
704
706
|
case 'tool_calls':
|
|
705
707
|
case 'content_filter':
|
|
706
708
|
return value;
|
|
709
|
+
case 'function_call':
|
|
710
|
+
return 'tool_calls';
|
|
707
711
|
default:
|
|
708
712
|
return 'error';
|
|
709
713
|
}
|
|
@@ -713,6 +717,11 @@ function toResponsesFinishReason(response) {
|
|
|
713
717
|
return 'error';
|
|
714
718
|
if ((response.output ?? []).some((item) => item?.type === 'function_call'))
|
|
715
719
|
return 'tool_calls';
|
|
720
|
+
const incompleteReason = response.incomplete_details?.reason;
|
|
721
|
+
if (incompleteReason === 'max_output_tokens')
|
|
722
|
+
return 'length';
|
|
723
|
+
if (incompleteReason === 'content_filter')
|
|
724
|
+
return 'content_filter';
|
|
716
725
|
switch (response.status) {
|
|
717
726
|
case 'completed':
|
|
718
727
|
return 'stop';
|
|
@@ -722,3 +731,24 @@ function toResponsesFinishReason(response) {
|
|
|
722
731
|
return response.error ? 'error' : 'stop';
|
|
723
732
|
}
|
|
724
733
|
}
|
|
734
|
+
function toOutcome(finishReason, providerFinishReason, details) {
|
|
735
|
+
return {
|
|
736
|
+
finishReason,
|
|
737
|
+
...(typeof providerFinishReason === 'string' ? { providerFinishReason } : {}),
|
|
738
|
+
...(details ? { details } : {})
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
function toResponsesOutcome(response) {
|
|
742
|
+
const finishReason = toResponsesFinishReason(response);
|
|
743
|
+
const details = response?.incomplete_details || response?.error
|
|
744
|
+
? {
|
|
745
|
+
...(response.incomplete_details ? { incompleteDetails: response.incomplete_details } : {}),
|
|
746
|
+
...(response.error ? { error: response.error } : {})
|
|
747
|
+
}
|
|
748
|
+
: undefined;
|
|
749
|
+
return {
|
|
750
|
+
finishReason,
|
|
751
|
+
...(typeof response?.status === 'string' ? { providerStatus: response.status, providerFinishReason: response.status } : {}),
|
|
752
|
+
...(details ? { details } : {})
|
|
753
|
+
};
|
|
754
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@purista/harness-openai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "OpenAI model provider adapter for @purista/harness.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"vitest": "^4.1.8"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"@purista/harness": "
|
|
51
|
+
"@purista/harness": "^1.5.0"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=24.15.0"
|