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