zk-credits 0.2.0 → 0.2.2

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/sidecar.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { codexModelsResponse } from './codex-profile.js';
3
+ import { responsesEventStream, translateResponsesRequest } from './responses-bridge.js';
3
4
  import { PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, } from '@zk-credits/x402-zk-prepaid';
4
5
  const MAX_REQUEST_BYTES = 2_000_000;
5
6
  const PAYMENT_HEADERS = [PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, 'cache-control'];
@@ -81,6 +82,32 @@ async function relayGatewayResponse(res, upstream) {
81
82
  reader.releaseLock();
82
83
  }
83
84
  }
85
+ async function relayResponsesGatewayResponse(res, upstream, responseModel) {
86
+ if (upstream.status < 200 || upstream.status >= 300) {
87
+ await relayGatewayResponse(res, upstream);
88
+ return;
89
+ }
90
+ const upstreamText = await upstream.text();
91
+ let completion;
92
+ try {
93
+ completion = JSON.parse(upstreamText);
94
+ }
95
+ catch {
96
+ throw new Error('Gateway returned an invalid chat completion');
97
+ }
98
+ const eventStream = responsesEventStream(completion, responseModel);
99
+ const headers = {
100
+ 'Content-Type': 'text/event-stream; charset=utf-8',
101
+ 'Cache-Control': 'no-cache',
102
+ };
103
+ for (const name of PAYMENT_HEADERS) {
104
+ const value = upstream.headers.get(name);
105
+ if (value)
106
+ headers[name] = value;
107
+ }
108
+ res.writeHead(upstream.status, headers);
109
+ res.end(eventStream);
110
+ }
84
111
  /** Creates a loopback-only proxy whose sole spend path is x402 zk-prepaid. */
85
112
  export function createSidecarServer(options) {
86
113
  const gatewayBaseUrl = options.gatewayBaseUrl.replace(/\/$/u, '');
@@ -117,7 +144,7 @@ export function createSidecarServer(options) {
117
144
  sendJson(res, 200, options.metrics());
118
145
  return;
119
146
  }
120
- if (req.method !== 'POST' || pathname !== '/v1/chat/completions') {
147
+ if (req.method !== 'POST' || (pathname !== '/v1/chat/completions' && pathname !== '/v1/responses')) {
121
148
  sendJson(res, 404, { error: 'unsupported_openai_path' });
122
149
  return;
123
150
  }
@@ -127,17 +154,34 @@ export function createSidecarServer(options) {
127
154
  }
128
155
  try {
129
156
  const body = await readJsonBody(req);
130
- const rejection = completionRejection(body.parsed);
131
- if (rejection) {
132
- sendJson(res, 400, { error: rejection });
133
- return;
157
+ const isResponses = pathname === '/v1/responses';
158
+ let outboundBody = body.raw;
159
+ let responseModel = '';
160
+ if (isResponses) {
161
+ const translation = translateResponsesRequest(body.parsed);
162
+ if (!translation.ok) {
163
+ sendJson(res, 400, { error: translation.error });
164
+ return;
165
+ }
166
+ outboundBody = JSON.stringify(translation.chatRequest);
167
+ responseModel = translation.responseModel;
168
+ }
169
+ else {
170
+ const rejection = completionRejection(body.parsed);
171
+ if (rejection) {
172
+ sendJson(res, 400, { error: rejection });
173
+ return;
174
+ }
134
175
  }
135
- const upstream = await options.prepaidClient.fetch(`${gatewayBaseUrl}${pathname}`, {
176
+ const upstream = await options.prepaidClient.fetch(`${gatewayBaseUrl}/v1/chat/completions`, {
136
177
  method: 'POST',
137
178
  headers: { 'Content-Type': 'application/json' },
138
- body: body.raw,
179
+ body: outboundBody,
139
180
  });
140
- await relayGatewayResponse(res, upstream);
181
+ if (isResponses)
182
+ await relayResponsesGatewayResponse(res, upstream, responseModel);
183
+ else
184
+ await relayGatewayResponse(res, upstream);
141
185
  }
142
186
  catch (error) {
143
187
  if (!res.headersSent) {