@adaptiqai/deepseek-harness 0.2.14 → 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 +1 -1
- package/lib/client.js +4 -4
- package/lib/host.js +252 -96
- package/lib/types/client/MemoryPill.d.ts +11 -1
- package/lib/types/client/pill.d.ts +23 -1
- package/lib/types/host/stream.d.ts +2 -1
- package/package.json +2 -2
package/lib/host.js
CHANGED
|
@@ -152,7 +152,7 @@ function classifyFailure(status, raw, headers, model2, options = {}) {
|
|
|
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")) {
|
|
@@ -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;
|
|
608
|
-
continue;
|
|
609
|
-
}
|
|
610
|
-
if (response.status === 202)
|
|
611
|
-
continue;
|
|
612
|
-
if (response.status === 429) {
|
|
613
|
-
const retry = Number(response.headers.get("retry-after") ?? 0) * 1e3;
|
|
614
|
-
delay = Math.max(interval, retry) + 250;
|
|
655
|
+
const answer = await pollDeviceCode(this.client(flow.signal), { deviceCode, interval });
|
|
656
|
+
if (answer.state === "waiting") {
|
|
657
|
+
delay = answer.delayMs;
|
|
615
658
|
continue;
|
|
616
659
|
}
|
|
617
|
-
if (
|
|
618
|
-
|
|
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." });
|
|
660
|
+
if (answer.state !== "approved") {
|
|
661
|
+
this.fail(flow, { code: answer.state, message: answer.message });
|
|
624
662
|
return;
|
|
625
663
|
}
|
|
626
|
-
if (
|
|
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}).` });
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
const body = await readJson(response);
|
|
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";
|
|
@@ -1108,6 +1203,22 @@ var en = {
|
|
|
1108
1203
|
popKnowledge: "Knowledge",
|
|
1109
1204
|
addKnowledge: "Add knowledge",
|
|
1110
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}",
|
|
1111
1222
|
openInKnowledge: "Open in Knowledge",
|
|
1112
1223
|
kTitle: "Knowledge",
|
|
1113
1224
|
kSearch: "Search your knowledge",
|
|
@@ -1587,6 +1698,21 @@ function button(id, label2, extra = {}) {
|
|
|
1587
1698
|
return { id, label: en[label2], labelKey: label2, ...extra };
|
|
1588
1699
|
}
|
|
1589
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
|
+
}
|
|
1590
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.";
|
|
1591
1717
|
var ATTACH_TRIES = 3;
|
|
1592
1718
|
function transient(error) {
|
|
@@ -1952,6 +2078,7 @@ var Workspace = class {
|
|
|
1952
2078
|
listeners = /* @__PURE__ */ new Set();
|
|
1953
2079
|
state = { preferences: DEFAULT_PREFERENCES, sessions: {} };
|
|
1954
2080
|
saving = Promise.resolve();
|
|
2081
|
+
persistTimer;
|
|
1955
2082
|
refreshing = null;
|
|
1956
2083
|
timer;
|
|
1957
2084
|
pendingAttach = /* @__PURE__ */ new Map();
|
|
@@ -2011,7 +2138,8 @@ var Workspace = class {
|
|
|
2011
2138
|
preferences: { ...DEFAULT_PREFERENCES, ...saved.preferences },
|
|
2012
2139
|
sessions: typeof saved.sessions === "object" && saved.sessions !== null ? saved.sessions : {},
|
|
2013
2140
|
purchase: saved.purchase ?? null,
|
|
2014
|
-
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {}
|
|
2141
|
+
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {},
|
|
2142
|
+
processed: savedProcessed(saved.processed)
|
|
2015
2143
|
};
|
|
2016
2144
|
this.purchases.restore(saved.purchase);
|
|
2017
2145
|
}
|
|
@@ -2027,6 +2155,10 @@ var Workspace = class {
|
|
|
2027
2155
|
this.purchases.dispose();
|
|
2028
2156
|
clearTimeout(this.timer);
|
|
2029
2157
|
clearTimeout(this.attachTimer);
|
|
2158
|
+
if (this.persistTimer !== void 0) {
|
|
2159
|
+
clearTimeout(this.persistTimer);
|
|
2160
|
+
void this.persist();
|
|
2161
|
+
}
|
|
2030
2162
|
for (const session of this.sessions.values()) {
|
|
2031
2163
|
clearTimeout(session.timer);
|
|
2032
2164
|
clearTimeout(session.waitTimer);
|
|
@@ -2094,7 +2226,8 @@ var Workspace = class {
|
|
|
2094
2226
|
region: model2.region,
|
|
2095
2227
|
nativeMemory: model2.nativeMemory,
|
|
2096
2228
|
tools: model2.tools,
|
|
2097
|
-
memory: this.modelMemory.get(model2.id) ?? null
|
|
2229
|
+
memory: this.modelMemory.get(model2.id) ?? null,
|
|
2230
|
+
prices: model2.prices
|
|
2098
2231
|
};
|
|
2099
2232
|
}
|
|
2100
2233
|
/**
|
|
@@ -2704,12 +2837,16 @@ var Workspace = class {
|
|
|
2704
2837
|
return next;
|
|
2705
2838
|
}
|
|
2706
2839
|
async persist() {
|
|
2840
|
+
clearTimeout(this.persistTimer);
|
|
2841
|
+
this.persistTimer = void 0;
|
|
2707
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);
|
|
2708
2844
|
const snapshot = {
|
|
2709
2845
|
preferences: this.state.preferences,
|
|
2710
2846
|
sessions: Object.fromEntries(entries),
|
|
2711
2847
|
purchase: this.state.purchase ?? null,
|
|
2712
|
-
...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) }
|
|
2713
2850
|
};
|
|
2714
2851
|
this.saving = this.saving.then(() => this.deps.store.save(snapshot)).catch((error) => {
|
|
2715
2852
|
this.deps.log?.("warn", `adaptiq: could not save preferences: ${String(error)}`);
|
|
@@ -2820,6 +2957,7 @@ var Workspace = class {
|
|
|
2820
2957
|
saved: session.saved,
|
|
2821
2958
|
optimizing: session.optimizing,
|
|
2822
2959
|
lastTurn: session.lastTurn,
|
|
2960
|
+
processed: processedSummary(this.state.processed?.[id]),
|
|
2823
2961
|
knowledge: [...session.knowledge, ...[...session.pendingKnowledge.values()].filter((item) => !session.knowledge.some((entry) => entry.id === item.id))],
|
|
2824
2962
|
conversations: [...session.conversations, ...[...session.pendingConversations.values()].filter((item) => !session.conversations.some((entry) => entry.id === item.id))],
|
|
2825
2963
|
known: session.exists,
|
|
@@ -3199,10 +3337,19 @@ var Workspace = class {
|
|
|
3199
3337
|
this.setPhase(session, "responding");
|
|
3200
3338
|
this.clearNotices("busy", "preparing", "offline", "retrying");
|
|
3201
3339
|
}
|
|
3202
|
-
usage(sessionId2, model2, usage2) {
|
|
3340
|
+
usage(sessionId2, model2, usage2, step = {}) {
|
|
3203
3341
|
if (sessionId2 === void 0)
|
|
3204
3342
|
return;
|
|
3205
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
|
+
}
|
|
3206
3353
|
session.lastTurn = {
|
|
3207
3354
|
fromMemory: usage2.cacheReadTokens ?? 0,
|
|
3208
3355
|
newInput: usage2.inputTokens,
|
|
@@ -4542,6 +4689,12 @@ function mapUsage(raw) {
|
|
|
4542
4689
|
...total > 0 ? { totalTokens: total } : prompt + output > 0 ? { totalTokens: prompt + output } : {}
|
|
4543
4690
|
};
|
|
4544
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
|
+
}
|
|
4545
4698
|
function memoryNotice(raw) {
|
|
4546
4699
|
let value = raw;
|
|
4547
4700
|
if (typeof raw === "string") {
|
|
@@ -4573,6 +4726,7 @@ async function* translate(events, hooks) {
|
|
|
4573
4726
|
let reasoningField = null;
|
|
4574
4727
|
let finish = null;
|
|
4575
4728
|
let usage2 = null;
|
|
4729
|
+
let costUsd = null;
|
|
4576
4730
|
let started = false;
|
|
4577
4731
|
let nextIndex = 0;
|
|
4578
4732
|
const closed = /* @__PURE__ */ new Set();
|
|
@@ -4618,6 +4772,7 @@ async function* translate(events, hooks) {
|
|
|
4618
4772
|
}
|
|
4619
4773
|
if (typeof payload.usage === "object" && payload.usage !== null) {
|
|
4620
4774
|
usage2 = mapUsage(payload.usage);
|
|
4775
|
+
costUsd = usageCost(payload.usage);
|
|
4621
4776
|
}
|
|
4622
4777
|
const choices = Array.isArray(payload.choices) ? payload.choices : [];
|
|
4623
4778
|
const choice = choices[0];
|
|
@@ -4679,7 +4834,7 @@ async function* translate(events, hooks) {
|
|
|
4679
4834
|
throw hooks.onError({ error: { message: "The model returned no reply.", type: "empty_response", code: "EMPTY_RESPONSE" } });
|
|
4680
4835
|
}
|
|
4681
4836
|
if (usage2 !== null) {
|
|
4682
|
-
hooks.onUsage?.(usage2);
|
|
4837
|
+
hooks.onUsage?.(usage2, costUsd);
|
|
4683
4838
|
yield { type: "usage", usage: usage2 };
|
|
4684
4839
|
}
|
|
4685
4840
|
const hasTools = blocks.some((block) => block.kind === "tool-call");
|
|
@@ -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
|
});
|
|
@@ -6272,7 +6428,7 @@ Open **Settings \u2192 AdaptiqAI** to connect, or run \`/adaptiq signin\`.
|
|
|
6272
6428
|
var ENTRY_PROTOCOL = 1;
|
|
6273
6429
|
var RELOAD_SIGNATURE = true ? "ada3dfffa1b3d7b1" : "source";
|
|
6274
6430
|
function pluginVersion() {
|
|
6275
|
-
if (true) return "0.2.
|
|
6431
|
+
if (true) return "0.2.15";
|
|
6276
6432
|
try {
|
|
6277
6433
|
return createRequire(import.meta.url)("../package.json").version;
|
|
6278
6434
|
} catch {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AccountSnapshot, SessionView } from '@adaptiqai/core/types';
|
|
1
|
+
import type { AccountSnapshot, ProcessedSummary, SessionView, TokenPrices } from '@adaptiqai/core/types';
|
|
2
2
|
import type { Kit } from './actions.ts';
|
|
3
3
|
import { type UseProjection } from './model.ts';
|
|
4
4
|
import { type T } from './ui.tsx';
|
|
@@ -13,6 +13,16 @@ export interface PillProps {
|
|
|
13
13
|
}
|
|
14
14
|
/** The pill in the composer toolbar. */
|
|
15
15
|
export declare function MemoryPill({ t, kit, sessionId, useAqAccount, useAqSession, useProjection }: PillProps): import("react").JSX.Element | null;
|
|
16
|
+
/**
|
|
17
|
+
* What the conversation's requests processed: the latest turn (every agent
|
|
18
|
+
* step since the person's last message) and the whole conversation. Apart from
|
|
19
|
+
* the memory's size, since each step reads all of it again.
|
|
20
|
+
*/
|
|
21
|
+
export declare function ProcessedSection({ t, processed, prices }: {
|
|
22
|
+
t: T;
|
|
23
|
+
processed: ProcessedSummary;
|
|
24
|
+
prices: TokenPrices | null;
|
|
25
|
+
}): import("react").JSX.Element;
|
|
16
26
|
/**
|
|
17
27
|
* One calm line above the composer when the chosen model is not the one this
|
|
18
28
|
* conversation's memory lives on: switch back, or start fresh on the new model.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** The composer pill's words and timing, kept apart from React so they can be tested. */
|
|
2
|
-
import type { WaitKind } from '@adaptiqai/core/types';
|
|
2
|
+
import type { ProcessedView, TokenPrices, WaitKind } from '@adaptiqai/core/types';
|
|
3
3
|
type T = (key: string, params?: Record<string, unknown>) => string;
|
|
4
4
|
/** How long "+24.6k from memory" stays after a reply. */
|
|
5
5
|
export declare const AFTER_REPLY_MS = 4000;
|
|
@@ -56,4 +56,26 @@ export declare class AfterReply {
|
|
|
56
56
|
} | null): void;
|
|
57
57
|
dispose(): void;
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* The popover's one line on why processed tokens outgrow the memory, from the
|
|
61
|
+
* conversation's own numbers and its model's price for reading from memory.
|
|
62
|
+
* @param t - translate.
|
|
63
|
+
* @param view - the conversation's processed tokens.
|
|
64
|
+
* @param prices - the model's per-token prices, when known.
|
|
65
|
+
* @returns e.g. "Each step reads the whole memory again. 96% came from memory, which is free.", or null before anything was read from memory.
|
|
66
|
+
*/
|
|
67
|
+
export declare function processedExplain(t: T, view: ProcessedView, prices: TokenPrices | null): string | null;
|
|
68
|
+
/**
|
|
69
|
+
* How many requests (agent steps) a column counts.
|
|
70
|
+
* @param t - translate.
|
|
71
|
+
* @param count - requests.
|
|
72
|
+
* @returns e.g. "85 steps".
|
|
73
|
+
*/
|
|
74
|
+
export declare function stepsText(t: T, count: number): string;
|
|
75
|
+
/**
|
|
76
|
+
* A processed cost, or a dash where a request had no price.
|
|
77
|
+
* @param usd - USD, or null.
|
|
78
|
+
* @returns e.g. "$0.24".
|
|
79
|
+
*/
|
|
80
|
+
export declare function costText(usd: number | null): string;
|
|
59
81
|
export {};
|
|
@@ -16,7 +16,8 @@ export interface TranslateHooks {
|
|
|
16
16
|
onFirstOutput?(): void;
|
|
17
17
|
/** An in-band error: map it to the thrown failure. */
|
|
18
18
|
onError(payload: Record<string, unknown>): Error;
|
|
19
|
-
|
|
19
|
+
/** The request's usage, and what the gateway charged for it when the answer says (USD). */
|
|
20
|
+
onUsage?(usage: TokenUsage, costUsd: number | null): void;
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Translate decoded SSE events into harness stream chunks.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptiqai/deepseek-harness",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.15",
|
|
4
4
|
"description": "AdaptiqAI for DeepSeek Harness: models with 5M-token native memory and Knowledge. Sign up, get a model and work without leaving the harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
"react-dom": "~18.3.1",
|
|
91
91
|
"typescript": "~5.9.3",
|
|
92
92
|
"vitest": "~3.2.7",
|
|
93
|
-
"@adaptiqai/core": "0.2.
|
|
93
|
+
"@adaptiqai/core": "0.2.11"
|
|
94
94
|
},
|
|
95
95
|
"repository": {
|
|
96
96
|
"type": "git",
|