@usewind/node 0.1.0 → 0.1.1
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/DESIGN.md +1 -1
- package/README.md +1 -1
- package/dist/index.cjs +56 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +37 -3
- package/dist/index.d.ts +37 -3
- package/dist/index.js +56 -7
- package/dist/index.js.map +1 -1
- package/package.json +9 -9
package/dist/index.d.ts
CHANGED
|
@@ -17,6 +17,21 @@ interface ChatMessage {
|
|
|
17
17
|
content: unknown;
|
|
18
18
|
[k: string]: unknown;
|
|
19
19
|
}
|
|
20
|
+
/** OpenAI-style function tool. Wind maps it onto Anthropic and Gemini for you. */
|
|
21
|
+
interface ChatTool {
|
|
22
|
+
type: 'function';
|
|
23
|
+
function: {
|
|
24
|
+
name: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
parameters?: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
type ChatToolChoice = 'auto' | 'none' | 'required' | {
|
|
30
|
+
type: 'function';
|
|
31
|
+
function: {
|
|
32
|
+
name: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
20
35
|
/** Present on every successful `POST /v1/ai/*` response. */
|
|
21
36
|
interface WindBlock {
|
|
22
37
|
feature: string | null;
|
|
@@ -49,6 +64,14 @@ interface ChatParams {
|
|
|
49
64
|
/** Optional — hold cap resolves request → feature → app default → model ceiling. */
|
|
50
65
|
max_tokens?: number;
|
|
51
66
|
temperature?: number;
|
|
67
|
+
/**
|
|
68
|
+
* Function tools, OpenAI format, for every provider. Send the assistant
|
|
69
|
+
* message back unchanged (including any `extra_content` on its tool calls —
|
|
70
|
+
* Gemini needs it), then one `{ role: 'tool', tool_call_id, content }` per call.
|
|
71
|
+
*/
|
|
72
|
+
tools?: ChatTool[];
|
|
73
|
+
tool_choice?: ChatToolChoice;
|
|
74
|
+
parallel_tool_calls?: boolean;
|
|
52
75
|
/** Prefer `.chatStream()` over setting this directly. */
|
|
53
76
|
stream?: boolean;
|
|
54
77
|
/** Defaults to `crypto.randomUUID()`; the same value is reused for every internal retry. */
|
|
@@ -56,10 +79,15 @@ interface ChatParams {
|
|
|
56
79
|
signal?: AbortSignal;
|
|
57
80
|
}
|
|
58
81
|
interface ChatStreamChunk {
|
|
59
|
-
/**
|
|
82
|
+
/**
|
|
83
|
+
* One provider chunk, OpenAI shape (`choices[0].delta.content` /
|
|
84
|
+
* `.tool_calls`), JSON-parsed. `null` on the final, settlement-only chunk.
|
|
85
|
+
*/
|
|
60
86
|
delta: unknown;
|
|
61
87
|
/** The final chunk of a stream carries the settled `wind` block; `null` on all others. */
|
|
62
88
|
wind: WindBlock | null;
|
|
89
|
+
/** Final token counts — on the final chunk only. */
|
|
90
|
+
usage?: ChatUsage;
|
|
63
91
|
}
|
|
64
92
|
/** 'frozen' — Wind's own risk layer, independent of anything you or the user configured; clears when the user reconnects. */
|
|
65
93
|
type ConnectionStatus = 'active' | 'exhausted' | 'revoked' | 'frozen';
|
|
@@ -213,6 +241,12 @@ interface RawRequest {
|
|
|
213
241
|
/** Use HTTP Basic client credentials for `Authorization`. */
|
|
214
242
|
basic?: boolean;
|
|
215
243
|
signal?: AbortSignal;
|
|
244
|
+
/**
|
|
245
|
+
* When the response is a 2xx `text/event-stream`, return its unread
|
|
246
|
+
* `ReadableStream` as `body` instead of buffering it — `.chatStream()`
|
|
247
|
+
* parses the SSE events as they arrive.
|
|
248
|
+
*/
|
|
249
|
+
stream?: boolean;
|
|
216
250
|
}
|
|
217
251
|
interface RawResponse<T = unknown> {
|
|
218
252
|
status: number;
|
|
@@ -592,7 +626,7 @@ declare class Wind {
|
|
|
592
626
|
register: (appId: string, feature: Feature) => Promise<Feature>;
|
|
593
627
|
update: (appId: string, slug: string, patch: Partial<Feature>) => Promise<Feature>;
|
|
594
628
|
};
|
|
595
|
-
/** Verify a webhook's `
|
|
629
|
+
/** Verify a webhook's `Wind-Signature` and return the typed event. Needs the raw body. */
|
|
596
630
|
verify(input: {
|
|
597
631
|
payload: string | Buffer;
|
|
598
632
|
signature: string;
|
|
@@ -606,4 +640,4 @@ declare function createWind(config?: Partial<WindConfig>): Wind;
|
|
|
606
640
|
*/
|
|
607
641
|
declare const wind: Wind;
|
|
608
642
|
|
|
609
|
-
export { type Account, AllocationExhaustedError, type AllocationRequest, type AllocationRequestParams, AppSuspendedError, type ChatMessage, type ChatParams, type ChatResult, type ChatStreamChunk, type ChatUsage, type Chattable, type ConnectTransaction, type Connection, ConnectionFrozenError, ConnectionRevokedError, ConnectionScope, type ConnectionStatus, type Feature, FeatureCostExceededError, FeatureModelNotConfiguredError, FeatureScope, type Grant, type GrantStore, IdempotencyKeyReusedError, ModelNotAllowedError, ProviderError, RateLimitedError, type RevokeResult, RiskThrottledError, type RoutesOptions, TokenExpiredError, type TokenResponse, type TransactionStore, type WebhookEvent, Wind, WindApiError, type WindBlock, type WindConfig, WindConfigError, WindError, type WindErrorEnvelope, type WindErrorInit, WindNotConnectedError, WindNotImplementedError, WindSignatureError, createWind, memoryGrantStore, wind };
|
|
643
|
+
export { type Account, AllocationExhaustedError, type AllocationRequest, type AllocationRequestParams, AppSuspendedError, type ChatMessage, type ChatParams, type ChatResult, type ChatStreamChunk, type ChatTool, type ChatToolChoice, type ChatUsage, type Chattable, type ConnectTransaction, type Connection, ConnectionFrozenError, ConnectionRevokedError, ConnectionScope, type ConnectionStatus, type Feature, FeatureCostExceededError, FeatureModelNotConfiguredError, FeatureScope, type Grant, type GrantStore, IdempotencyKeyReusedError, ModelNotAllowedError, ProviderError, RateLimitedError, type RevokeResult, RiskThrottledError, type RoutesOptions, TokenExpiredError, type TokenResponse, type TransactionStore, type WebhookEvent, Wind, WindApiError, type WindBlock, type WindConfig, WindConfigError, WindError, type WindErrorEnvelope, type WindErrorInit, WindNotConnectedError, WindNotImplementedError, WindSignatureError, createWind, memoryGrantStore, wind };
|
package/dist/index.js
CHANGED
|
@@ -234,6 +234,9 @@ var RawClient = class {
|
|
|
234
234
|
signal: req.signal
|
|
235
235
|
});
|
|
236
236
|
const requestId = res.headers.get("x-request-id");
|
|
237
|
+
if (req.stream && res.ok && res.body && (res.headers.get("content-type") ?? "").includes("text/event-stream")) {
|
|
238
|
+
return { status: res.status, headers: res.headers, body: res.body, requestId };
|
|
239
|
+
}
|
|
237
240
|
let parsed = void 0;
|
|
238
241
|
const text = await res.text();
|
|
239
242
|
if (text) {
|
|
@@ -288,7 +291,8 @@ var RawClient = class {
|
|
|
288
291
|
bearer: args.accessToken,
|
|
289
292
|
headers,
|
|
290
293
|
body: args.body,
|
|
291
|
-
signal: args.signal
|
|
294
|
+
signal: args.signal,
|
|
295
|
+
stream: isStreamBody(args.body)
|
|
292
296
|
});
|
|
293
297
|
}
|
|
294
298
|
/** `POST /v1/ai/features/{slug}`. */
|
|
@@ -299,7 +303,8 @@ var RawClient = class {
|
|
|
299
303
|
bearer: args.accessToken,
|
|
300
304
|
headers: { "Idempotency-Key": args.idempotencyKey },
|
|
301
305
|
body: args.body,
|
|
302
|
-
signal: args.signal
|
|
306
|
+
signal: args.signal,
|
|
307
|
+
stream: isStreamBody(args.body)
|
|
303
308
|
});
|
|
304
309
|
}
|
|
305
310
|
// ── Management (client-credentials) ────────────────────────────────────────
|
|
@@ -362,6 +367,9 @@ var RawClient = class {
|
|
|
362
367
|
return this.request({ method: "POST", path, ...init });
|
|
363
368
|
}
|
|
364
369
|
};
|
|
370
|
+
function isStreamBody(body) {
|
|
371
|
+
return typeof body === "object" && body !== null && body.stream === true;
|
|
372
|
+
}
|
|
365
373
|
|
|
366
374
|
// src/tokens.ts
|
|
367
375
|
var ACCESS_TOKEN_SKEW_MS = 6e4;
|
|
@@ -620,6 +628,9 @@ function requestBody(params) {
|
|
|
620
628
|
messages: params.messages,
|
|
621
629
|
...params.max_tokens !== void 0 && { max_tokens: params.max_tokens },
|
|
622
630
|
...params.temperature !== void 0 && { temperature: params.temperature },
|
|
631
|
+
...params.tools !== void 0 && { tools: params.tools },
|
|
632
|
+
...params.tool_choice !== void 0 && { tool_choice: params.tool_choice },
|
|
633
|
+
...params.parallel_tool_calls !== void 0 && { parallel_tool_calls: params.parallel_tool_calls },
|
|
623
634
|
...params.stream !== void 0 && { stream: params.stream }
|
|
624
635
|
};
|
|
625
636
|
}
|
|
@@ -666,13 +677,51 @@ async function* billedStream(ctx, userId, params, call) {
|
|
|
666
677
|
if (res.status < 200 || res.status >= 300) {
|
|
667
678
|
throw WindError.fromResponse(res.status, res.body, { requestId: res.requestId });
|
|
668
679
|
}
|
|
669
|
-
|
|
670
|
-
if (!contentType.includes("text/event-stream")) {
|
|
680
|
+
if (!(res.body instanceof ReadableStream)) {
|
|
671
681
|
const result = res.body;
|
|
672
|
-
yield { delta: result, wind: result.wind };
|
|
682
|
+
yield { delta: result, wind: result.wind ?? null, usage: result.usage };
|
|
673
683
|
return;
|
|
674
684
|
}
|
|
675
|
-
|
|
685
|
+
for await (const event of sseEvents(res.body)) {
|
|
686
|
+
if (event === "[DONE]") return;
|
|
687
|
+
let data;
|
|
688
|
+
try {
|
|
689
|
+
data = JSON.parse(event);
|
|
690
|
+
} catch {
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
if (data?.wind_final) {
|
|
694
|
+
yield { delta: null, wind: data.wind_final.wind ?? null, usage: data.wind_final.usage };
|
|
695
|
+
} else if (data?.error) {
|
|
696
|
+
const err = data.error.error ?? data.error;
|
|
697
|
+
const status = err.code === "provider_error" ? 502 : 403;
|
|
698
|
+
throw WindError.fromResponse(status, { error: err }, { requestId: res.requestId });
|
|
699
|
+
} else if (data?.streamed && data.wind) {
|
|
700
|
+
yield { delta: null, wind: data.wind, usage: data.usage };
|
|
701
|
+
} else {
|
|
702
|
+
yield { delta: data, wind: null };
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
async function* sseEvents(stream) {
|
|
707
|
+
const reader = stream.getReader();
|
|
708
|
+
const decoder = new TextDecoder();
|
|
709
|
+
let buffer = "";
|
|
710
|
+
try {
|
|
711
|
+
while (true) {
|
|
712
|
+
const { done, value } = await reader.read();
|
|
713
|
+
if (done) break;
|
|
714
|
+
buffer += decoder.decode(value, { stream: true });
|
|
715
|
+
const lines = buffer.split("\n");
|
|
716
|
+
buffer = lines.pop() ?? "";
|
|
717
|
+
for (const line of lines) {
|
|
718
|
+
if (line.startsWith("data:")) yield line.slice(5).trim();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (buffer.startsWith("data:")) yield buffer.slice(5).trim();
|
|
722
|
+
} finally {
|
|
723
|
+
reader.releaseLock();
|
|
724
|
+
}
|
|
676
725
|
}
|
|
677
726
|
var TOLERANCE_S = 300;
|
|
678
727
|
var WebhookVerifier = class {
|
|
@@ -995,7 +1044,7 @@ var Wind = class {
|
|
|
995
1044
|
update: (appId, slug, patch) => this.raw.updateFeature(appId, slug, patch)
|
|
996
1045
|
};
|
|
997
1046
|
// ── webhooks ─────────────────────────────────────────────────────────────
|
|
998
|
-
/** Verify a webhook's `
|
|
1047
|
+
/** Verify a webhook's `Wind-Signature` and return the typed event. Needs the raw body. */
|
|
999
1048
|
verify(input) {
|
|
1000
1049
|
return this.#verifier.verify(input);
|
|
1001
1050
|
}
|