@adaptiqai/pi 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +239 -92
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -100,7 +100,7 @@ function classifyFailure(status, raw, headers, model2, options = {}) {
|
|
|
100
100
|
if (effective === 503 && detail.code !== null && MODEL_OFFLINE_CODES.includes(detail.code)) {
|
|
101
101
|
return make(CODES.server, `${model2 ?? "This model"} is offline right now. It will retry automatically.`, "retrying");
|
|
102
102
|
}
|
|
103
|
-
if (has(detail, "AdaptiqNativePreflightBusy", "session_route_unavailable", "conversation_preparing", "preparing", "upload_capacity_exhausted") || effective === 503 && !has(detail, "offline")) {
|
|
103
|
+
if (has(detail, "AdaptiqNativePreflightBusy", "session_route_unavailable", "conversation_preparing", "preparing", "upload_capacity_exhausted", "AdaptiqMemoryNotReady") || effective === 425 || effective === 503 && !has(detail, "offline")) {
|
|
104
104
|
return make(CODES.preparing, "AdaptiqAI is getting your conversation ready. It will retry automatically.", "preparing");
|
|
105
105
|
}
|
|
106
106
|
if (effective === 409 && has(detail, "AdaptiqNativePreflight", "conversation")) {
|
|
@@ -317,6 +317,91 @@ function detailMessage(raw) {
|
|
|
317
317
|
}
|
|
318
318
|
return null;
|
|
319
319
|
}
|
|
320
|
+
var EXPIRED = "The sign-in link expired. Start again.";
|
|
321
|
+
async function startDeviceCode(client, request) {
|
|
322
|
+
let response;
|
|
323
|
+
try {
|
|
324
|
+
response = await client.fetch(`${client.apiBase}/v1/cli-auth/device`, {
|
|
325
|
+
method: "POST",
|
|
326
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
327
|
+
body: JSON.stringify({
|
|
328
|
+
client_app: request.app,
|
|
329
|
+
client_name: request.app,
|
|
330
|
+
device_name: request.device,
|
|
331
|
+
client_binding: request.binding,
|
|
332
|
+
...request.tokenLifetime === void 0 ? {} : { token_lifetime: request.tokenLifetime }
|
|
333
|
+
}),
|
|
334
|
+
signal: client.signal === void 0 ? AbortSignal.timeout(2e4) : AbortSignal.any([client.signal, AbortSignal.timeout(2e4)]),
|
|
335
|
+
redirect: "error"
|
|
336
|
+
});
|
|
337
|
+
} catch (error) {
|
|
338
|
+
if (client.signal?.aborted === true)
|
|
339
|
+
throw error;
|
|
340
|
+
throw new Error(UNREACHABLE, { cause: error });
|
|
341
|
+
}
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
const message = detailMessage(await readJson(response));
|
|
344
|
+
if (response.status >= 500)
|
|
345
|
+
throw new Error("AdaptiqAI isn't answering right now. Try again in a minute.");
|
|
346
|
+
throw new Error(message ?? `AdaptiqAI sign-in could not start (HTTP ${response.status}).`);
|
|
347
|
+
}
|
|
348
|
+
const body = await readJson(response);
|
|
349
|
+
const deviceCode = String(body?.device_code ?? "");
|
|
350
|
+
const userCode = String(body?.user_code ?? "");
|
|
351
|
+
const url = String(body?.verification_uri_complete ?? body?.verification_uri ?? "");
|
|
352
|
+
if (deviceCode === "" || userCode === "" || !/^https?:\/\//u.test(url))
|
|
353
|
+
throw new Error("AdaptiqAI returned an incomplete sign-in.");
|
|
354
|
+
return {
|
|
355
|
+
deviceCode,
|
|
356
|
+
userCode,
|
|
357
|
+
url,
|
|
358
|
+
expiresAt: client.now() + Math.min(DEVICE_TIMEOUT_MS, Math.max(60, Number(body?.expires_in ?? 600)) * 1e3),
|
|
359
|
+
interval: Math.max(1, Number(body?.interval ?? 2)) * 1e3
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
async function pollDeviceCode(client, code, extra = {}) {
|
|
363
|
+
let response;
|
|
364
|
+
try {
|
|
365
|
+
response = await client.fetch(`${client.apiBase}/v1/cli-auth/device/token`, {
|
|
366
|
+
method: "POST",
|
|
367
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
368
|
+
body: JSON.stringify({ ...extra, device_code: code.deviceCode }),
|
|
369
|
+
signal: client.signal === void 0 ? AbortSignal.timeout(2e4) : AbortSignal.any([client.signal, AbortSignal.timeout(2e4)]),
|
|
370
|
+
redirect: "error"
|
|
371
|
+
});
|
|
372
|
+
} catch {
|
|
373
|
+
return { state: "waiting", delayMs: code.interval * 2 };
|
|
374
|
+
}
|
|
375
|
+
if (response.status === 202)
|
|
376
|
+
return { state: "waiting", delayMs: code.interval };
|
|
377
|
+
if (response.status === 429) {
|
|
378
|
+
const retry = Number(response.headers.get("retry-after") ?? 0) * 1e3;
|
|
379
|
+
return { state: "waiting", delayMs: Math.max(code.interval, retry) + 250 };
|
|
380
|
+
}
|
|
381
|
+
if (response.status === 403) {
|
|
382
|
+
const raw = await readJson(response);
|
|
383
|
+
return { state: "denied", message: detailCode(raw) === "access_denied" ? "The connection was declined in the browser." : detailMessage(raw) ?? "The connection was declined." };
|
|
384
|
+
}
|
|
385
|
+
if (response.status === 410 || response.status === 404)
|
|
386
|
+
return { state: "expired", message: EXPIRED };
|
|
387
|
+
if (!response.ok) {
|
|
388
|
+
if (response.status >= 500)
|
|
389
|
+
return { state: "waiting", delayMs: code.interval * 2 };
|
|
390
|
+
return { state: "failed", message: detailMessage(await readJson(response)) ?? `Sign-in failed (HTTP ${response.status}).` };
|
|
391
|
+
}
|
|
392
|
+
const body = await readJson(response);
|
|
393
|
+
const access = String(body?.access_token ?? "");
|
|
394
|
+
const refresh = String(body?.refresh_token ?? "");
|
|
395
|
+
if (!access.startsWith("ak_") || refresh !== "" && !refresh.startsWith("akr_"))
|
|
396
|
+
return { state: "failed", message: "AdaptiqAI returned an invalid credential." };
|
|
397
|
+
return {
|
|
398
|
+
state: "approved",
|
|
399
|
+
access,
|
|
400
|
+
refresh: refresh === "" ? null : refresh,
|
|
401
|
+
expiresIn: Math.max(60, Number(body?.expires_in ?? 3600)),
|
|
402
|
+
workspaceLabel: typeof body?.workspace_label === "string" && body.workspace_label !== "" ? body.workspace_label : "Your workspace"
|
|
403
|
+
};
|
|
404
|
+
}
|
|
320
405
|
var AuthManager = class {
|
|
321
406
|
options;
|
|
322
407
|
fetch;
|
|
@@ -359,6 +444,9 @@ var AuthManager = class {
|
|
|
359
444
|
this.state = phase;
|
|
360
445
|
this.options.onChange?.();
|
|
361
446
|
}
|
|
447
|
+
client(signal) {
|
|
448
|
+
return { apiBase: this.options.apiBase, fetch: this.fetch, now: this.now, signal };
|
|
449
|
+
}
|
|
362
450
|
/** Read the stored state once at startup. */
|
|
363
451
|
async init() {
|
|
364
452
|
const stored = await this.options.store.read();
|
|
@@ -492,39 +580,11 @@ var AuthManager = class {
|
|
|
492
580
|
const clientProof = `${randomUUID()}${randomUUID()}`;
|
|
493
581
|
const binding = createHash("sha256").update(clientProof).digest("hex");
|
|
494
582
|
const app = this.options.appName ?? "DeepSeek Harness";
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
body: JSON.stringify({
|
|
501
|
-
client_app: app,
|
|
502
|
-
client_name: app,
|
|
503
|
-
device_name: deviceLabel(this.options.deviceName ?? hostname()),
|
|
504
|
-
client_binding: binding
|
|
505
|
-
}),
|
|
506
|
-
signal: AbortSignal.any([flow.signal, AbortSignal.timeout(2e4)]),
|
|
507
|
-
redirect: "error"
|
|
508
|
-
});
|
|
509
|
-
} catch (error) {
|
|
510
|
-
if (flow.signal.aborted)
|
|
511
|
-
throw error;
|
|
512
|
-
throw new Error(UNREACHABLE, { cause: error });
|
|
513
|
-
}
|
|
514
|
-
if (!response.ok) {
|
|
515
|
-
const message = detailMessage(await readJson(response));
|
|
516
|
-
if (response.status >= 500)
|
|
517
|
-
throw new Error("AdaptiqAI isn't answering right now. Try again in a minute.");
|
|
518
|
-
throw new Error(message ?? `AdaptiqAI sign-in could not start (HTTP ${response.status}).`);
|
|
519
|
-
}
|
|
520
|
-
const body = await readJson(response);
|
|
521
|
-
const deviceCode = String(body?.device_code ?? "");
|
|
522
|
-
const userCode = String(body?.user_code ?? "");
|
|
523
|
-
const url = String(body?.verification_uri_complete ?? body?.verification_uri ?? "");
|
|
524
|
-
if (deviceCode === "" || userCode === "" || !/^https?:\/\//u.test(url))
|
|
525
|
-
throw new Error("AdaptiqAI returned an incomplete sign-in.");
|
|
526
|
-
const expiresAt = this.now() + Math.min(DEVICE_TIMEOUT_MS, Math.max(60, Number(body?.expires_in ?? 600)) * 1e3);
|
|
527
|
-
const interval = Math.max(1, Number(body?.interval ?? 2)) * 1e3;
|
|
583
|
+
const { deviceCode, userCode, url, expiresAt, interval } = await startDeviceCode(this.client(flow.signal), {
|
|
584
|
+
app,
|
|
585
|
+
device: deviceLabel(this.options.deviceName ?? hostname()),
|
|
586
|
+
binding
|
|
587
|
+
});
|
|
528
588
|
this.pendingSignIn = { url, userCode, expiresAt };
|
|
529
589
|
this.set("signing-in");
|
|
530
590
|
void this.poll(flow, deviceCode, clientProof, interval, expiresAt);
|
|
@@ -536,61 +596,27 @@ var AuthManager = class {
|
|
|
536
596
|
while (this.now() < expiresAt) {
|
|
537
597
|
await this.sleep(delay, flow.signal);
|
|
538
598
|
delay = interval;
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
method: "POST",
|
|
543
|
-
headers: { "content-type": "application/json", accept: "application/json" },
|
|
544
|
-
body: JSON.stringify({ device_code: deviceCode }),
|
|
545
|
-
signal: AbortSignal.any([flow.signal, AbortSignal.timeout(2e4)]),
|
|
546
|
-
redirect: "error"
|
|
547
|
-
});
|
|
548
|
-
} catch {
|
|
549
|
-
if (flow.signal.aborted)
|
|
550
|
-
return;
|
|
551
|
-
delay = interval * 2;
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
if (response.status === 202)
|
|
555
|
-
continue;
|
|
556
|
-
if (response.status === 429) {
|
|
557
|
-
const retry = Number(response.headers.get("retry-after") ?? 0) * 1e3;
|
|
558
|
-
delay = Math.max(interval, retry) + 250;
|
|
599
|
+
const answer = await pollDeviceCode(this.client(flow.signal), { deviceCode, interval });
|
|
600
|
+
if (answer.state === "waiting") {
|
|
601
|
+
delay = answer.delayMs;
|
|
559
602
|
continue;
|
|
560
603
|
}
|
|
561
|
-
if (
|
|
562
|
-
|
|
563
|
-
this.fail(flow, { code: "denied", message: detailCode(raw) === "access_denied" ? "The connection was declined in the browser." : detailMessage(raw) ?? "The connection was declined." });
|
|
604
|
+
if (answer.state !== "approved") {
|
|
605
|
+
this.fail(flow, { code: answer.state, message: answer.message });
|
|
564
606
|
return;
|
|
565
607
|
}
|
|
566
|
-
if (
|
|
567
|
-
this.fail(flow, { code: "expired", message: "The sign-in link expired. Start again." });
|
|
568
|
-
return;
|
|
569
|
-
}
|
|
570
|
-
if (!response.ok) {
|
|
571
|
-
if (response.status >= 500) {
|
|
572
|
-
delay = interval * 2;
|
|
573
|
-
continue;
|
|
574
|
-
}
|
|
575
|
-
this.fail(flow, { code: "failed", message: detailMessage(await readJson(response)) ?? `Sign-in failed (HTTP ${response.status}).` });
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
const body = await readJson(response);
|
|
579
|
-
const access = String(body?.access_token ?? "");
|
|
580
|
-
const refresh = String(body?.refresh_token ?? "");
|
|
581
|
-
if (!access.startsWith("ak_") || !refresh.startsWith("akr_")) {
|
|
608
|
+
if (answer.refresh === null) {
|
|
582
609
|
this.fail(flow, { code: "failed", message: "AdaptiqAI returned an invalid credential." });
|
|
583
610
|
return;
|
|
584
611
|
}
|
|
585
|
-
const workspaceLabel = typeof body?.workspace_label === "string" && body.workspace_label !== "" ? body.workspace_label : "Your workspace";
|
|
586
612
|
const grant = {
|
|
587
613
|
schema: "adaptiq-dsh-grant-v1",
|
|
588
614
|
apiBase: this.options.apiBase,
|
|
589
|
-
access,
|
|
590
|
-
refresh,
|
|
615
|
+
access: answer.access,
|
|
616
|
+
refresh: answer.refresh,
|
|
591
617
|
clientProof,
|
|
592
|
-
expiresAt: this.now() +
|
|
593
|
-
workspaceLabel,
|
|
618
|
+
expiresAt: this.now() + answer.expiresIn * 1e3,
|
|
619
|
+
workspaceLabel: answer.workspaceLabel,
|
|
594
620
|
obtainedAt: this.now()
|
|
595
621
|
};
|
|
596
622
|
await this.options.store.modify(async () => grant);
|
|
@@ -599,12 +625,12 @@ var AuthManager = class {
|
|
|
599
625
|
this.flow = null;
|
|
600
626
|
this.pendingSignIn = null;
|
|
601
627
|
this.source = "device";
|
|
602
|
-
this.label = workspaceLabel;
|
|
628
|
+
this.label = answer.workspaceLabel;
|
|
603
629
|
this.set("connected");
|
|
604
|
-
this.options.onSignedIn?.(workspaceLabel);
|
|
630
|
+
this.options.onSignedIn?.(answer.workspaceLabel);
|
|
605
631
|
return;
|
|
606
632
|
}
|
|
607
|
-
this.fail(flow, { code: "expired", message:
|
|
633
|
+
this.fail(flow, { code: "expired", message: EXPIRED });
|
|
608
634
|
} catch (error) {
|
|
609
635
|
if (flow.signal.aborted)
|
|
610
636
|
return;
|
|
@@ -729,6 +755,20 @@ var obj = (value) => typeof value === "object" && value !== null && !Array.isArr
|
|
|
729
755
|
var str = (value) => typeof value === "string" && value.trim() !== "" ? value.trim() : null;
|
|
730
756
|
var num = (value) => typeof value === "number" && Number.isFinite(value) && value > 0 ? value : null;
|
|
731
757
|
var count = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
758
|
+
function pricesFromRow(raw) {
|
|
759
|
+
const pricing = obj(raw);
|
|
760
|
+
const price = (value) => {
|
|
761
|
+
const parsed = typeof value === "string" && value.trim() !== "" ? Number(value) : typeof value === "number" ? value : Number.NaN;
|
|
762
|
+
return Number.isFinite(parsed) && parsed >= 0 ? parsed : null;
|
|
763
|
+
};
|
|
764
|
+
const input = price(pricing?.prompt);
|
|
765
|
+
const memoryWrite = price(pricing?.input_cache_write);
|
|
766
|
+
const memoryRead = price(pricing?.input_cache_read);
|
|
767
|
+
const output = price(pricing?.completion);
|
|
768
|
+
if (input === null || memoryWrite === null || memoryRead === null || output === null)
|
|
769
|
+
return null;
|
|
770
|
+
return { input, memoryWrite, memoryRead, output };
|
|
771
|
+
}
|
|
732
772
|
var LEVEL_NAMES = {
|
|
733
773
|
off: "Off",
|
|
734
774
|
minimal: "Minimal",
|
|
@@ -817,17 +857,17 @@ function placementsFromRoutes(routes) {
|
|
|
817
857
|
const model2 = str(route?.model);
|
|
818
858
|
if (route === null || model2 === null || route.enabled !== true)
|
|
819
859
|
continue;
|
|
820
|
-
const
|
|
860
|
+
const add2 = (a, b) => a === null ? b : b === null ? a : a + b;
|
|
821
861
|
const current = out.get(model2);
|
|
822
862
|
const running = count(route.running);
|
|
823
863
|
const waiting = count(route.waiting);
|
|
824
864
|
out.set(model2, {
|
|
825
865
|
name: current?.name ?? (str(route.name) !== null ? routeModelName(str(route.name)) : null),
|
|
826
866
|
status: "running",
|
|
827
|
-
lanes:
|
|
828
|
-
maxParallel:
|
|
829
|
-
runningNow:
|
|
830
|
-
waitingNow:
|
|
867
|
+
lanes: add2(current?.lanes ?? null, count(route.lanes)),
|
|
868
|
+
maxParallel: add2(current?.maxParallel ?? null, count(route.max_parallel_agents)),
|
|
869
|
+
runningNow: add2(current?.runningNow ?? null, running),
|
|
870
|
+
waitingNow: add2(current?.waitingNow ?? null, waiting),
|
|
831
871
|
region: current?.region ?? str(route.region),
|
|
832
872
|
card: null,
|
|
833
873
|
contextWindow: null,
|
|
@@ -888,7 +928,8 @@ function model(id, row, placement) {
|
|
|
888
928
|
maxParallel: placement?.maxParallel ?? count(gateway?.max_parallel_agents),
|
|
889
929
|
runningNow: placement?.runningNow ?? null,
|
|
890
930
|
waitingNow: placement?.waitingNow ?? null,
|
|
891
|
-
region: placement?.region ?? str(gateway?.region)
|
|
931
|
+
region: placement?.region ?? str(gateway?.region),
|
|
932
|
+
prices: pricesFromRow(row?.pricing)
|
|
892
933
|
};
|
|
893
934
|
}
|
|
894
935
|
function selectableLevels(reasoning) {
|
|
@@ -957,6 +998,60 @@ function laneLimit(offer) {
|
|
|
957
998
|
return free < offer.minLanes ? 0 : Math.min(offer.maxLanes, free);
|
|
958
999
|
}
|
|
959
1000
|
|
|
1001
|
+
// ../core/lib/processed.js
|
|
1002
|
+
var NOTHING_PROCESSED = { requests: 0, newInput: 0, fromMemory: 0, written: 0, output: 0, reasoning: 0, costUsd: 0 };
|
|
1003
|
+
function stepCost(usage, prices) {
|
|
1004
|
+
if (prices === null)
|
|
1005
|
+
return null;
|
|
1006
|
+
return usage.inputTokens * prices.input + (usage.cacheWriteTokens ?? 0) * prices.memoryWrite + (usage.cacheReadTokens ?? 0) * prices.memoryRead + usage.outputTokens * prices.output;
|
|
1007
|
+
}
|
|
1008
|
+
function add(view, step) {
|
|
1009
|
+
return {
|
|
1010
|
+
requests: view.requests + 1,
|
|
1011
|
+
newInput: view.newInput + step.usage.inputTokens,
|
|
1012
|
+
fromMemory: view.fromMemory + (step.usage.cacheReadTokens ?? 0),
|
|
1013
|
+
written: view.written + (step.usage.cacheWriteTokens ?? 0),
|
|
1014
|
+
output: view.output + step.usage.outputTokens,
|
|
1015
|
+
reasoning: view.reasoning + (step.usage.reasoningTokens ?? 0),
|
|
1016
|
+
costUsd: view.costUsd === null || step.costUsd === null ? null : view.costUsd + step.costUsd
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function addStep(record, step, now) {
|
|
1020
|
+
const turnKey = step.turn ?? record?.turnKey ?? null;
|
|
1021
|
+
const fresh = record == null || step.turn !== void 0 && step.turn !== record.turnKey;
|
|
1022
|
+
return {
|
|
1023
|
+
since: record?.since ?? now,
|
|
1024
|
+
at: now,
|
|
1025
|
+
turnKey,
|
|
1026
|
+
turn: add(fresh ? NOTHING_PROCESSED : record.turn, step),
|
|
1027
|
+
session: add(record?.session ?? NOTHING_PROCESSED, step)
|
|
1028
|
+
};
|
|
1029
|
+
}
|
|
1030
|
+
function readProcessed(raw) {
|
|
1031
|
+
const record = typeof raw === "object" && raw !== null ? raw : null;
|
|
1032
|
+
const view = (value) => {
|
|
1033
|
+
const fields = typeof value === "object" && value !== null ? value : null;
|
|
1034
|
+
if (fields === null)
|
|
1035
|
+
return null;
|
|
1036
|
+
const count3 = (name) => {
|
|
1037
|
+
const field = fields[name];
|
|
1038
|
+
return typeof field === "number" && Number.isFinite(field) && field >= 0 ? field : null;
|
|
1039
|
+
};
|
|
1040
|
+
const numbers = { requests: count3("requests"), newInput: count3("newInput"), fromMemory: count3("fromMemory"), written: count3("written"), output: count3("output"), reasoning: count3("reasoning") };
|
|
1041
|
+
if (Object.values(numbers).some((value2) => value2 === null))
|
|
1042
|
+
return null;
|
|
1043
|
+
return { ...numbers, costUsd: count3("costUsd") };
|
|
1044
|
+
};
|
|
1045
|
+
const turn = view(record?.turn);
|
|
1046
|
+
const session = view(record?.session);
|
|
1047
|
+
const since = record?.since;
|
|
1048
|
+
const at = record?.at;
|
|
1049
|
+
if (turn === null || session === null || typeof since !== "number" || typeof at !== "number")
|
|
1050
|
+
return null;
|
|
1051
|
+
const turnKey = typeof record?.turnKey === "number" ? record.turnKey : null;
|
|
1052
|
+
return { since, at, turnKey, turn, session };
|
|
1053
|
+
}
|
|
1054
|
+
|
|
960
1055
|
// ../core/lib/relations.js
|
|
961
1056
|
var PARENT_SESSION_HEADER = "X-Adaptiq-Parent-Session-Id";
|
|
962
1057
|
var SESSION_ROLE_HEADER = "X-Adaptiq-Session-Role";
|
|
@@ -1045,6 +1140,22 @@ var en = {
|
|
|
1045
1140
|
popKnowledge: "Knowledge",
|
|
1046
1141
|
addKnowledge: "Add knowledge",
|
|
1047
1142
|
popWorkspace: "All memory on {model}",
|
|
1143
|
+
popSeesNow: "What the model sees now",
|
|
1144
|
+
procTitle: "Processed",
|
|
1145
|
+
procTurn: "Last turn",
|
|
1146
|
+
procSession: "This conversation",
|
|
1147
|
+
procSteps: "{count} steps",
|
|
1148
|
+
procStepsOne: "1 step",
|
|
1149
|
+
procNewInput: "New input",
|
|
1150
|
+
procFromMemory: "Read from memory",
|
|
1151
|
+
procWritten: "Saved to memory",
|
|
1152
|
+
procOutput: "Output",
|
|
1153
|
+
procThinking: "Thinking, part of output",
|
|
1154
|
+
procCost: "Cost",
|
|
1155
|
+
procExplain: "Each step reads the whole memory again. {percent} came from memory.",
|
|
1156
|
+
procExplainFree: "Each step reads the whole memory again. {percent} came from memory, which is free.",
|
|
1157
|
+
procExplainCheaper: "Each step reads the whole memory again. {percent} came from memory, at a fraction of the input price.",
|
|
1158
|
+
procSince: "Counted on this computer since {date}",
|
|
1048
1159
|
openInKnowledge: "Open in Knowledge",
|
|
1049
1160
|
kTitle: "Knowledge",
|
|
1050
1161
|
kSearch: "Search your knowledge",
|
|
@@ -1529,6 +1640,21 @@ function button(id, label, extra = {}) {
|
|
|
1529
1640
|
return { id, label: en[label], labelKey: label, ...extra };
|
|
1530
1641
|
}
|
|
1531
1642
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1643
|
+
var PROCESSED_SAVE_MS = 2e3;
|
|
1644
|
+
function savedProcessed(raw) {
|
|
1645
|
+
const out = {};
|
|
1646
|
+
if (typeof raw !== "object" || raw === null)
|
|
1647
|
+
return out;
|
|
1648
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
1649
|
+
const record = readProcessed(value);
|
|
1650
|
+
if (record !== null)
|
|
1651
|
+
out[id] = record;
|
|
1652
|
+
}
|
|
1653
|
+
return out;
|
|
1654
|
+
}
|
|
1655
|
+
function processedSummary(record) {
|
|
1656
|
+
return record === void 0 ? null : { turn: record.turn, session: record.session, since: record.since };
|
|
1657
|
+
}
|
|
1532
1658
|
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.";
|
|
1533
1659
|
var ATTACH_TRIES = 3;
|
|
1534
1660
|
function transient(error) {
|
|
@@ -1894,6 +2020,7 @@ var Workspace = class {
|
|
|
1894
2020
|
listeners = /* @__PURE__ */ new Set();
|
|
1895
2021
|
state = { preferences: DEFAULT_PREFERENCES, sessions: {} };
|
|
1896
2022
|
saving = Promise.resolve();
|
|
2023
|
+
persistTimer;
|
|
1897
2024
|
refreshing = null;
|
|
1898
2025
|
timer;
|
|
1899
2026
|
pendingAttach = /* @__PURE__ */ new Map();
|
|
@@ -1953,7 +2080,8 @@ var Workspace = class {
|
|
|
1953
2080
|
preferences: { ...DEFAULT_PREFERENCES, ...saved.preferences },
|
|
1954
2081
|
sessions: typeof saved.sessions === "object" && saved.sessions !== null ? saved.sessions : {},
|
|
1955
2082
|
purchase: saved.purchase ?? null,
|
|
1956
|
-
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {}
|
|
2083
|
+
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {},
|
|
2084
|
+
processed: savedProcessed(saved.processed)
|
|
1957
2085
|
};
|
|
1958
2086
|
this.purchases.restore(saved.purchase);
|
|
1959
2087
|
}
|
|
@@ -1969,6 +2097,10 @@ var Workspace = class {
|
|
|
1969
2097
|
this.purchases.dispose();
|
|
1970
2098
|
clearTimeout(this.timer);
|
|
1971
2099
|
clearTimeout(this.attachTimer);
|
|
2100
|
+
if (this.persistTimer !== void 0) {
|
|
2101
|
+
clearTimeout(this.persistTimer);
|
|
2102
|
+
void this.persist();
|
|
2103
|
+
}
|
|
1972
2104
|
for (const session of this.sessions.values()) {
|
|
1973
2105
|
clearTimeout(session.timer);
|
|
1974
2106
|
clearTimeout(session.waitTimer);
|
|
@@ -2036,7 +2168,8 @@ var Workspace = class {
|
|
|
2036
2168
|
region: model2.region,
|
|
2037
2169
|
nativeMemory: model2.nativeMemory,
|
|
2038
2170
|
tools: model2.tools,
|
|
2039
|
-
memory: this.modelMemory.get(model2.id) ?? null
|
|
2171
|
+
memory: this.modelMemory.get(model2.id) ?? null,
|
|
2172
|
+
prices: model2.prices
|
|
2040
2173
|
};
|
|
2041
2174
|
}
|
|
2042
2175
|
/**
|
|
@@ -2646,12 +2779,16 @@ var Workspace = class {
|
|
|
2646
2779
|
return next;
|
|
2647
2780
|
}
|
|
2648
2781
|
async persist() {
|
|
2782
|
+
clearTimeout(this.persistTimer);
|
|
2783
|
+
this.persistTimer = void 0;
|
|
2649
2784
|
const entries = Object.entries(this.state.sessions).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2785
|
+
const processed = Object.entries(this.state.processed ?? {}).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2650
2786
|
const snapshot = {
|
|
2651
2787
|
preferences: this.state.preferences,
|
|
2652
2788
|
sessions: Object.fromEntries(entries),
|
|
2653
2789
|
purchase: this.state.purchase ?? null,
|
|
2654
|
-
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel }
|
|
2790
|
+
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel },
|
|
2791
|
+
...processed.length === 0 ? {} : { processed: Object.fromEntries(processed) }
|
|
2655
2792
|
};
|
|
2656
2793
|
this.saving = this.saving.then(() => this.deps.store.save(snapshot)).catch((error) => {
|
|
2657
2794
|
this.deps.log?.("warn", `adaptiq: could not save preferences: ${String(error)}`);
|
|
@@ -2762,6 +2899,7 @@ var Workspace = class {
|
|
|
2762
2899
|
saved: session.saved,
|
|
2763
2900
|
optimizing: session.optimizing,
|
|
2764
2901
|
lastTurn: session.lastTurn,
|
|
2902
|
+
processed: processedSummary(this.state.processed?.[id]),
|
|
2765
2903
|
knowledge: [...session.knowledge, ...[...session.pendingKnowledge.values()].filter((item) => !session.knowledge.some((entry) => entry.id === item.id))],
|
|
2766
2904
|
conversations: [...session.conversations, ...[...session.pendingConversations.values()].filter((item) => !session.conversations.some((entry) => entry.id === item.id))],
|
|
2767
2905
|
known: session.exists,
|
|
@@ -3141,10 +3279,19 @@ var Workspace = class {
|
|
|
3141
3279
|
this.setPhase(session, "responding");
|
|
3142
3280
|
this.clearNotices("busy", "preparing", "offline", "retrying");
|
|
3143
3281
|
}
|
|
3144
|
-
usage(sessionId, model2, usage) {
|
|
3282
|
+
usage(sessionId, model2, usage, step = {}) {
|
|
3145
3283
|
if (sessionId === void 0)
|
|
3146
3284
|
return;
|
|
3147
3285
|
const session = this.session(sessionId);
|
|
3286
|
+
const costUsd = step.costUsd ?? stepCost(usage, this.catalog.find((entry) => entry.id === model2)?.prices ?? null);
|
|
3287
|
+
const counted = addStep(this.state.processed?.[sessionId], { usage, costUsd, ...step.turn === void 0 ? {} : { turn: step.turn } }, this.now());
|
|
3288
|
+
this.state = { ...this.state, processed: { ...this.state.processed, [sessionId]: counted } };
|
|
3289
|
+
if (this.persistTimer === void 0) {
|
|
3290
|
+
this.persistTimer = setTimeout(() => {
|
|
3291
|
+
void this.persist();
|
|
3292
|
+
}, PROCESSED_SAVE_MS);
|
|
3293
|
+
this.persistTimer.unref?.();
|
|
3294
|
+
}
|
|
3148
3295
|
session.lastTurn = {
|
|
3149
3296
|
fromMemory: usage.cacheReadTokens ?? 0,
|
|
3150
3297
|
newInput: usage.inputTokens,
|
|
@@ -4949,7 +5096,7 @@ function userTexts(messages) {
|
|
|
4949
5096
|
}
|
|
4950
5097
|
|
|
4951
5098
|
// src/index.ts
|
|
4952
|
-
var VERSION = true ? "0.1.
|
|
5099
|
+
var VERSION = true ? "0.1.1" : "0.0.0";
|
|
4953
5100
|
var ROUTE = "adaptiqai";
|
|
4954
5101
|
var PARENT_ENV = "ADAPTIQ_PARENT_SESSION_ID";
|
|
4955
5102
|
var SESSION_ID2 = /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptiqai/pi",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "AdaptiqAI for Pi: your workspace's models, conversations AdaptiqAI remembers, and your saved knowledge, in one Pi package.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"esbuild": "~0.25.12",
|
|
38
38
|
"typescript": "~5.9.3",
|
|
39
39
|
"vitest": "~3.2.7",
|
|
40
|
-
"@adaptiqai/core": "0.2.
|
|
40
|
+
"@adaptiqai/core": "0.2.11"
|
|
41
41
|
},
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "node scripts/build.mjs",
|