@adaptiqai/mcp 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/.claude-plugin/plugin.json +1 -1
- package/lib/index.js +242 -95
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -100,7 +100,7 @@ function classifyFailure(status2, 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 answer2 = await pollDeviceCode(this.client(flow.signal), { deviceCode, interval });
|
|
600
|
+
if (answer2.state === "waiting") {
|
|
601
|
+
delay = answer2.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 (answer2.state !== "approved") {
|
|
605
|
+
this.fail(flow, { code: answer2.state, message: answer2.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 (answer2.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: answer2.access,
|
|
616
|
+
refresh: answer2.refresh,
|
|
591
617
|
clientProof,
|
|
592
|
-
expiresAt: this.now() +
|
|
593
|
-
workspaceLabel,
|
|
618
|
+
expiresAt: this.now() + answer2.expiresIn * 1e3,
|
|
619
|
+
workspaceLabel: answer2.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 = answer2.workspaceLabel;
|
|
603
629
|
this.set("connected");
|
|
604
|
-
this.options.onSignedIn?.(workspaceLabel);
|
|
630
|
+
this.options.onSignedIn?.(answer2.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) {
|
|
@@ -948,6 +989,60 @@ function laneLimit(offer) {
|
|
|
948
989
|
return free < offer.minLanes ? 0 : Math.min(offer.maxLanes, free);
|
|
949
990
|
}
|
|
950
991
|
|
|
992
|
+
// ../core/lib/processed.js
|
|
993
|
+
var NOTHING_PROCESSED = { requests: 0, newInput: 0, fromMemory: 0, written: 0, output: 0, reasoning: 0, costUsd: 0 };
|
|
994
|
+
function stepCost(usage, prices) {
|
|
995
|
+
if (prices === null)
|
|
996
|
+
return null;
|
|
997
|
+
return usage.inputTokens * prices.input + (usage.cacheWriteTokens ?? 0) * prices.memoryWrite + (usage.cacheReadTokens ?? 0) * prices.memoryRead + usage.outputTokens * prices.output;
|
|
998
|
+
}
|
|
999
|
+
function add(view, step) {
|
|
1000
|
+
return {
|
|
1001
|
+
requests: view.requests + 1,
|
|
1002
|
+
newInput: view.newInput + step.usage.inputTokens,
|
|
1003
|
+
fromMemory: view.fromMemory + (step.usage.cacheReadTokens ?? 0),
|
|
1004
|
+
written: view.written + (step.usage.cacheWriteTokens ?? 0),
|
|
1005
|
+
output: view.output + step.usage.outputTokens,
|
|
1006
|
+
reasoning: view.reasoning + (step.usage.reasoningTokens ?? 0),
|
|
1007
|
+
costUsd: view.costUsd === null || step.costUsd === null ? null : view.costUsd + step.costUsd
|
|
1008
|
+
};
|
|
1009
|
+
}
|
|
1010
|
+
function addStep(record, step, now) {
|
|
1011
|
+
const turnKey = step.turn ?? record?.turnKey ?? null;
|
|
1012
|
+
const fresh = record == null || step.turn !== void 0 && step.turn !== record.turnKey;
|
|
1013
|
+
return {
|
|
1014
|
+
since: record?.since ?? now,
|
|
1015
|
+
at: now,
|
|
1016
|
+
turnKey,
|
|
1017
|
+
turn: add(fresh ? NOTHING_PROCESSED : record.turn, step),
|
|
1018
|
+
session: add(record?.session ?? NOTHING_PROCESSED, step)
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
function readProcessed(raw) {
|
|
1022
|
+
const record = typeof raw === "object" && raw !== null ? raw : null;
|
|
1023
|
+
const view = (value) => {
|
|
1024
|
+
const fields = typeof value === "object" && value !== null ? value : null;
|
|
1025
|
+
if (fields === null)
|
|
1026
|
+
return null;
|
|
1027
|
+
const count3 = (name) => {
|
|
1028
|
+
const field = fields[name];
|
|
1029
|
+
return typeof field === "number" && Number.isFinite(field) && field >= 0 ? field : null;
|
|
1030
|
+
};
|
|
1031
|
+
const numbers = { requests: count3("requests"), newInput: count3("newInput"), fromMemory: count3("fromMemory"), written: count3("written"), output: count3("output"), reasoning: count3("reasoning") };
|
|
1032
|
+
if (Object.values(numbers).some((value2) => value2 === null))
|
|
1033
|
+
return null;
|
|
1034
|
+
return { ...numbers, costUsd: count3("costUsd") };
|
|
1035
|
+
};
|
|
1036
|
+
const turn = view(record?.turn);
|
|
1037
|
+
const session = view(record?.session);
|
|
1038
|
+
const since = record?.since;
|
|
1039
|
+
const at = record?.at;
|
|
1040
|
+
if (turn === null || session === null || typeof since !== "number" || typeof at !== "number")
|
|
1041
|
+
return null;
|
|
1042
|
+
const turnKey = typeof record?.turnKey === "number" ? record.turnKey : null;
|
|
1043
|
+
return { since, at, turnKey, turn, session };
|
|
1044
|
+
}
|
|
1045
|
+
|
|
951
1046
|
// ../core/lib/strings.js
|
|
952
1047
|
var en = {
|
|
953
1048
|
brand: "AdaptiqAI",
|
|
@@ -1019,6 +1114,22 @@ var en = {
|
|
|
1019
1114
|
popKnowledge: "Knowledge",
|
|
1020
1115
|
addKnowledge: "Add knowledge",
|
|
1021
1116
|
popWorkspace: "All memory on {model}",
|
|
1117
|
+
popSeesNow: "What the model sees now",
|
|
1118
|
+
procTitle: "Processed",
|
|
1119
|
+
procTurn: "Last turn",
|
|
1120
|
+
procSession: "This conversation",
|
|
1121
|
+
procSteps: "{count} steps",
|
|
1122
|
+
procStepsOne: "1 step",
|
|
1123
|
+
procNewInput: "New input",
|
|
1124
|
+
procFromMemory: "Read from memory",
|
|
1125
|
+
procWritten: "Saved to memory",
|
|
1126
|
+
procOutput: "Output",
|
|
1127
|
+
procThinking: "Thinking, part of output",
|
|
1128
|
+
procCost: "Cost",
|
|
1129
|
+
procExplain: "Each step reads the whole memory again. {percent} came from memory.",
|
|
1130
|
+
procExplainFree: "Each step reads the whole memory again. {percent} came from memory, which is free.",
|
|
1131
|
+
procExplainCheaper: "Each step reads the whole memory again. {percent} came from memory, at a fraction of the input price.",
|
|
1132
|
+
procSince: "Counted on this computer since {date}",
|
|
1022
1133
|
openInKnowledge: "Open in Knowledge",
|
|
1023
1134
|
kTitle: "Knowledge",
|
|
1024
1135
|
kSearch: "Search your knowledge",
|
|
@@ -1503,6 +1614,21 @@ function button(id, label, extra = {}) {
|
|
|
1503
1614
|
return { id, label: en[label], labelKey: label, ...extra };
|
|
1504
1615
|
}
|
|
1505
1616
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1617
|
+
var PROCESSED_SAVE_MS = 2e3;
|
|
1618
|
+
function savedProcessed(raw) {
|
|
1619
|
+
const out = {};
|
|
1620
|
+
if (typeof raw !== "object" || raw === null)
|
|
1621
|
+
return out;
|
|
1622
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
1623
|
+
const record = readProcessed(value);
|
|
1624
|
+
if (record !== null)
|
|
1625
|
+
out[id] = record;
|
|
1626
|
+
}
|
|
1627
|
+
return out;
|
|
1628
|
+
}
|
|
1629
|
+
function processedSummary(record) {
|
|
1630
|
+
return record === void 0 ? null : { turn: record.turn, session: record.session, since: record.since };
|
|
1631
|
+
}
|
|
1506
1632
|
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.";
|
|
1507
1633
|
var ATTACH_TRIES = 3;
|
|
1508
1634
|
function transient(error) {
|
|
@@ -1868,6 +1994,7 @@ var Workspace = class {
|
|
|
1868
1994
|
listeners = /* @__PURE__ */ new Set();
|
|
1869
1995
|
state = { preferences: DEFAULT_PREFERENCES, sessions: {} };
|
|
1870
1996
|
saving = Promise.resolve();
|
|
1997
|
+
persistTimer;
|
|
1871
1998
|
refreshing = null;
|
|
1872
1999
|
timer;
|
|
1873
2000
|
pendingAttach = /* @__PURE__ */ new Map();
|
|
@@ -1927,7 +2054,8 @@ var Workspace = class {
|
|
|
1927
2054
|
preferences: { ...DEFAULT_PREFERENCES, ...saved.preferences },
|
|
1928
2055
|
sessions: typeof saved.sessions === "object" && saved.sessions !== null ? saved.sessions : {},
|
|
1929
2056
|
purchase: saved.purchase ?? null,
|
|
1930
|
-
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {}
|
|
2057
|
+
...saved.defaultModel === "pending" || saved.defaultModel === "done" ? { defaultModel: saved.defaultModel } : {},
|
|
2058
|
+
processed: savedProcessed(saved.processed)
|
|
1931
2059
|
};
|
|
1932
2060
|
this.purchases.restore(saved.purchase);
|
|
1933
2061
|
}
|
|
@@ -1943,6 +2071,10 @@ var Workspace = class {
|
|
|
1943
2071
|
this.purchases.dispose();
|
|
1944
2072
|
clearTimeout(this.timer);
|
|
1945
2073
|
clearTimeout(this.attachTimer);
|
|
2074
|
+
if (this.persistTimer !== void 0) {
|
|
2075
|
+
clearTimeout(this.persistTimer);
|
|
2076
|
+
void this.persist();
|
|
2077
|
+
}
|
|
1946
2078
|
for (const session of this.sessions.values()) {
|
|
1947
2079
|
clearTimeout(session.timer);
|
|
1948
2080
|
clearTimeout(session.waitTimer);
|
|
@@ -2010,7 +2142,8 @@ var Workspace = class {
|
|
|
2010
2142
|
region: model2.region,
|
|
2011
2143
|
nativeMemory: model2.nativeMemory,
|
|
2012
2144
|
tools: model2.tools,
|
|
2013
|
-
memory: this.modelMemory.get(model2.id) ?? null
|
|
2145
|
+
memory: this.modelMemory.get(model2.id) ?? null,
|
|
2146
|
+
prices: model2.prices
|
|
2014
2147
|
};
|
|
2015
2148
|
}
|
|
2016
2149
|
/**
|
|
@@ -2620,12 +2753,16 @@ var Workspace = class {
|
|
|
2620
2753
|
return next;
|
|
2621
2754
|
}
|
|
2622
2755
|
async persist() {
|
|
2756
|
+
clearTimeout(this.persistTimer);
|
|
2757
|
+
this.persistTimer = void 0;
|
|
2623
2758
|
const entries = Object.entries(this.state.sessions).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2759
|
+
const processed = Object.entries(this.state.processed ?? {}).sort((a, b) => b[1].at - a[1].at).slice(0, 500);
|
|
2624
2760
|
const snapshot = {
|
|
2625
2761
|
preferences: this.state.preferences,
|
|
2626
2762
|
sessions: Object.fromEntries(entries),
|
|
2627
2763
|
purchase: this.state.purchase ?? null,
|
|
2628
|
-
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel }
|
|
2764
|
+
...this.state.defaultModel === void 0 ? {} : { defaultModel: this.state.defaultModel },
|
|
2765
|
+
...processed.length === 0 ? {} : { processed: Object.fromEntries(processed) }
|
|
2629
2766
|
};
|
|
2630
2767
|
this.saving = this.saving.then(() => this.deps.store.save(snapshot)).catch((error) => {
|
|
2631
2768
|
this.deps.log?.("warn", `adaptiq: could not save preferences: ${String(error)}`);
|
|
@@ -2736,6 +2873,7 @@ var Workspace = class {
|
|
|
2736
2873
|
saved: session.saved,
|
|
2737
2874
|
optimizing: session.optimizing,
|
|
2738
2875
|
lastTurn: session.lastTurn,
|
|
2876
|
+
processed: processedSummary(this.state.processed?.[id]),
|
|
2739
2877
|
knowledge: [...session.knowledge, ...[...session.pendingKnowledge.values()].filter((item) => !session.knowledge.some((entry) => entry.id === item.id))],
|
|
2740
2878
|
conversations: [...session.conversations, ...[...session.pendingConversations.values()].filter((item) => !session.conversations.some((entry) => entry.id === item.id))],
|
|
2741
2879
|
known: session.exists,
|
|
@@ -3115,10 +3253,19 @@ var Workspace = class {
|
|
|
3115
3253
|
this.setPhase(session, "responding");
|
|
3116
3254
|
this.clearNotices("busy", "preparing", "offline", "retrying");
|
|
3117
3255
|
}
|
|
3118
|
-
usage(sessionId, model2, usage) {
|
|
3256
|
+
usage(sessionId, model2, usage, step = {}) {
|
|
3119
3257
|
if (sessionId === void 0)
|
|
3120
3258
|
return;
|
|
3121
3259
|
const session = this.session(sessionId);
|
|
3260
|
+
const costUsd = step.costUsd ?? stepCost(usage, this.catalog.find((entry) => entry.id === model2)?.prices ?? null);
|
|
3261
|
+
const counted = addStep(this.state.processed?.[sessionId], { usage, costUsd, ...step.turn === void 0 ? {} : { turn: step.turn } }, this.now());
|
|
3262
|
+
this.state = { ...this.state, processed: { ...this.state.processed, [sessionId]: counted } };
|
|
3263
|
+
if (this.persistTimer === void 0) {
|
|
3264
|
+
this.persistTimer = setTimeout(() => {
|
|
3265
|
+
void this.persist();
|
|
3266
|
+
}, PROCESSED_SAVE_MS);
|
|
3267
|
+
this.persistTimer.unref?.();
|
|
3268
|
+
}
|
|
3122
3269
|
session.lastTurn = {
|
|
3123
3270
|
fromMemory: usage.cacheReadTokens ?? 0,
|
|
3124
3271
|
newInput: usage.inputTokens,
|
|
@@ -4877,7 +5024,7 @@ function claudeCode(options) {
|
|
|
4877
5024
|
};
|
|
4878
5025
|
const recent = async (at) => {
|
|
4879
5026
|
const found = [];
|
|
4880
|
-
const
|
|
5027
|
+
const add2 = async (path, chat, agent) => {
|
|
4881
5028
|
const info = await stat2(path).catch(() => null);
|
|
4882
5029
|
if (info !== null && Date.now() - info.mtimeMs < RECENT_MS) found.push({ path, chat, ...agent === void 0 ? {} : { agent }, mtime: info.mtimeMs });
|
|
4883
5030
|
};
|
|
@@ -4885,11 +5032,11 @@ function claudeCode(options) {
|
|
|
4885
5032
|
await Promise.all((await readdir(dir, { withFileTypes: true }).catch(() => [])).map(async (entry) => {
|
|
4886
5033
|
const agent = /^agent-(.+)\.jsonl$/u.exec(entry.name)?.[1];
|
|
4887
5034
|
if (entry.isDirectory() && depth < AGENT_DEPTH) await agents(join(dir, entry.name), chat, depth + 1);
|
|
4888
|
-
else if (entry.isFile() && agent !== void 0) await
|
|
5035
|
+
else if (entry.isFile() && agent !== void 0) await add2(join(dir, entry.name), chat, agent);
|
|
4889
5036
|
}));
|
|
4890
5037
|
};
|
|
4891
5038
|
await Promise.all((await readdir(at, { withFileTypes: true }).catch(() => [])).map(async (entry) => {
|
|
4892
|
-
if (entry.isFile() && entry.name.endsWith(".jsonl")) await
|
|
5039
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl")) await add2(join(at, entry.name), entry.name.slice(0, -".jsonl".length));
|
|
4893
5040
|
else if (entry.isDirectory()) await agents(join(at, entry.name, "subagents"), entry.name, 0);
|
|
4894
5041
|
}));
|
|
4895
5042
|
return found.sort((a, b) => b.mtime - a.mtime);
|
|
@@ -5196,7 +5343,7 @@ function fileStateStore(dir) {
|
|
|
5196
5343
|
}
|
|
5197
5344
|
|
|
5198
5345
|
// src/index.ts
|
|
5199
|
-
var VERSION = true ? "0.1.
|
|
5346
|
+
var VERSION = true ? "0.1.1" : "0.0.0";
|
|
5200
5347
|
var PROTOCOLS = ["2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"];
|
|
5201
5348
|
var WORDS = {
|
|
5202
5349
|
signIn: "a terminal with `npx -y @adaptiqai/mcp login`",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptiqai/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "AdaptiqAI for Claude Code, Cline and any MCP app: your saved knowledge and this conversation's memory, as tools for the agent.",
|
|
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",
|