@lionhummer/constellation 0.9.0 → 0.9.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/README.md +6 -5
- package/dist/index.js +13 -4
- package/dist/types/client-core/src/index.d.ts +2 -0
- package/dist/types/sdk/src/index.d.ts +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -273,13 +273,13 @@ async function handle(event: WebhookEvent) {
|
|
|
273
273
|
}
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
//
|
|
277
|
-
|
|
278
|
-
for (const event of await store.pending()) await handle(event);
|
|
279
|
-
}, 60_000);
|
|
276
|
+
// Optional: resume unfinished events right after a restart.
|
|
277
|
+
for (const event of await store.pending()) void handle(event);
|
|
280
278
|
```
|
|
281
279
|
|
|
282
|
-
|
|
280
|
+
Don't run tools inside the webhook call. Constellation waits 5 seconds for the acknowledgement by default, and nothing in Constellation waits for your tools.
|
|
281
|
+
|
|
282
|
+
If your process dies while handling an event, you don't need a poller to recover it. Constellation sends an unanswered `model.completed` event again after the response window (10 minutes by default), up to 3 times, and stops as soon as your response arrives. A re-sent event has the same `id`, so `store.accept` and `store.prepare` resume it from your saved checkpoint. If the event is still being processed when the re-send arrives, acknowledge it anyway. Keep your processing lease shorter than the response window and renew it while work continues, so a re-send after a crash can take the event over.
|
|
283
283
|
|
|
284
284
|
## What `processEvent` does
|
|
285
285
|
|
|
@@ -348,6 +348,7 @@ The SDK records `client.processing` and one span per tool automatically. A respo
|
|
|
348
348
|
| Setting | Default | Notes |
|
|
349
349
|
| --- | --- | --- |
|
|
350
350
|
| `timeoutMs` | 30 minutes | Deadline for the whole request, including your processing between steps. |
|
|
351
|
+
| `compressRequests` client option | `true` | Request bodies of 16 KiB or more are sent gzip-compressed. Every step resends the full conversation, so this cuts upload time several-fold. |
|
|
351
352
|
| `attemptTimeoutMs`, `firstByteTimeoutMs`, `idleTimeoutMs` | not set | Optional per-provider-call limits. Operators also run stall watchdogs: by default 120 s to the first response byte and 300 s with no data. Keepalives count as data. |
|
|
352
353
|
| `maxProviderAttempts` | 32 | Provider attempts per step, including fallbacks (1–256). |
|
|
353
354
|
| `toolConcurrency` hook option | 8 | Parallel tool calls per event (1–128). |
|
package/dist/index.js
CHANGED
|
@@ -102,6 +102,15 @@ async function pause(ms, signal) {
|
|
|
102
102
|
signal?.addEventListener("abort", abort, { once: true });
|
|
103
103
|
});
|
|
104
104
|
}
|
|
105
|
+
var COMPRESS_FROM_BYTES = 16 * 1024;
|
|
106
|
+
async function encodeBody(body, compress) {
|
|
107
|
+
const json = JSON.stringify(body);
|
|
108
|
+
if (!compress || json.length < COMPRESS_FROM_BYTES || typeof CompressionStream === "undefined") {
|
|
109
|
+
return { body: json, headers: { "Content-Type": "application/json" } };
|
|
110
|
+
}
|
|
111
|
+
const gzipped = await new Response(new Blob([json]).stream().pipeThrough(new CompressionStream("gzip"))).arrayBuffer();
|
|
112
|
+
return { body: gzipped, headers: { "Content-Type": "application/json", "Content-Encoding": "gzip" } };
|
|
113
|
+
}
|
|
105
114
|
|
|
106
115
|
class RequestClient {
|
|
107
116
|
#fetcher;
|
|
@@ -115,12 +124,11 @@ class RequestClient {
|
|
|
115
124
|
return `${this.#options.baseUrl.replace(/\/$/, "")}${route}`;
|
|
116
125
|
}
|
|
117
126
|
async#call(path, method = "GET", body, signal) {
|
|
127
|
+
const encoded = body === undefined ? undefined : await encodeBody(body, this.#options.compressRequests ?? true);
|
|
118
128
|
const response = await this.#fetcher(this.#url(path), {
|
|
119
129
|
method,
|
|
120
|
-
headers: {
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
body: body === undefined ? undefined : JSON.stringify(body),
|
|
130
|
+
headers: encoded?.headers ?? {},
|
|
131
|
+
body: encoded?.body,
|
|
124
132
|
signal: signal ? AbortSignal.any([
|
|
125
133
|
signal,
|
|
126
134
|
AbortSignal.timeout(this.#options.timeoutMs ?? 30000)
|
|
@@ -637,6 +645,7 @@ class Constellation extends RequestClient {
|
|
|
637
645
|
super({
|
|
638
646
|
baseUrl: options.baseUrl,
|
|
639
647
|
timeoutMs: options.timeoutMs,
|
|
648
|
+
compressRequests: options.compressRequests,
|
|
640
649
|
fetch: authenticatedFetch
|
|
641
650
|
});
|
|
642
651
|
this.#baseUrl = options.baseUrl.replace(/\/$/, "");
|
|
@@ -492,6 +492,8 @@ type ClientOptions = {
|
|
|
492
492
|
apiPrefix?: "/v1" | "/internal";
|
|
493
493
|
fetch?: typeof fetch;
|
|
494
494
|
timeoutMs?: number;
|
|
495
|
+
/** gzip JSON bodies of at least 16 KiB (default true). */
|
|
496
|
+
compressRequests?: boolean;
|
|
495
497
|
};
|
|
496
498
|
export declare class RequestClient {
|
|
497
499
|
#private;
|
|
@@ -94,6 +94,7 @@ export declare class Constellation extends RequestClient {
|
|
|
94
94
|
apiKey: string;
|
|
95
95
|
fetch?: typeof fetch;
|
|
96
96
|
timeoutMs?: number;
|
|
97
|
+
compressRequests?: boolean;
|
|
97
98
|
});
|
|
98
99
|
/** Discover HTTP operations available to this bearer key. */
|
|
99
100
|
discover(signal?: AbortSignal): Promise<DiscoveryDocument>;
|