@adaptiqai/deepseek-harness 0.2.13 → 0.2.15
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 +8 -8
- package/lib/client.js +4 -4
- package/lib/host.js +409 -254
- package/lib/types/client/MemoryPill.d.ts +11 -1
- package/lib/types/client/SettingsPage.d.ts +1 -1
- package/lib/types/client/pill.d.ts +24 -2
- package/lib/types/host/stream.d.ts +2 -1
- package/package.json +2 -2
package/lib/host.js
CHANGED
|
@@ -124,42 +124,42 @@ function classifyFailure(status, raw, headers, model2, options = {}) {
|
|
|
124
124
|
}
|
|
125
125
|
if (detail.code === "plan_usage_exhausted") {
|
|
126
126
|
const renewsAt = envelope.detail?.renews_at;
|
|
127
|
-
const failure = make(CODES.noLanes, detail.message ?? "Your plan's usage is used up for now.
|
|
127
|
+
const failure = make(CODES.noLanes, detail.message ?? "Your plan's usage is used up for now. Pay per token from your balance in the meantime.", "no-lanes");
|
|
128
128
|
return typeof renewsAt === "number" ? { ...failure, planRenewsAt: renewsAt } : failure;
|
|
129
129
|
}
|
|
130
130
|
if (effective === 402 || detail.code === "rental_paused") {
|
|
131
131
|
const releaseAt = envelope.detail?.release_at;
|
|
132
132
|
const minutes = typeof releaseAt === "number" ? Math.max(1, Math.ceil((releaseAt * 1e3 - Date.now()) / 6e4)) : null;
|
|
133
|
-
const keep = minutes === null ? "to continue" : `within ${minutes} minute${minutes === 1 ? "" : "s"} to keep
|
|
134
|
-
const failure = make(CODES.outOfCredit, `Your balance ran out
|
|
133
|
+
const keep = minutes === null ? "to continue" : `within ${minutes} minute${minutes === 1 ? "" : "s"} to keep your models running`;
|
|
134
|
+
const failure = make(CODES.outOfCredit, `Your balance ran out. Add funds ${keep}.`, "out-of-credit");
|
|
135
135
|
return minutes === null ? failure : { ...failure, minutesLeft: minutes };
|
|
136
136
|
}
|
|
137
137
|
if (effective === 401) {
|
|
138
138
|
return make(CODES.signIn, "Your AdaptiqAI sign-in has expired. Open Settings \u2192 AdaptiqAI and sign in again.", "sign-in");
|
|
139
139
|
}
|
|
140
140
|
if (detail.code === "rental_stopped_unused") {
|
|
141
|
-
return make(CODES.noLanes, "
|
|
141
|
+
return make(CODES.noLanes, "The model stopped after going unused. Get access to start it again.", "no-lanes");
|
|
142
142
|
}
|
|
143
143
|
if (has(detail, "AdaptiqLaneAccessRequired", "inference_entitlement_required", "instance_access_required", "lane_access") || effective === 403 && has(detail, "lane", "entitle", "model access")) {
|
|
144
|
-
return make(CODES.noLanes, "
|
|
144
|
+
return make(CODES.noLanes, "This model isn't in your workspace yet. Get access to continue; you pay per token from your balance.", "no-lanes");
|
|
145
145
|
}
|
|
146
146
|
if (effective === 403) {
|
|
147
147
|
return make(CODES.signIn, "This AdaptiqAI connection isn't allowed to do that. Sign in again from Settings \u2192 AdaptiqAI.", "sign-in");
|
|
148
148
|
}
|
|
149
149
|
if (effective === 429 || has(detail, "AdaptiqLaneQueueTimeout", "InflightLimit", "rate_limit")) {
|
|
150
|
-
return make(CODES.busy,
|
|
150
|
+
return make(CODES.busy, `${name2} is busy. Your request will retry automatically in a moment.`, "busy");
|
|
151
151
|
}
|
|
152
152
|
if (effective === 503 && detail.code !== null && MODEL_OFFLINE_CODES.includes(detail.code)) {
|
|
153
153
|
return make(CODES.server, `${model2 ?? "This model"} is offline right now. It will retry automatically.`, "retrying");
|
|
154
154
|
}
|
|
155
|
-
if (has(detail, "AdaptiqNativePreflightBusy", "session_route_unavailable", "conversation_preparing", "preparing", "upload_capacity_exhausted") || effective === 503 && !has(detail, "offline")) {
|
|
155
|
+
if (has(detail, "AdaptiqNativePreflightBusy", "session_route_unavailable", "conversation_preparing", "preparing", "upload_capacity_exhausted", "AdaptiqMemoryNotReady") || effective === 425 || effective === 503 && !has(detail, "offline")) {
|
|
156
156
|
return make(CODES.preparing, "AdaptiqAI is getting your conversation ready. It will retry automatically.", "preparing");
|
|
157
157
|
}
|
|
158
158
|
if (effective === 409 && has(detail, "AdaptiqNativePreflight", "conversation")) {
|
|
159
159
|
return make(CODES.conversationUnavailable, "This conversation couldn't be opened on AdaptiqAI right now. Try again shortly; your saved memory is unchanged.", null);
|
|
160
160
|
}
|
|
161
161
|
if (effective === 404 && (has(detail, "model", "not_found", "does not exist") || detail.message === null)) {
|
|
162
|
-
return make(CODES.modelNotFound, `${name2} isn't available to your workspace right now. Pick another AdaptiqAI model, or check your
|
|
162
|
+
return make(CODES.modelNotFound, `${name2} isn't available to your workspace right now. Pick another AdaptiqAI model, or check your models in the console.`, "model-unavailable");
|
|
163
163
|
}
|
|
164
164
|
if (effective === 400 || effective === 413 || effective === 422) {
|
|
165
165
|
const said = detail.message !== null ? ` (${detail.message.slice(0, 200)})` : "";
|
|
@@ -373,6 +373,91 @@ function detailMessage(raw) {
|
|
|
373
373
|
}
|
|
374
374
|
return null;
|
|
375
375
|
}
|
|
376
|
+
var EXPIRED = "The sign-in link expired. Start again.";
|
|
377
|
+
async function startDeviceCode(client, request) {
|
|
378
|
+
let response;
|
|
379
|
+
try {
|
|
380
|
+
response = await client.fetch(`${client.apiBase}/v1/cli-auth/device`, {
|
|
381
|
+
method: "POST",
|
|
382
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
383
|
+
body: JSON.stringify({
|
|
384
|
+
client_app: request.app,
|
|
385
|
+
client_name: request.app,
|
|
386
|
+
device_name: request.device,
|
|
387
|
+
client_binding: request.binding,
|
|
388
|
+
...request.tokenLifetime === void 0 ? {} : { token_lifetime: request.tokenLifetime }
|
|
389
|
+
}),
|
|
390
|
+
signal: client.signal === void 0 ? AbortSignal.timeout(2e4) : AbortSignal.any([client.signal, AbortSignal.timeout(2e4)]),
|
|
391
|
+
redirect: "error"
|
|
392
|
+
});
|
|
393
|
+
} catch (error) {
|
|
394
|
+
if (client.signal?.aborted === true)
|
|
395
|
+
throw error;
|
|
396
|
+
throw new Error(UNREACHABLE, { cause: error });
|
|
397
|
+
}
|
|
398
|
+
if (!response.ok) {
|
|
399
|
+
const message = detailMessage(await readJson(response));
|
|
400
|
+
if (response.status >= 500)
|
|
401
|
+
throw new Error("AdaptiqAI isn't answering right now. Try again in a minute.");
|
|
402
|
+
throw new Error(message ?? `AdaptiqAI sign-in could not start (HTTP ${response.status}).`);
|
|
403
|
+
}
|
|
404
|
+
const body = await readJson(response);
|
|
405
|
+
const deviceCode = String(body?.device_code ?? "");
|
|
406
|
+
const userCode = String(body?.user_code ?? "");
|
|
407
|
+
const url = String(body?.verification_uri_complete ?? body?.verification_uri ?? "");
|
|
408
|
+
if (deviceCode === "" || userCode === "" || !/^https?:\/\//u.test(url))
|
|
409
|
+
throw new Error("AdaptiqAI returned an incomplete sign-in.");
|
|
410
|
+
return {
|
|
411
|
+
deviceCode,
|
|
412
|
+
userCode,
|
|
413
|
+
url,
|
|
414
|
+
expiresAt: client.now() + Math.min(DEVICE_TIMEOUT_MS, Math.max(60, Number(body?.expires_in ?? 600)) * 1e3),
|
|
415
|
+
interval: Math.max(1, Number(body?.interval ?? 2)) * 1e3
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
async function pollDeviceCode(client, code, extra = {}) {
|
|
419
|
+
let response;
|
|
420
|
+
try {
|
|
421
|
+
response = await client.fetch(`${client.apiBase}/v1/cli-auth/device/token`, {
|
|
422
|
+
method: "POST",
|
|
423
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
424
|
+
body: JSON.stringify({ ...extra, device_code: code.deviceCode }),
|
|
425
|
+
signal: client.signal === void 0 ? AbortSignal.timeout(2e4) : AbortSignal.any([client.signal, AbortSignal.timeout(2e4)]),
|
|
426
|
+
redirect: "error"
|
|
427
|
+
});
|
|
428
|
+
} catch {
|
|
429
|
+
return { state: "waiting", delayMs: code.interval * 2 };
|
|
430
|
+
}
|
|
431
|
+
if (response.status === 202)
|
|
432
|
+
return { state: "waiting", delayMs: code.interval };
|
|
433
|
+
if (response.status === 429) {
|
|
434
|
+
const retry = Number(response.headers.get("retry-after") ?? 0) * 1e3;
|
|
435
|
+
return { state: "waiting", delayMs: Math.max(code.interval, retry) + 250 };
|
|
436
|
+
}
|
|
437
|
+
if (response.status === 403) {
|
|
438
|
+
const raw = await readJson(response);
|
|
439
|
+
return { state: "denied", message: detailCode(raw) === "access_denied" ? "The connection was declined in the browser." : detailMessage(raw) ?? "The connection was declined." };
|
|
440
|
+
}
|
|
441
|
+
if (response.status === 410 || response.status === 404)
|
|
442
|
+
return { state: "expired", message: EXPIRED };
|
|
443
|
+
if (!response.ok) {
|
|
444
|
+
if (response.status >= 500)
|
|
445
|
+
return { state: "waiting", delayMs: code.interval * 2 };
|
|
446
|
+
return { state: "failed", message: detailMessage(await readJson(response)) ?? `Sign-in failed (HTTP ${response.status}).` };
|
|
447
|
+
}
|
|
448
|
+
const body = await readJson(response);
|
|
449
|
+
const access2 = String(body?.access_token ?? "");
|
|
450
|
+
const refresh = String(body?.refresh_token ?? "");
|
|
451
|
+
if (!access2.startsWith("ak_") || refresh !== "" && !refresh.startsWith("akr_"))
|
|
452
|
+
return { state: "failed", message: "AdaptiqAI returned an invalid credential." };
|
|
453
|
+
return {
|
|
454
|
+
state: "approved",
|
|
455
|
+
access: access2,
|
|
456
|
+
refresh: refresh === "" ? null : refresh,
|
|
457
|
+
expiresIn: Math.max(60, Number(body?.expires_in ?? 3600)),
|
|
458
|
+
workspaceLabel: typeof body?.workspace_label === "string" && body.workspace_label !== "" ? body.workspace_label : "Your workspace"
|
|
459
|
+
};
|
|
460
|
+
}
|
|
376
461
|
var AuthManager = class {
|
|
377
462
|
options;
|
|
378
463
|
fetch;
|
|
@@ -415,6 +500,9 @@ var AuthManager = class {
|
|
|
415
500
|
this.state = phase;
|
|
416
501
|
this.options.onChange?.();
|
|
417
502
|
}
|
|
503
|
+
client(signal) {
|
|
504
|
+
return { apiBase: this.options.apiBase, fetch: this.fetch, now: this.now, signal };
|
|
505
|
+
}
|
|
418
506
|
/** Read the stored state once at startup. */
|
|
419
507
|
async init() {
|
|
420
508
|
const stored = await this.options.store.read();
|
|
@@ -548,39 +636,11 @@ var AuthManager = class {
|
|
|
548
636
|
const clientProof = `${randomUUID()}${randomUUID()}`;
|
|
549
637
|
const binding = createHash("sha256").update(clientProof).digest("hex");
|
|
550
638
|
const app = this.options.appName ?? "DeepSeek Harness";
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
body: JSON.stringify({
|
|
557
|
-
client_app: app,
|
|
558
|
-
client_name: app,
|
|
559
|
-
device_name: deviceLabel(this.options.deviceName ?? hostname()),
|
|
560
|
-
client_binding: binding
|
|
561
|
-
}),
|
|
562
|
-
signal: AbortSignal.any([flow.signal, AbortSignal.timeout(2e4)]),
|
|
563
|
-
redirect: "error"
|
|
564
|
-
});
|
|
565
|
-
} catch (error) {
|
|
566
|
-
if (flow.signal.aborted)
|
|
567
|
-
throw error;
|
|
568
|
-
throw new Error(UNREACHABLE, { cause: error });
|
|
569
|
-
}
|
|
570
|
-
if (!response.ok) {
|
|
571
|
-
const message = detailMessage(await readJson(response));
|
|
572
|
-
if (response.status >= 500)
|
|
573
|
-
throw new Error("AdaptiqAI isn't answering right now. Try again in a minute.");
|
|
574
|
-
throw new Error(message ?? `AdaptiqAI sign-in could not start (HTTP ${response.status}).`);
|
|
575
|
-
}
|
|
576
|
-
const body = await readJson(response);
|
|
577
|
-
const deviceCode = String(body?.device_code ?? "");
|
|
578
|
-
const userCode = String(body?.user_code ?? "");
|
|
579
|
-
const url = String(body?.verification_uri_complete ?? body?.verification_uri ?? "");
|
|
580
|
-
if (deviceCode === "" || userCode === "" || !/^https?:\/\//u.test(url))
|
|
581
|
-
throw new Error("AdaptiqAI returned an incomplete sign-in.");
|
|
582
|
-
const expiresAt = this.now() + Math.min(DEVICE_TIMEOUT_MS, Math.max(60, Number(body?.expires_in ?? 600)) * 1e3);
|
|
583
|
-
const interval = Math.max(1, Number(body?.interval ?? 2)) * 1e3;
|
|
639
|
+
const { deviceCode, userCode, url, expiresAt, interval } = await startDeviceCode(this.client(flow.signal), {
|
|
640
|
+
app,
|
|
641
|
+
device: deviceLabel(this.options.deviceName ?? hostname()),
|
|
642
|
+
binding
|
|
643
|
+
});
|
|
584
644
|
this.pendingSignIn = { url, userCode, expiresAt };
|
|
585
645
|
this.set("signing-in");
|
|
586
646
|
void this.poll(flow, deviceCode, clientProof, interval, expiresAt);
|
|
@@ -592,61 +652,27 @@ var AuthManager = class {
|
|
|
592
652
|
while (this.now() < expiresAt) {
|
|
593
653
|
await this.sleep(delay, flow.signal);
|
|
594
654
|
delay = interval;
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
method: "POST",
|
|
599
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
600
|
-
body: JSON.stringify({ device_code: deviceCode }),
|
|
601
|
-
signal: AbortSignal.any([flow.signal, AbortSignal.timeout(2e4)]),
|
|
602
|
-
redirect: "error"
|
|
603
|
-
});
|
|
604
|
-
} catch {
|
|
605
|
-
if (flow.signal.aborted)
|
|
606
|
-
return;
|
|
607
|
-
delay = interval * 2;
|
|
655
|
+
const answer = await pollDeviceCode(this.client(flow.signal), { deviceCode, interval });
|
|
656
|
+
if (answer.state === "waiting") {
|
|
657
|
+
delay = answer.delayMs;
|
|
608
658
|
continue;
|
|
609
659
|
}
|
|
610
|
-
if (
|
|
611
|
-
|
|
612
|
-
if (response.status === 429) {
|
|
613
|
-
const retry = Number(response.headers.get("retry-after") ?? 0) * 1e3;
|
|
614
|
-
delay = Math.max(interval, retry) + 250;
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
|
-
if (response.status === 403) {
|
|
618
|
-
const raw = await readJson(response);
|
|
619
|
-
this.fail(flow, { code: "denied", message: detailCode(raw) === "access_denied" ? "The connection was declined in the browser." : detailMessage(raw) ?? "The connection was declined." });
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
if (response.status === 410 || response.status === 404) {
|
|
623
|
-
this.fail(flow, { code: "expired", message: "The sign-in link expired. Start again." });
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
if (!response.ok) {
|
|
627
|
-
if (response.status >= 500) {
|
|
628
|
-
delay = interval * 2;
|
|
629
|
-
continue;
|
|
630
|
-
}
|
|
631
|
-
this.fail(flow, { code: "failed", message: detailMessage(await readJson(response)) ?? `Sign-in failed (HTTP ${response.status}).` });
|
|
660
|
+
if (answer.state !== "approved") {
|
|
661
|
+
this.fail(flow, { code: answer.state, message: answer.message });
|
|
632
662
|
return;
|
|
633
663
|
}
|
|
634
|
-
|
|
635
|
-
const access2 = String(body?.access_token ?? "");
|
|
636
|
-
const refresh = String(body?.refresh_token ?? "");
|
|
637
|
-
if (!access2.startsWith("ak_") || !refresh.startsWith("akr_")) {
|
|
664
|
+
if (answer.refresh === null) {
|
|
638
665
|
this.fail(flow, { code: "failed", message: "AdaptiqAI returned an invalid credential." });
|
|
639
666
|
return;
|
|
640
667
|
}
|
|
641
|
-
const workspaceLabel = typeof body?.workspace_label === "string" && body.workspace_label !== "" ? body.workspace_label : "Your workspace";
|
|
642
668
|
const grant = {
|
|
643
669
|
schema: "adaptiq-dsh-grant-v1",
|
|
644
670
|
apiBase: this.options.apiBase,
|
|
645
|
-
access:
|
|
646
|
-
refresh,
|
|
671
|
+
access: answer.access,
|
|
672
|
+
refresh: answer.refresh,
|
|
647
673
|
clientProof,
|
|
648
|
-
expiresAt: this.now() +
|
|
649
|
-
workspaceLabel,
|
|
674
|
+
expiresAt: this.now() + answer.expiresIn * 1e3,
|
|
675
|
+
workspaceLabel: answer.workspaceLabel,
|
|
650
676
|
obtainedAt: this.now()
|
|
651
677
|
};
|
|
652
678
|
await this.options.store.modify(async () => grant);
|
|
@@ -655,12 +681,12 @@ var AuthManager = class {
|
|
|
655
681
|
this.flow = null;
|
|
656
682
|
this.pendingSignIn = null;
|
|
657
683
|
this.source = "device";
|
|
658
|
-
this.label = workspaceLabel;
|
|
684
|
+
this.label = answer.workspaceLabel;
|
|
659
685
|
this.set("connected");
|
|
660
|
-
this.options.onSignedIn?.(workspaceLabel);
|
|
686
|
+
this.options.onSignedIn?.(answer.workspaceLabel);
|
|
661
687
|
return;
|
|
662
688
|
}
|
|
663
|
-
this.fail(flow, { code: "expired", message:
|
|
689
|
+
this.fail(flow, { code: "expired", message: EXPIRED });
|
|
664
690
|
} catch (error) {
|
|
665
691
|
if (flow.signal.aborted)
|
|
666
692
|
return;
|
|
@@ -785,6 +811,20 @@ var obj = (value) => typeof value === "object" && value !== null && !Array.isArr
|
|
|
785
811
|
var str = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
786
812
|
var num = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
787
813
|
var count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
814
|
+
function pricesFromRow(raw) {
|
|
815
|
+
const pricing = obj(raw);
|
|
816
|
+
const price = (value) => {
|
|
817
|
+
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : typeof value === "number" ? value : Number.NaN;
|
|
818
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
|
|
819
|
+
};
|
|
820
|
+
const input = price(pricing?.prompt);
|
|
821
|
+
const memoryWrite = price(pricing?.input_cache_write);
|
|
822
|
+
const memoryRead = price(pricing?.input_cache_read);
|
|
823
|
+
const output = price(pricing?.completion);
|
|
824
|
+
if (input === null || memoryWrite === null || memoryRead === null || output === null)
|
|
825
|
+
return null;
|
|
826
|
+
return { input, memoryWrite, memoryRead, output };
|
|
827
|
+
}
|
|
788
828
|
var LEVEL_NAMES = {
|
|
789
829
|
off: "Off",
|
|
790
830
|
minimal: "Minimal",
|
|
@@ -873,17 +913,17 @@ function placementsFromRoutes(routes) {
|
|
|
873
913
|
const model2 = str(route?.model);
|
|
874
914
|
if (route === null || model2 === null || route.enabled !== true)
|
|
875
915
|
continue;
|
|
876
|
-
const
|
|
916
|
+
const add2 = (a, b) => a === null ? b : b === null ? a : a + b;
|
|
877
917
|
const current = out.get(model2);
|
|
878
918
|
const running = count(route.running);
|
|
879
919
|
const waiting = count(route.waiting);
|
|
880
920
|
out.set(model2, {
|
|
881
921
|
name: current?.name ?? (str(route.name) !== null ? routeModelName(str(route.name)) : null),
|
|
882
922
|
status: "running",
|
|
883
|
-
lanes:
|
|
884
|
-
maxParallel:
|
|
885
|
-
runningNow:
|
|
886
|
-
waitingNow:
|
|
923
|
+
lanes: add2(current?.lanes ?? null, count(route.lanes)),
|
|
924
|
+
maxParallel: add2(current?.maxParallel ?? null, count(route.max_parallel_agents)),
|
|
925
|
+
runningNow: add2(current?.runningNow ?? null, running),
|
|
926
|
+
waitingNow: add2(current?.waitingNow ?? null, waiting),
|
|
887
927
|
region: current?.region ?? str(route.region),
|
|
888
928
|
card: null,
|
|
889
929
|
contextWindow: null,
|
|
@@ -944,7 +984,8 @@ function model(id, row, placement) {
|
|
|
944
984
|
maxParallel: placement?.maxParallel ?? count(gateway?.max_parallel_agents),
|
|
945
985
|
runningNow: placement?.runningNow ?? null,
|
|
946
986
|
waitingNow: placement?.waitingNow ?? null,
|
|
947
|
-
region: placement?.region ?? str(gateway?.region)
|
|
987
|
+
region: placement?.region ?? str(gateway?.region),
|
|
988
|
+
prices: pricesFromRow(row?.pricing)
|
|
948
989
|
};
|
|
949
990
|
}
|
|
950
991
|
function selectableLevels(reasoning2) {
|
|
@@ -1020,6 +1061,60 @@ function laneLimit(offer) {
|
|
|
1020
1061
|
return free < offer.minLanes ? 0 : Math.min(offer.maxLanes, free);
|
|
1021
1062
|
}
|
|
1022
1063
|
|
|
1064
|
+
// ../core/lib/processed.js
|
|
1065
|
+
var NOTHING_PROCESSED = { requests: 0, newInput: 0, fromMemory: 0, written: 0, output: 0, reasoning: 0, costUsd: 0 };
|
|
1066
|
+
function stepCost(usage2, prices) {
|
|
1067
|
+
if (prices === null)
|
|
1068
|
+
return null;
|
|
1069
|
+
return usage2.inputTokens * prices.input + (usage2.cacheWriteTokens ?? 0) * prices.memoryWrite + (usage2.cacheReadTokens ?? 0) * prices.memoryRead + usage2.outputTokens * prices.output;
|
|
1070
|
+
}
|
|
1071
|
+
function add(view, step) {
|
|
1072
|
+
return {
|
|
1073
|
+
requests: view.requests + 1,
|
|
1074
|
+
newInput: view.newInput + step.usage.inputTokens,
|
|
1075
|
+
fromMemory: view.fromMemory + (step.usage.cacheReadTokens ?? 0),
|
|
1076
|
+
written: view.written + (step.usage.cacheWriteTokens ?? 0),
|
|
1077
|
+
output: view.output + step.usage.outputTokens,
|
|
1078
|
+
reasoning: view.reasoning + (step.usage.reasoningTokens ?? 0),
|
|
1079
|
+
costUsd: view.costUsd === null || step.costUsd === null ? null : view.costUsd + step.costUsd
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
function addStep(record, step, now) {
|
|
1083
|
+
const turnKey = step.turn ?? record?.turnKey ?? null;
|
|
1084
|
+
const fresh = record == null || step.turn !== void 0 && step.turn !== record.turnKey;
|
|
1085
|
+
return {
|
|
1086
|
+
since: record?.since ?? now,
|
|
1087
|
+
at: now,
|
|
1088
|
+
turnKey,
|
|
1089
|
+
turn: add(fresh ? NOTHING_PROCESSED : record.turn, step),
|
|
1090
|
+
session: add(record?.session ?? NOTHING_PROCESSED, step)
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
function readProcessed(raw) {
|
|
1094
|
+
const record = typeof raw === "object" && raw !== null ? raw : null;
|
|
1095
|
+
const view = (value) => {
|
|
1096
|
+
const fields = typeof value === "object" && value !== null ? value : null;
|
|
1097
|
+
if (fields === null)
|
|
1098
|
+
return null;
|
|
1099
|
+
const count3 = (name2) => {
|
|
1100
|
+
const field = fields[name2];
|
|
1101
|
+
return typeof field === "number" && Number.isFinite(field) && field >= 0 ? field : null;
|
|
1102
|
+
};
|
|
1103
|
+
const numbers = { requests: count3("requests"), newInput: count3("newInput"), fromMemory: count3("fromMemory"), written: count3("written"), output: count3("output"), reasoning: count3("reasoning") };
|
|
1104
|
+
if (Object.values(numbers).some((value2) => value2 === null))
|
|
1105
|
+
return null;
|
|
1106
|
+
return { ...numbers, costUsd: count3("costUsd") };
|
|
1107
|
+
};
|
|
1108
|
+
const turn = view(record?.turn);
|
|
1109
|
+
const session = view(record?.session);
|
|
1110
|
+
const since = record?.since;
|
|
1111
|
+
const at = record?.at;
|
|
1112
|
+
if (turn === null || session === null || typeof since !== "number" || typeof at !== "number")
|
|
1113
|
+
return null;
|
|
1114
|
+
const turnKey = typeof record?.turnKey === "number" ? record.turnKey : null;
|
|
1115
|
+
return { since, at, turnKey, turn, session };
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1023
1118
|
// ../core/lib/relations.js
|
|
1024
1119
|
var PARENT_SESSION_HEADER = "X-Adaptiq-Parent-Session-Id";
|
|
1025
1120
|
var SESSION_ROLE_HEADER = "X-Adaptiq-Session-Role";
|
|
@@ -1066,13 +1161,11 @@ var en = {
|
|
|
1066
1161
|
expiredTitle: "Your sign-in expired",
|
|
1067
1162
|
signInAgain: "Sign in again",
|
|
1068
1163
|
tryAgain: "Try again",
|
|
1069
|
-
models: "Models
|
|
1164
|
+
models: "Models",
|
|
1070
1165
|
status_running: "Running",
|
|
1071
1166
|
status_offline: "Offline",
|
|
1072
1167
|
status_disabled: "Paused",
|
|
1073
1168
|
status_unknown: "Available",
|
|
1074
|
-
lanesOne: "{count} lane",
|
|
1075
|
-
lanesMany: "{count} lanes",
|
|
1076
1169
|
thinkingLevels: "Thinking {levels}",
|
|
1077
1170
|
noModels: "Pick your first model",
|
|
1078
1171
|
getAccess: "Get access",
|
|
@@ -1098,10 +1191,10 @@ var en = {
|
|
|
1098
1191
|
routeConflictTitle: "AdaptiqAI models are hidden",
|
|
1099
1192
|
pillMemory: "Memory",
|
|
1100
1193
|
pillPreparing: "Preparing memory",
|
|
1101
|
-
pillQueued: "Waiting
|
|
1194
|
+
pillQueued: "Waiting in line",
|
|
1102
1195
|
pillStarting: "Starting\u2026",
|
|
1103
1196
|
pillSignIn: "Sign in to AdaptiqAI",
|
|
1104
|
-
pillFromMemory: "{tokens} from memory",
|
|
1197
|
+
pillFromMemory: "{tokens} from memory \xB7 free",
|
|
1105
1198
|
pillTooltip: "AdaptiqAI memory for this conversation",
|
|
1106
1199
|
popTitle: "Memory",
|
|
1107
1200
|
popSaving: "Saving",
|
|
@@ -1110,6 +1203,22 @@ var en = {
|
|
|
1110
1203
|
popKnowledge: "Knowledge",
|
|
1111
1204
|
addKnowledge: "Add knowledge",
|
|
1112
1205
|
popWorkspace: "All memory on {model}",
|
|
1206
|
+
popSeesNow: "What the model sees now",
|
|
1207
|
+
procTitle: "Processed",
|
|
1208
|
+
procTurn: "Last turn",
|
|
1209
|
+
procSession: "This conversation",
|
|
1210
|
+
procSteps: "{count} steps",
|
|
1211
|
+
procStepsOne: "1 step",
|
|
1212
|
+
procNewInput: "New input",
|
|
1213
|
+
procFromMemory: "Read from memory",
|
|
1214
|
+
procWritten: "Saved to memory",
|
|
1215
|
+
procOutput: "Output",
|
|
1216
|
+
procThinking: "Thinking, part of output",
|
|
1217
|
+
procCost: "Cost",
|
|
1218
|
+
procExplain: "Each step reads the whole memory again. {percent} came from memory.",
|
|
1219
|
+
procExplainFree: "Each step reads the whole memory again. {percent} came from memory, which is free.",
|
|
1220
|
+
procExplainCheaper: "Each step reads the whole memory again. {percent} came from memory, at a fraction of the input price.",
|
|
1221
|
+
procSince: "Counted on this computer since {date}",
|
|
1113
1222
|
openInKnowledge: "Open in Knowledge",
|
|
1114
1223
|
kTitle: "Knowledge",
|
|
1115
1224
|
kSearch: "Search your knowledge",
|
|
@@ -1177,22 +1286,22 @@ var en = {
|
|
|
1177
1286
|
accessTitle: "Get a model",
|
|
1178
1287
|
offerSpeed: "{speed} tokens/s",
|
|
1179
1288
|
offerMemory: "{tokens} memory",
|
|
1180
|
-
offerPrice: "{price} per
|
|
1289
|
+
offerPrice: "{price} per {period}",
|
|
1181
1290
|
offerOwned: "In your workspace",
|
|
1182
1291
|
offerFull: "Full right now",
|
|
1183
1292
|
period_hour: "hour",
|
|
1184
1293
|
period_month: "month",
|
|
1185
1294
|
period_once: "purchase",
|
|
1186
|
-
lanesLabel: "
|
|
1187
|
-
lanesHint: "
|
|
1295
|
+
lanesLabel: "At once",
|
|
1296
|
+
lanesHint: "How many conversations can run at the same time.",
|
|
1188
1297
|
totalPrice: "{price} per {period}",
|
|
1189
1298
|
noOffers: "No models are on offer right now. Check back soon.",
|
|
1190
|
-
manualNote: "Our team
|
|
1191
|
-
balanceNote: "
|
|
1299
|
+
manualNote: "Our team turns it on after you confirm.",
|
|
1300
|
+
balanceNote: "You pay per token from your balance. Reads from memory are free.",
|
|
1192
1301
|
cardNote: "You pay by card in your browser.",
|
|
1193
|
-
addLanes: "
|
|
1302
|
+
addLanes: "Run more at once",
|
|
1194
1303
|
purchase_approving: "Confirm in your browser",
|
|
1195
|
-
purchase_approving_body: "We opened a page to confirm {
|
|
1304
|
+
purchase_approving_body: "We opened a page to confirm {model}. This updates by itself.",
|
|
1196
1305
|
purchase_console_body: "Finish on the page we opened. {model} appears here as soon as it's active.",
|
|
1197
1306
|
purchase_requested: "Requested. We'll activate it shortly",
|
|
1198
1307
|
purchase_requested_body: "You'll get an email too. {model} appears here by itself.",
|
|
@@ -1202,10 +1311,8 @@ var en = {
|
|
|
1202
1311
|
purchase_ready_body: "Pick it in the model picker and start.",
|
|
1203
1312
|
purchase_denied: "The purchase was declined in the browser.",
|
|
1204
1313
|
purchase_expired: "The confirmation page expired.",
|
|
1205
|
-
purchase_stopped: "The
|
|
1314
|
+
purchase_stopped: "The model has stopped.",
|
|
1206
1315
|
purchase_failed: "The purchase didn't go through.",
|
|
1207
|
-
lanesCount: "{count} lanes",
|
|
1208
|
-
laneCount: "1 lane",
|
|
1209
1316
|
openPage: "Open the page again",
|
|
1210
1317
|
stopWaiting: "Stop waiting",
|
|
1211
1318
|
startChatting: "Start a conversation",
|
|
@@ -1284,16 +1391,16 @@ var en = {
|
|
|
1284
1391
|
n_signIn_title: "Sign in to keep going",
|
|
1285
1392
|
n_signIn_body: "Your AdaptiqAI connection needs a fresh sign-in.",
|
|
1286
1393
|
n_connect_body: "Connect your AdaptiqAI account to use this model.",
|
|
1287
|
-
n_noLanes_title: "
|
|
1288
|
-
n_noLanes_body: "You
|
|
1289
|
-
n_laneStopped_body: "
|
|
1290
|
-
n_planUsedUp_body: "Your plan's usage is used up until {until}.
|
|
1291
|
-
n_planUsedUpNoDate_body: "Your plan's usage is used up for now.
|
|
1394
|
+
n_noLanes_title: "Get access to continue",
|
|
1395
|
+
n_noLanes_body: "This model isn't in your workspace yet. You pay per token from your balance; reads from memory are free.",
|
|
1396
|
+
n_laneStopped_body: "The model stopped after going unused. Start it again to continue.",
|
|
1397
|
+
n_planUsedUp_body: "Your plan's usage is used up until {until}. Pay per token from your balance in the meantime.",
|
|
1398
|
+
n_planUsedUpNoDate_body: "Your plan's usage is used up for now. Pay per token from your balance in the meantime.",
|
|
1292
1399
|
n_credit_title: "Add funds to continue",
|
|
1293
|
-
n_credit_body: "Your balance ran out
|
|
1294
|
-
n_creditMinutes_body: "Your balance ran out
|
|
1295
|
-
n_busy_title: "
|
|
1296
|
-
n_busy_body: "Your request
|
|
1400
|
+
n_credit_body: "Your balance ran out. Add funds to keep going.",
|
|
1401
|
+
n_creditMinutes_body: "Your balance ran out. Add funds within {minutes} min to keep your models running.",
|
|
1402
|
+
n_busy_title: "{model} is busy",
|
|
1403
|
+
n_busy_body: "Your request is waiting in line and retries by itself.",
|
|
1297
1404
|
n_preparing_title: "Getting your conversation ready",
|
|
1298
1405
|
n_preparing_body: "AdaptiqAI is loading this conversation's memory. It retries by itself.",
|
|
1299
1406
|
n_unavailable_title: "{model} isn't available",
|
|
@@ -1332,122 +1439,6 @@ function fill(template, params = {}) {
|
|
|
1332
1439
|
return template.replace(/\{(\w+)\}/gu, (whole, name2) => name2 in params ? String(params[name2]) : whole);
|
|
1333
1440
|
}
|
|
1334
1441
|
|
|
1335
|
-
// ../core/lib/update.js
|
|
1336
|
-
var RELEASE_AGE_MS = 24 * 36e5;
|
|
1337
|
-
var RELEASE_VERSION = /^\d+\.\d+\.\d+$/u;
|
|
1338
|
-
function semverGreater(a, b) {
|
|
1339
|
-
const parse = (value) => value.replace(/^v/u, "").split(/[.-]/u).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
|
|
1340
|
-
const [x, y] = [parse(a), parse(b)];
|
|
1341
|
-
for (let i = 0; i < 3; i++)
|
|
1342
|
-
if ((x[i] ?? 0) !== (y[i] ?? 0))
|
|
1343
|
-
return (x[i] ?? 0) > (y[i] ?? 0);
|
|
1344
|
-
return false;
|
|
1345
|
-
}
|
|
1346
|
-
var UpdateFailure = class extends Error {
|
|
1347
|
-
code;
|
|
1348
|
-
constructor(code, message) {
|
|
1349
|
-
super(message);
|
|
1350
|
-
this.code = code;
|
|
1351
|
-
this.name = "UpdateFailure";
|
|
1352
|
-
}
|
|
1353
|
-
};
|
|
1354
|
-
|
|
1355
|
-
// ../core/lib/usage.js
|
|
1356
|
-
async function* parseSse(body, activity) {
|
|
1357
|
-
const decoder = new TextDecoder();
|
|
1358
|
-
const reader = body.getReader();
|
|
1359
|
-
let buffer = "";
|
|
1360
|
-
try {
|
|
1361
|
-
while (true) {
|
|
1362
|
-
const { value, done } = await reader.read();
|
|
1363
|
-
if (done)
|
|
1364
|
-
break;
|
|
1365
|
-
activity();
|
|
1366
|
-
buffer += decoder.decode(value, { stream: true });
|
|
1367
|
-
let boundary = nextBoundary(buffer);
|
|
1368
|
-
while (boundary !== null) {
|
|
1369
|
-
const block = buffer.slice(0, boundary.index);
|
|
1370
|
-
buffer = buffer.slice(boundary.index + boundary.length);
|
|
1371
|
-
const event = parseBlock(block);
|
|
1372
|
-
if (event !== null)
|
|
1373
|
-
yield event;
|
|
1374
|
-
boundary = nextBoundary(buffer);
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
buffer += decoder.decode();
|
|
1378
|
-
const tail = parseBlock(buffer);
|
|
1379
|
-
if (tail !== null)
|
|
1380
|
-
yield tail;
|
|
1381
|
-
} finally {
|
|
1382
|
-
reader.releaseLock();
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
function nextBoundary(buffer) {
|
|
1386
|
-
const match = /\r?\n\r?\n/u.exec(buffer);
|
|
1387
|
-
return match === null ? null : { index: match.index, length: match[0].length };
|
|
1388
|
-
}
|
|
1389
|
-
function parseBlock(block) {
|
|
1390
|
-
let event = null;
|
|
1391
|
-
const data = [];
|
|
1392
|
-
for (const line of block.split(/\r?\n/u)) {
|
|
1393
|
-
const notice = /^: ?adaptiq-memory (.*)$/u.exec(line);
|
|
1394
|
-
if (notice !== null) {
|
|
1395
|
-
event = "adaptiq.memory";
|
|
1396
|
-
data.push(notice[1]);
|
|
1397
|
-
continue;
|
|
1398
|
-
}
|
|
1399
|
-
if (line === "" || line.startsWith(":"))
|
|
1400
|
-
continue;
|
|
1401
|
-
const colon = line.indexOf(":");
|
|
1402
|
-
const field = colon === -1 ? line : line.slice(0, colon);
|
|
1403
|
-
const value = colon === -1 ? "" : line.slice(colon + 1).replace(/^ /u, "");
|
|
1404
|
-
if (field === "event")
|
|
1405
|
-
event = value;
|
|
1406
|
-
else if (field === "data")
|
|
1407
|
-
data.push(value);
|
|
1408
|
-
}
|
|
1409
|
-
return data.length === 0 ? null : { event, data: data.join("\n") };
|
|
1410
|
-
}
|
|
1411
|
-
function mapUsage(raw) {
|
|
1412
|
-
const n = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.round(value) : 0;
|
|
1413
|
-
const details = typeof raw.prompt_tokens_details === "object" && raw.prompt_tokens_details !== null ? raw.prompt_tokens_details : {};
|
|
1414
|
-
const completion = typeof raw.completion_tokens_details === "object" && raw.completion_tokens_details !== null ? raw.completion_tokens_details : {};
|
|
1415
|
-
const prompt = n(raw.prompt_tokens);
|
|
1416
|
-
const output = n(raw.completion_tokens);
|
|
1417
|
-
const cached = Math.min(prompt, n(details.cached_tokens) || n(raw.prompt_cache_hit_tokens));
|
|
1418
|
-
const written = Math.min(prompt - cached, n(details.cache_write_tokens) || n(raw.cache_write_tokens) || n(raw.cache_creation_input_tokens));
|
|
1419
|
-
const reasoning2 = n(completion.reasoning_tokens);
|
|
1420
|
-
const total = n(raw.total_tokens);
|
|
1421
|
-
return {
|
|
1422
|
-
inputTokens: Math.max(0, prompt - cached - written),
|
|
1423
|
-
outputTokens: output,
|
|
1424
|
-
...cached > 0 ? { cacheReadTokens: cached } : {},
|
|
1425
|
-
...written > 0 ? { cacheWriteTokens: written } : {},
|
|
1426
|
-
...reasoning2 > 0 ? { reasoningTokens: reasoning2 } : {},
|
|
1427
|
-
...total > 0 ? { totalTokens: total } : prompt + output > 0 ? { totalTokens: prompt + output } : {}
|
|
1428
|
-
};
|
|
1429
|
-
}
|
|
1430
|
-
function memoryNotice(raw) {
|
|
1431
|
-
let value = raw;
|
|
1432
|
-
if (typeof raw === "string") {
|
|
1433
|
-
try {
|
|
1434
|
-
value = JSON.parse(raw);
|
|
1435
|
-
} catch {
|
|
1436
|
-
return null;
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
if (typeof value !== "object" || value === null)
|
|
1440
|
-
return null;
|
|
1441
|
-
const notice = value;
|
|
1442
|
-
if (notice.kind !== "hibernated" && notice.kind !== "suggestion")
|
|
1443
|
-
return null;
|
|
1444
|
-
const sessions = Array.isArray(notice.sessions) ? notice.sessions.length : 0;
|
|
1445
|
-
if (sessions === 0)
|
|
1446
|
-
return null;
|
|
1447
|
-
const number = (field) => typeof field === "number" && Number.isFinite(field) && field >= 0 ? field : null;
|
|
1448
|
-
return { kind: notice.kind, sessions, tokens: number(notice.tokens), usageRatio: number(notice.usage_ratio) };
|
|
1449
|
-
}
|
|
1450
|
-
|
|
1451
1442
|
// ../core/lib/workspace.js
|
|
1452
1443
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
1453
1444
|
|
|
@@ -1554,9 +1545,9 @@ var PurchaseFlow = class {
|
|
|
1554
1545
|
}
|
|
1555
1546
|
const limit = laneLimit(offer);
|
|
1556
1547
|
if (limit === 0)
|
|
1557
|
-
throw new Error(`${offer.name}
|
|
1548
|
+
throw new Error(`${offer.name} is full right now. Try again later, or pick another model.`);
|
|
1558
1549
|
if (!Number.isInteger(lanes) || lanes < offer.minLanes || lanes > limit) {
|
|
1559
|
-
throw new Error(`Choose between ${offer.minLanes} and ${limit}
|
|
1550
|
+
throw new Error(`Choose between ${offer.minLanes} and ${limit} conversations at once.`);
|
|
1560
1551
|
}
|
|
1561
1552
|
const base = {
|
|
1562
1553
|
offerId: offer.id,
|
|
@@ -1677,6 +1668,26 @@ var PurchaseFlow = class {
|
|
|
1677
1668
|
}
|
|
1678
1669
|
};
|
|
1679
1670
|
|
|
1671
|
+
// ../core/lib/update.js
|
|
1672
|
+
var RELEASE_AGE_MS = 24 * 36e5;
|
|
1673
|
+
var RELEASE_VERSION = /^\d+\.\d+\.\d+$/u;
|
|
1674
|
+
function semverGreater(a, b) {
|
|
1675
|
+
const parse = (value) => value.replace(/^v/u, "").split(/[.-]/u).slice(0, 3).map((part) => Number.parseInt(part, 10) || 0);
|
|
1676
|
+
const [x, y] = [parse(a), parse(b)];
|
|
1677
|
+
for (let i = 0; i < 3; i++)
|
|
1678
|
+
if ((x[i] ?? 0) !== (y[i] ?? 0))
|
|
1679
|
+
return (x[i] ?? 0) > (y[i] ?? 0);
|
|
1680
|
+
return false;
|
|
1681
|
+
}
|
|
1682
|
+
var UpdateFailure = class extends Error {
|
|
1683
|
+
code;
|
|
1684
|
+
constructor(code, message) {
|
|
1685
|
+
super(message);
|
|
1686
|
+
this.code = code;
|
|
1687
|
+
this.name = "UpdateFailure";
|
|
1688
|
+
}
|
|
1689
|
+
};
|
|
1690
|
+
|
|
1680
1691
|
// ../core/lib/workspace.js
|
|
1681
1692
|
var obj4 = (value) => typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
1682
1693
|
var str4 = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
@@ -1687,6 +1698,21 @@ function button(id, label2, extra = {}) {
|
|
|
1687
1698
|
return { id, label: en[label2], labelKey: label2, ...extra };
|
|
1688
1699
|
}
|
|
1689
1700
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1701
|
+
var PROCESSED_SAVE_MS = 2e3;
|
|
1702
|
+
function savedProcessed(raw) {
|
|
1703
|
+
const out = {};
|
|
1704
|
+
if (typeof raw !== "object" || raw === null)
|
|
1705
|
+
return out;
|
|
1706
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
1707
|
+
const record = readProcessed(value);
|
|
1708
|
+
if (record !== null)
|
|
1709
|
+
out[id] = record;
|
|
1710
|
+
}
|
|
1711
|
+
return out;
|
|
1712
|
+
}
|
|
1713
|
+
function processedSummary(record) {
|
|
1714
|
+
return record === void 0 ? null : { turn: record.turn, session: record.session, since: record.since };
|
|
1715
|
+
}
|
|
1690
1716
|
var PRIVATE_HELD = "A private conversation is not kept on AdaptiqAI, so it can't use this before it exists there. Turn Remember on for this conversation to add it.";
|
|
1691
1717
|
var ATTACH_TRIES = 3;
|
|
1692
1718
|
function transient(error) {
|
|
@@ -1851,7 +1877,7 @@ function copyFailure(error, model2) {
|
|
|
1851
1877
|
case "model_mismatch":
|
|
1852
1878
|
return str4(detail.message) ?? `This collection can't be made available for ${model2}.`;
|
|
1853
1879
|
case "inference_entitlement_required":
|
|
1854
|
-
return "
|
|
1880
|
+
return "This model isn't in your workspace yet. Get access to continue; you pay per token from your balance.";
|
|
1855
1881
|
case "collection_not_found":
|
|
1856
1882
|
return "This collection no longer exists.";
|
|
1857
1883
|
case "sources_not_exportable":
|
|
@@ -2052,6 +2078,7 @@ var Workspace = class {
|
|
|
2052
2078
|
listeners = /* @__PURE__ */ new Set();
|
|
2053
2079
|
state = { preferences: DEFAULT_PREFERENCES, sessions: {} };
|
|
2054
2080
|
saving = Promise.resolve();
|
|
2081
|
+
persistTimer;
|
|
2055
2082
|
refreshing = null;
|
|
2056
2083
|
timer;
|
|
2057
2084
|
pendingAttach = /* @__PURE__ */ new Map();
|
|
@@ -2111,7 +2138,8 @@ var Workspace = class {
|
|
|
2111
2138
|
preferences: { ...DEFAULT_PREFERENCES, ...saved.preferences },
|
|
2112
2139
|
sessions: typeof saved.sessions === "object" && saved.sessions !== null ? saved.sessions : {},
|
|
2113
2140
|
purchase: saved.purchase ?? null,
|
|
2114
|
-
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {}
|
|
2141
|
+
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {},
|
|
2142
|
+
processed: savedProcessed(saved.processed)
|
|
2115
2143
|
};
|
|
2116
2144
|
this.purchases.restore(saved.purchase);
|
|
2117
2145
|
}
|
|
@@ -2127,6 +2155,10 @@ var Workspace = class {
|
|
|
2127
2155
|
this.purchases.dispose();
|
|
2128
2156
|
clearTimeout(this.timer);
|
|
2129
2157
|
clearTimeout(this.attachTimer);
|
|
2158
|
+
if (this.persistTimer !== void 0) {
|
|
2159
|
+
clearTimeout(this.persistTimer);
|
|
2160
|
+
void this.persist();
|
|
2161
|
+
}
|
|
2130
2162
|
for (const session of this.sessions.values()) {
|
|
2131
2163
|
clearTimeout(session.timer);
|
|
2132
2164
|
clearTimeout(session.waitTimer);
|
|
@@ -2194,7 +2226,8 @@ var Workspace = class {
|
|
|
2194
2226
|
region: model2.region,
|
|
2195
2227
|
nativeMemory: model2.nativeMemory,
|
|
2196
2228
|
tools: model2.tools,
|
|
2197
|
-
memory: this.modelMemory.get(model2.id) ?? null
|
|
2229
|
+
memory: this.modelMemory.get(model2.id) ?? null,
|
|
2230
|
+
prices: model2.prices
|
|
2198
2231
|
};
|
|
2199
2232
|
}
|
|
2200
2233
|
/**
|
|
@@ -2804,12 +2837,16 @@ var Workspace = class {
|
|
|
2804
2837
|
return next;
|
|
2805
2838
|
}
|
|
2806
2839
|
async persist() {
|
|
2840
|
+
clearTimeout(this.persistTimer);
|
|
2841
|
+
this.persistTimer = void 0;
|
|
2807
2842
|
const entries = Object.entries(this.state.sessions).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2843
|
+
const processed = Object.entries(this.state.processed ?? {}).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2808
2844
|
const snapshot = {
|
|
2809
2845
|
preferences: this.state.preferences,
|
|
2810
2846
|
sessions: Object.fromEntries(entries),
|
|
2811
2847
|
purchase: this.state.purchase ?? null,
|
|
2812
|
-
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel }
|
|
2848
|
+
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel },
|
|
2849
|
+
...processed.length === 0 ? {} : { processed: Object.fromEntries(processed) }
|
|
2813
2850
|
};
|
|
2814
2851
|
this.saving = this.saving.then(() => this.deps.store.save(snapshot)).catch((error) => {
|
|
2815
2852
|
this.deps.log?.("warn", `adaptiq: could not save preferences: ${String(error)}`);
|
|
@@ -2830,7 +2867,9 @@ var Workspace = class {
|
|
|
2830
2867
|
/**
|
|
2831
2868
|
* Whether this conversation is known to be stored on AdaptiqAI. A private
|
|
2832
2869
|
* turn of a conversation that is not stored yet runs ephemeral: there is
|
|
2833
|
-
* nothing to read back and nothing may be saved.
|
|
2870
|
+
* nothing to read back and nothing may be saved. While the last answer was
|
|
2871
|
+
* "not stored", the server is asked again: a remembered turn since may have
|
|
2872
|
+
* stored it, and a plugin that reports no turns would not hear of it.
|
|
2834
2873
|
* @param sessionId - harness session id.
|
|
2835
2874
|
* @returns true when the server has the conversation.
|
|
2836
2875
|
*/
|
|
@@ -2838,7 +2877,7 @@ var Workspace = class {
|
|
|
2838
2877
|
if (sessionId2 === void 0)
|
|
2839
2878
|
return false;
|
|
2840
2879
|
const session = this.session(sessionId2);
|
|
2841
|
-
if (session.remoteAt === 0 && this.deps.auth.phase() === "connected") {
|
|
2880
|
+
if ((session.remoteAt === 0 || !session.exists) && this.deps.auth.phase() === "connected") {
|
|
2842
2881
|
await Promise.race([this.loadSession(session).catch(() => {
|
|
2843
2882
|
}), new Promise((resolve2) => setTimeout(resolve2, 2500))]);
|
|
2844
2883
|
}
|
|
@@ -2918,6 +2957,7 @@ var Workspace = class {
|
|
|
2918
2957
|
saved: session.saved,
|
|
2919
2958
|
optimizing: session.optimizing,
|
|
2920
2959
|
lastTurn: session.lastTurn,
|
|
2960
|
+
processed: processedSummary(this.state.processed?.[id]),
|
|
2921
2961
|
knowledge: [...session.knowledge, ...[...session.pendingKnowledge.values()].filter((item) => !session.knowledge.some((entry) => entry.id === item.id))],
|
|
2922
2962
|
conversations: [...session.conversations, ...[...session.pendingConversations.values()].filter((item) => !session.conversations.some((entry) => entry.id === item.id))],
|
|
2923
2963
|
known: session.exists,
|
|
@@ -3297,10 +3337,19 @@ var Workspace = class {
|
|
|
3297
3337
|
this.setPhase(session, "responding");
|
|
3298
3338
|
this.clearNotices("busy", "preparing", "offline", "retrying");
|
|
3299
3339
|
}
|
|
3300
|
-
usage(sessionId2, model2, usage2) {
|
|
3340
|
+
usage(sessionId2, model2, usage2, step = {}) {
|
|
3301
3341
|
if (sessionId2 === void 0)
|
|
3302
3342
|
return;
|
|
3303
3343
|
const session = this.session(sessionId2);
|
|
3344
|
+
const costUsd = step.costUsd ?? stepCost(usage2, this.catalog.find((entry) => entry.id === model2)?.prices ?? null);
|
|
3345
|
+
const counted = addStep(this.state.processed?.[sessionId2], { usage: usage2, costUsd, ...step.turn === void 0 ? {} : { turn: step.turn } }, this.now());
|
|
3346
|
+
this.state = { ...this.state, processed: { ...this.state.processed, [sessionId2]: counted } };
|
|
3347
|
+
if (this.persistTimer === void 0) {
|
|
3348
|
+
this.persistTimer = setTimeout(() => {
|
|
3349
|
+
void this.persist();
|
|
3350
|
+
}, PROCESSED_SAVE_MS);
|
|
3351
|
+
this.persistTimer.unref?.();
|
|
3352
|
+
}
|
|
3304
3353
|
session.lastTurn = {
|
|
3305
3354
|
fromMemory: usage2.cacheReadTokens ?? 0,
|
|
3306
3355
|
newInput: usage2.inputTokens,
|
|
@@ -4562,6 +4611,111 @@ var Workspace = class {
|
|
|
4562
4611
|
}
|
|
4563
4612
|
};
|
|
4564
4613
|
|
|
4614
|
+
// ../core/lib/tools.js
|
|
4615
|
+
var SOURCE_LIMIT = 6 * 1024 * 1024;
|
|
4616
|
+
|
|
4617
|
+
// ../core/lib/usage.js
|
|
4618
|
+
async function* parseSse(body, activity) {
|
|
4619
|
+
const decoder = new TextDecoder();
|
|
4620
|
+
const reader = body.getReader();
|
|
4621
|
+
let buffer = "";
|
|
4622
|
+
try {
|
|
4623
|
+
while (true) {
|
|
4624
|
+
const { value, done } = await reader.read();
|
|
4625
|
+
if (done)
|
|
4626
|
+
break;
|
|
4627
|
+
activity();
|
|
4628
|
+
buffer += decoder.decode(value, { stream: true });
|
|
4629
|
+
let boundary = nextBoundary(buffer);
|
|
4630
|
+
while (boundary !== null) {
|
|
4631
|
+
const block = buffer.slice(0, boundary.index);
|
|
4632
|
+
buffer = buffer.slice(boundary.index + boundary.length);
|
|
4633
|
+
const event = parseBlock(block);
|
|
4634
|
+
if (event !== null)
|
|
4635
|
+
yield event;
|
|
4636
|
+
boundary = nextBoundary(buffer);
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
buffer += decoder.decode();
|
|
4640
|
+
const tail = parseBlock(buffer);
|
|
4641
|
+
if (tail !== null)
|
|
4642
|
+
yield tail;
|
|
4643
|
+
} finally {
|
|
4644
|
+
reader.releaseLock();
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
function nextBoundary(buffer) {
|
|
4648
|
+
const match = /\r?\n\r?\n/u.exec(buffer);
|
|
4649
|
+
return match === null ? null : { index: match.index, length: match[0].length };
|
|
4650
|
+
}
|
|
4651
|
+
function parseBlock(block) {
|
|
4652
|
+
let event = null;
|
|
4653
|
+
const data = [];
|
|
4654
|
+
for (const line of block.split(/\r?\n/u)) {
|
|
4655
|
+
const notice = /^: ?adaptiq-memory (.*)$/u.exec(line);
|
|
4656
|
+
if (notice !== null) {
|
|
4657
|
+
event = "adaptiq.memory";
|
|
4658
|
+
data.push(notice[1]);
|
|
4659
|
+
continue;
|
|
4660
|
+
}
|
|
4661
|
+
if (line === "" || line.startsWith(":"))
|
|
4662
|
+
continue;
|
|
4663
|
+
const colon = line.indexOf(":");
|
|
4664
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
4665
|
+
const value = colon === -1 ? "" : line.slice(colon + 1).replace(/^ /u, "");
|
|
4666
|
+
if (field === "event")
|
|
4667
|
+
event = value;
|
|
4668
|
+
else if (field === "data")
|
|
4669
|
+
data.push(value);
|
|
4670
|
+
}
|
|
4671
|
+
return data.length === 0 ? null : { event, data: data.join("\n") };
|
|
4672
|
+
}
|
|
4673
|
+
function mapUsage(raw) {
|
|
4674
|
+
const n = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.round(value) : 0;
|
|
4675
|
+
const details = typeof raw.prompt_tokens_details === "object" && raw.prompt_tokens_details !== null ? raw.prompt_tokens_details : {};
|
|
4676
|
+
const completion = typeof raw.completion_tokens_details === "object" && raw.completion_tokens_details !== null ? raw.completion_tokens_details : {};
|
|
4677
|
+
const prompt = n(raw.prompt_tokens);
|
|
4678
|
+
const output = n(raw.completion_tokens);
|
|
4679
|
+
const cached = Math.min(prompt, n(details.cached_tokens) || n(raw.prompt_cache_hit_tokens));
|
|
4680
|
+
const written = Math.min(prompt - cached, n(details.cache_write_tokens) || n(raw.cache_write_tokens) || n(raw.cache_creation_input_tokens));
|
|
4681
|
+
const reasoning2 = n(completion.reasoning_tokens);
|
|
4682
|
+
const total = n(raw.total_tokens);
|
|
4683
|
+
return {
|
|
4684
|
+
inputTokens: Math.max(0, prompt - cached - written),
|
|
4685
|
+
outputTokens: output,
|
|
4686
|
+
...cached > 0 ? { cacheReadTokens: cached } : {},
|
|
4687
|
+
...written > 0 ? { cacheWriteTokens: written } : {},
|
|
4688
|
+
...reasoning2 > 0 ? { reasoningTokens: reasoning2 } : {},
|
|
4689
|
+
...total > 0 ? { totalTokens: total } : prompt + output > 0 ? { totalTokens: prompt + output } : {}
|
|
4690
|
+
};
|
|
4691
|
+
}
|
|
4692
|
+
function usageCost(raw) {
|
|
4693
|
+
const adaptiq = typeof raw.adaptiq === "object" && raw.adaptiq !== null ? raw.adaptiq : null;
|
|
4694
|
+
const value = adaptiq?.cost_usd;
|
|
4695
|
+
const cost = typeof value === "string" && value.trim() !== "" ? Number(value) : typeof value === "number" ? value : Number.NaN;
|
|
4696
|
+
return Number.isFinite(cost) && cost >= 0 ? cost : null;
|
|
4697
|
+
}
|
|
4698
|
+
function memoryNotice(raw) {
|
|
4699
|
+
let value = raw;
|
|
4700
|
+
if (typeof raw === "string") {
|
|
4701
|
+
try {
|
|
4702
|
+
value = JSON.parse(raw);
|
|
4703
|
+
} catch {
|
|
4704
|
+
return null;
|
|
4705
|
+
}
|
|
4706
|
+
}
|
|
4707
|
+
if (typeof value !== "object" || value === null)
|
|
4708
|
+
return null;
|
|
4709
|
+
const notice = value;
|
|
4710
|
+
if (notice.kind !== "hibernated" && notice.kind !== "suggestion")
|
|
4711
|
+
return null;
|
|
4712
|
+
const sessions = Array.isArray(notice.sessions) ? notice.sessions.length : 0;
|
|
4713
|
+
if (sessions === 0)
|
|
4714
|
+
return null;
|
|
4715
|
+
const number = (field) => typeof field === "number" && Number.isFinite(field) && field >= 0 ? field : null;
|
|
4716
|
+
return { kind: notice.kind, sessions, tokens: number(notice.tokens), usageRatio: number(notice.usage_ratio) };
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4565
4719
|
// src/host/stream.ts
|
|
4566
4720
|
var REASONING_FIELDS = ["reasoning_content", "reasoning", "reasoning_text"];
|
|
4567
4721
|
async function* translate(events, hooks) {
|
|
@@ -4572,6 +4726,7 @@ async function* translate(events, hooks) {
|
|
|
4572
4726
|
let reasoningField = null;
|
|
4573
4727
|
let finish = null;
|
|
4574
4728
|
let usage2 = null;
|
|
4729
|
+
let costUsd = null;
|
|
4575
4730
|
let started = false;
|
|
4576
4731
|
let nextIndex = 0;
|
|
4577
4732
|
const closed = /* @__PURE__ */ new Set();
|
|
@@ -4617,6 +4772,7 @@ async function* translate(events, hooks) {
|
|
|
4617
4772
|
}
|
|
4618
4773
|
if (typeof payload.usage === "object" && payload.usage !== null) {
|
|
4619
4774
|
usage2 = mapUsage(payload.usage);
|
|
4775
|
+
costUsd = usageCost(payload.usage);
|
|
4620
4776
|
}
|
|
4621
4777
|
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
4622
4778
|
const choice = choices[0];
|
|
@@ -4678,7 +4834,7 @@ async function* translate(events, hooks) {
|
|
|
4678
4834
|
throw hooks.onError({ error: { message: "The model returned no reply.", type: "empty_response", code: "EMPTY_RESPONSE" } });
|
|
4679
4835
|
}
|
|
4680
4836
|
if (usage2 !== null) {
|
|
4681
|
-
hooks.onUsage?.(usage2);
|
|
4837
|
+
hooks.onUsage?.(usage2, costUsd);
|
|
4682
4838
|
yield { type: "usage", usage: usage2 };
|
|
4683
4839
|
}
|
|
4684
4840
|
const hasTools = blocks.some((block) => block.kind === "tool-call");
|
|
@@ -5056,7 +5212,6 @@ function resolvedInfo(route, model2) {
|
|
|
5056
5212
|
function describe(model2) {
|
|
5057
5213
|
const parts = [];
|
|
5058
5214
|
if (model2.nativeMemory || (model2.contextWindow ?? 0) >= 1e6) parts.push("Native memory");
|
|
5059
|
-
if (model2.lanes !== null) parts.push(`${model2.lanes} ${model2.lanes === 1 ? "lane" : "lanes"}`);
|
|
5060
5215
|
return parts.join(" \xB7 ");
|
|
5061
5216
|
}
|
|
5062
5217
|
function toLlmError(failure, cause) {
|
|
@@ -5190,7 +5345,8 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
5190
5345
|
return toLlmError(failure, cause);
|
|
5191
5346
|
};
|
|
5192
5347
|
if (sessionId2 !== void 0) this.deps.events.started(sessionId2, options.model);
|
|
5193
|
-
|
|
5348
|
+
const written = options.purpose === void 0 ? userTurns(options.messages) : null;
|
|
5349
|
+
if (sessionId2 !== void 0 && written !== null) this.deps.noteUserTexts?.(sessionId2, written);
|
|
5194
5350
|
try {
|
|
5195
5351
|
let credential = await this.deps.auth.credential();
|
|
5196
5352
|
if (credential === void 0) {
|
|
@@ -5299,8 +5455,8 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
5299
5455
|
answered = true;
|
|
5300
5456
|
if (sessionId2 !== void 0) this.deps.events.output(sessionId2);
|
|
5301
5457
|
},
|
|
5302
|
-
onUsage: (usage2) => {
|
|
5303
|
-
if (sessionId2 !== void 0) this.deps.events.usage(sessionId2, options.model, usage2);
|
|
5458
|
+
onUsage: (usage2, costUsd) => {
|
|
5459
|
+
if (sessionId2 !== void 0) this.deps.events.usage(sessionId2, options.model, usage2, { costUsd, ...written === null ? {} : { turn: written.length } });
|
|
5304
5460
|
},
|
|
5305
5461
|
onError: (payload) => fail2(classifyFailure(null, payload, response?.headers ?? null, name2, { autoSleep: this.deps.autoSleep?.(options.model) === true }))
|
|
5306
5462
|
});
|
|
@@ -5327,7 +5483,7 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
5327
5483
|
|
|
5328
5484
|
// src/host/commands.ts
|
|
5329
5485
|
var HELP = [
|
|
5330
|
-
"/adaptiq \u2014 workspace, models
|
|
5486
|
+
"/adaptiq \u2014 workspace, models and memory",
|
|
5331
5487
|
"/adaptiq signin \u2014 connect your AdaptiqAI account in the browser",
|
|
5332
5488
|
"/adaptiq private \u2014 stop saving new messages of this conversation",
|
|
5333
5489
|
"/adaptiq remember \u2014 save this conversation to memory again",
|
|
@@ -5433,10 +5589,9 @@ ${HELP}`;
|
|
|
5433
5589
|
lines.push("No models yet. Pick one in Settings \u2192 AdaptiqAI.");
|
|
5434
5590
|
} else {
|
|
5435
5591
|
for (const model2 of snapshot.models) {
|
|
5436
|
-
const lanes = model2.lanes === null ? "" : ` \xB7 ${model2.lanes} ${model2.lanes === 1 ? "lane" : "lanes"}`;
|
|
5437
5592
|
const live = model2.runningNow === null ? "" : ` (${model2.runningNow} running, ${model2.waitingNow ?? 0} waiting)`;
|
|
5438
5593
|
const window = model2.contextWindow === null ? "" : ` \xB7 ${formatTokens(model2.contextWindow)} context`;
|
|
5439
|
-
lines.push(`\u2022 ${model2.name}${window}${
|
|
5594
|
+
lines.push(`\u2022 ${model2.name}${window}${live}${model2.status === "offline" ? " \xB7 offline" : ""}`);
|
|
5440
5595
|
}
|
|
5441
5596
|
}
|
|
5442
5597
|
if (memory?.available === true && memory.conversationsTokens !== null) {
|
|
@@ -5770,7 +5925,7 @@ var render = (_args, value) => {
|
|
|
5770
5925
|
return [{ type: "text", text: typeof text2 === "string" ? text2 : JSON.stringify(value) }];
|
|
5771
5926
|
};
|
|
5772
5927
|
var say2 = (result) => ({ result });
|
|
5773
|
-
var
|
|
5928
|
+
var SOURCE_LIMIT2 = 6 * 1024 * 1024;
|
|
5774
5929
|
var MEDIA = {
|
|
5775
5930
|
".pdf": "application/pdf",
|
|
5776
5931
|
".txt": "text/plain",
|
|
@@ -6027,7 +6182,7 @@ ${content}`);
|
|
|
6027
6182
|
const info = await stat(path);
|
|
6028
6183
|
if (!info.isFile()) fail(`${raw} is not a file.`);
|
|
6029
6184
|
bytes += info.size;
|
|
6030
|
-
if (bytes >
|
|
6185
|
+
if (bytes > SOURCE_LIMIT2) fail("These files are too large for one request. Use fewer or smaller files, or a repository link.");
|
|
6031
6186
|
const content = await readFile2(path);
|
|
6032
6187
|
files.push({ name: source.name ?? basename(path), mediaType: mediaTypeOf(path), contentBase64: content.toString("base64") });
|
|
6033
6188
|
} else {
|
|
@@ -6273,7 +6428,7 @@ Open **Settings \u2192 AdaptiqAI** to connect, or run \`/adaptiq signin\`.
|
|
|
6273
6428
|
var ENTRY_PROTOCOL = 1;
|
|
6274
6429
|
var RELOAD_SIGNATURE = true ? "ada3dfffa1b3d7b1" : "source";
|
|
6275
6430
|
function pluginVersion() {
|
|
6276
|
-
if (true) return "0.2.
|
|
6431
|
+
if (true) return "0.2.15";
|
|
6277
6432
|
try {
|
|
6278
6433
|
return createRequire(import.meta.url)("../package.json").version;
|
|
6279
6434
|
} catch {
|