@adaptiqai/deepseek-harness 0.2.11 → 0.2.13
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 +3 -0
- package/lib/client.js +2 -2
- package/lib/host.js +409 -56
- package/lib/types/host/adapter.d.ts +15 -0
- package/lib/types/host/images.d.ts +91 -0
- package/lib/types/host/release-age.d.ts +57 -0
- package/lib/types/host/wire.d.ts +25 -7
- package/package.json +2 -2
package/lib/host.js
CHANGED
|
@@ -17,7 +17,7 @@ var __runInitializers = (array, flags, self, value) => {
|
|
|
17
17
|
return value;
|
|
18
18
|
};
|
|
19
19
|
var __decorateElement = (array, flags, name2, decorators, target, extra) => {
|
|
20
|
-
var fn, it, done, ctx,
|
|
20
|
+
var fn, it, done, ctx, access2, k = flags & 7, s = !!(flags & 8), p = !!(flags & 16);
|
|
21
21
|
var j = k > 3 ? array.length + 1 : k ? s ? 1 : 2 : 0, key = __decoratorStrings[k + 5];
|
|
22
22
|
var initializers = k > 3 && (array[j - 1] = []), extraInitializers = array[j] || (array[j] = []);
|
|
23
23
|
var desc = k && (!p && !s && (target = target.prototype), k < 5 && (k > 3 || !p) && __getOwnPropDesc(k < 4 ? target : { get [name2]() {
|
|
@@ -29,9 +29,9 @@ var __decorateElement = (array, flags, name2, decorators, target, extra) => {
|
|
|
29
29
|
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
30
30
|
ctx = __decoratorContext(k, name2, done = {}, array[3], extraInitializers);
|
|
31
31
|
if (k) {
|
|
32
|
-
ctx.static = s, ctx.private = p,
|
|
33
|
-
if (k ^ 3)
|
|
34
|
-
if (k > 2)
|
|
32
|
+
ctx.static = s, ctx.private = p, access2 = ctx.access = { has: p ? (x) => __privateIn(target, x) : (x) => name2 in x };
|
|
33
|
+
if (k ^ 3) access2.get = p ? (x) => (k ^ 1 ? __privateGet : __privateMethod)(x, target, k ^ 4 ? extra : desc.get) : (x) => x[name2];
|
|
34
|
+
if (k > 2) access2.set = p ? (x, y) => __privateSet(x, target, y, k ^ 4 ? extra : desc.set) : (x, y) => x[name2] = y;
|
|
35
35
|
}
|
|
36
36
|
it = (0, decorators[i])(k ? k < 4 ? p ? extra : desc[key] : k > 4 ? void 0 : { get: desc.get, set: desc.set } : target, ctx), done._ = 1;
|
|
37
37
|
if (k ^ 4 || it === void 0) __expectFn(it) && (k > 4 ? initializers.unshift(it) : k ? p ? extra = it : desc[key] = it : target = it);
|
|
@@ -54,7 +54,7 @@ import { attributionHeaders as attributionHeaders2 } from "@deepseek-ai/dsh-llm"
|
|
|
54
54
|
import { dshHomePath } from "@deepseek-ai/dsh-home-paths";
|
|
55
55
|
|
|
56
56
|
// src/host/adapter.ts
|
|
57
|
-
import { attributionHeaders, LlmAdapter, LlmError, ProviderRequestId } from "@deepseek-ai/dsh-llm";
|
|
57
|
+
import { attributionHeaders, IMAGE_OFFLOAD_REQUIRED_CODE, LlmAdapter, LlmError, ProviderRequestId } from "@deepseek-ai/dsh-llm";
|
|
58
58
|
|
|
59
59
|
// ../core/lib/errors.js
|
|
60
60
|
var CODES = {
|
|
@@ -122,21 +122,26 @@ function classifyFailure(status, raw, headers, model2, options = {}) {
|
|
|
122
122
|
const library = /\blibrary is full/iu.test(detail.message ?? "");
|
|
123
123
|
return { ...make(CODES.memoryFull, library ? MEMORY_FULL_LIBRARY : MEMORY_FULL, "memory-full"), memoryFull: library ? "library" : "no-room" };
|
|
124
124
|
}
|
|
125
|
+
if (detail.code === "plan_usage_exhausted") {
|
|
126
|
+
const renewsAt = envelope.detail?.renews_at;
|
|
127
|
+
const failure = make(CODES.noLanes, detail.message ?? "Your plan's usage is used up for now. Rent extra lanes in the meantime.", "no-lanes");
|
|
128
|
+
return typeof renewsAt === "number" ? { ...failure, planRenewsAt: renewsAt } : failure;
|
|
129
|
+
}
|
|
125
130
|
if (effective === 402 || detail.code === "rental_paused") {
|
|
126
131
|
const releaseAt = envelope.detail?.release_at;
|
|
127
132
|
const minutes = typeof releaseAt === "number" ? Math.max(1, Math.ceil((releaseAt * 1e3 - Date.now()) / 6e4)) : null;
|
|
128
133
|
const keep = minutes === null ? "to continue" : `within ${minutes} minute${minutes === 1 ? "" : "s"} to keep them`;
|
|
129
|
-
const failure = make(CODES.outOfCredit, `Your balance ran out, so your lanes
|
|
134
|
+
const failure = make(CODES.outOfCredit, `Your balance ran out, so your lanes are paused. Add funds ${keep}.`, "out-of-credit");
|
|
130
135
|
return minutes === null ? failure : { ...failure, minutesLeft: minutes };
|
|
131
136
|
}
|
|
132
137
|
if (effective === 401) {
|
|
133
138
|
return make(CODES.signIn, "Your AdaptiqAI sign-in has expired. Open Settings \u2192 AdaptiqAI and sign in again.", "sign-in");
|
|
134
139
|
}
|
|
135
140
|
if (detail.code === "rental_stopped_unused") {
|
|
136
|
-
return make(CODES.noLanes,
|
|
141
|
+
return make(CODES.noLanes, "Your lane stopped because it went unused, so nothing more was charged. Get access to start it again.", "no-lanes");
|
|
137
142
|
}
|
|
138
143
|
if (has(detail, "AdaptiqLaneAccessRequired", "inference_entitlement_required", "instance_access_required", "lane_access") || effective === 403 && has(detail, "lane", "entitle", "model access")) {
|
|
139
|
-
return make(CODES.noLanes,
|
|
144
|
+
return make(CODES.noLanes, "You need to rent a lane or subscribe to AdaptiqAI to continue.", "no-lanes");
|
|
140
145
|
}
|
|
141
146
|
if (effective === 403) {
|
|
142
147
|
return make(CODES.signIn, "This AdaptiqAI connection isn't allowed to do that. Sign in again from Settings \u2192 AdaptiqAI.", "sign-in");
|
|
@@ -321,10 +326,10 @@ var REFRESH_MARGIN_MS = 2 * 6e4;
|
|
|
321
326
|
var DEVICE_TIMEOUT_MS = 10 * 6e4;
|
|
322
327
|
var UNREACHABLE = "AdaptiqAI can't be reached. Check your internet connection and try again.";
|
|
323
328
|
function deviceLabel(value) {
|
|
324
|
-
let
|
|
325
|
-
while (Buffer.byteLength(
|
|
326
|
-
|
|
327
|
-
return
|
|
329
|
+
let label2 = value.replace(/\.local$/iu, "").replace(/[\p{Cc}\p{Cf}]/gu, " ").replace(/\s+/gu, " ").trim() || "this computer";
|
|
330
|
+
while (Buffer.byteLength(label2) > 80)
|
|
331
|
+
label2 = label2.slice(0, -1);
|
|
332
|
+
return label2;
|
|
328
333
|
}
|
|
329
334
|
var defaultSleep = (ms, signal) => new Promise((resolve2, reject) => {
|
|
330
335
|
if (signal.aborted) {
|
|
@@ -491,13 +496,13 @@ var AuthManager = class {
|
|
|
491
496
|
if (!response.ok)
|
|
492
497
|
throw new Error(`AdaptiqAI could not refresh the sign-in (HTTP ${response.status}).`);
|
|
493
498
|
const body = await readJson(response);
|
|
494
|
-
const
|
|
499
|
+
const access2 = String(body?.access_token ?? "");
|
|
495
500
|
const refresh = String(body?.refresh_token ?? "");
|
|
496
|
-
if (!
|
|
501
|
+
if (!access2.startsWith("ak_") || !refresh.startsWith("akr_"))
|
|
497
502
|
throw new Error("AdaptiqAI returned an invalid refreshed credential.");
|
|
498
503
|
return {
|
|
499
504
|
...current,
|
|
500
|
-
access,
|
|
505
|
+
access: access2,
|
|
501
506
|
refresh,
|
|
502
507
|
expiresAt: this.now() + Math.max(60, Number(body?.expires_in ?? 3600)) * 1e3,
|
|
503
508
|
workspaceLabel: typeof body?.workspace_label === "string" && body.workspace_label !== "" ? body.workspace_label : current.workspaceLabel
|
|
@@ -627,9 +632,9 @@ var AuthManager = class {
|
|
|
627
632
|
return;
|
|
628
633
|
}
|
|
629
634
|
const body = await readJson(response);
|
|
630
|
-
const
|
|
635
|
+
const access2 = String(body?.access_token ?? "");
|
|
631
636
|
const refresh = String(body?.refresh_token ?? "");
|
|
632
|
-
if (!
|
|
637
|
+
if (!access2.startsWith("ak_") || !refresh.startsWith("akr_")) {
|
|
633
638
|
this.fail(flow, { code: "failed", message: "AdaptiqAI returned an invalid credential." });
|
|
634
639
|
return;
|
|
635
640
|
}
|
|
@@ -637,7 +642,7 @@ var AuthManager = class {
|
|
|
637
642
|
const grant = {
|
|
638
643
|
schema: "adaptiq-dsh-grant-v1",
|
|
639
644
|
apiBase: this.options.apiBase,
|
|
640
|
-
access,
|
|
645
|
+
access: access2,
|
|
641
646
|
refresh,
|
|
642
647
|
clientProof,
|
|
643
648
|
expiresAt: this.now() + Math.max(60, Number(body?.expires_in ?? 3600)) * 1e3,
|
|
@@ -1274,15 +1279,19 @@ var en = {
|
|
|
1274
1279
|
n_connected_body: "Your AdaptiqAI models are in the model picker.",
|
|
1275
1280
|
n_compaction_title: "Nothing to compact",
|
|
1276
1281
|
n_compaction_body: "AdaptiqAI keeps the whole conversation in memory, so nothing needs shortening.",
|
|
1282
|
+
n_imagesTextOnly_title: "Images were not sent",
|
|
1283
|
+
n_imagesTextOnly_body: "{model} reads text only, so the model got a short note in place of each image. Choose a model that reads images to ask about them.",
|
|
1277
1284
|
n_signIn_title: "Sign in to keep going",
|
|
1278
1285
|
n_signIn_body: "Your AdaptiqAI connection needs a fresh sign-in.",
|
|
1279
1286
|
n_connect_body: "Connect your AdaptiqAI account to use this model.",
|
|
1280
|
-
n_noLanes_title: "
|
|
1281
|
-
n_noLanes_body: "
|
|
1282
|
-
n_laneStopped_body: "Your lane
|
|
1287
|
+
n_noLanes_title: "Rent a lane to continue",
|
|
1288
|
+
n_noLanes_body: "You need to rent a lane or subscribe to AdaptiqAI to continue.",
|
|
1289
|
+
n_laneStopped_body: "Your lane stopped because it went unused, so nothing more was charged.",
|
|
1290
|
+
n_planUsedUp_body: "Your plan's usage is used up until {until}. Rent extra lanes in the meantime.",
|
|
1291
|
+
n_planUsedUpNoDate_body: "Your plan's usage is used up for now. Rent extra lanes in the meantime.",
|
|
1283
1292
|
n_credit_title: "Add funds to continue",
|
|
1284
|
-
n_credit_body: "Your balance ran out, so your lanes
|
|
1285
|
-
n_creditMinutes_body: "Your balance ran out, so your lanes
|
|
1293
|
+
n_credit_body: "Your balance ran out, so your lanes are paused.",
|
|
1294
|
+
n_creditMinutes_body: "Your balance ran out, so your lanes are paused. Add funds within {minutes} min to keep them.",
|
|
1286
1295
|
n_busy_title: "All lanes are busy",
|
|
1287
1296
|
n_busy_body: "Your request on {model} is waiting for a free lane and will retry by itself.",
|
|
1288
1297
|
n_preparing_title: "Getting your conversation ready",
|
|
@@ -1674,8 +1683,8 @@ var str4 = (value) => typeof value === "string" && value.trim() !== "" ? value.t
|
|
|
1674
1683
|
function say(title, body, params = {}) {
|
|
1675
1684
|
return { title: fill(en[title], params), body: body === null ? "" : fill(en[body], params), text: { title, body, params } };
|
|
1676
1685
|
}
|
|
1677
|
-
function button(id,
|
|
1678
|
-
return { id, label: en[
|
|
1686
|
+
function button(id, label2, extra = {}) {
|
|
1687
|
+
return { id, label: en[label2], labelKey: label2, ...extra };
|
|
1679
1688
|
}
|
|
1680
1689
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1681
1690
|
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.";
|
|
@@ -1783,9 +1792,9 @@ function isYes(reply) {
|
|
|
1783
1792
|
const name2 = reply.slice(at).replace(/^[,,::;;.。]\s*/u, "");
|
|
1784
1793
|
return YES_PHRASES.has(words(reply.slice(0, at))) && NAMED.test(name2);
|
|
1785
1794
|
}
|
|
1786
|
-
function createRefusal(
|
|
1787
|
-
const reason = typeof
|
|
1788
|
-
const owners = [].concat(
|
|
1795
|
+
function createRefusal(access2) {
|
|
1796
|
+
const reason = typeof access2?.reason === "string" ? access2.reason : null;
|
|
1797
|
+
const owners = [].concat(access2?.owners ?? access2?.owner ?? []).map((owner) => typeof owner === "string" ? owner : typeof owner?.name === "string" ? owner.name : typeof owner?.email === "string" ? owner.email : "").filter((owner) => owner !== "");
|
|
1789
1798
|
const ask = owners.length === 0 ? "ask a workspace owner" : `ask ${owners.join(" or ")}`;
|
|
1790
1799
|
switch (reason) {
|
|
1791
1800
|
case "role":
|
|
@@ -1842,7 +1851,7 @@ function copyFailure(error, model2) {
|
|
|
1842
1851
|
case "model_mismatch":
|
|
1843
1852
|
return str4(detail.message) ?? `This collection can't be made available for ${model2}.`;
|
|
1844
1853
|
case "inference_entitlement_required":
|
|
1845
|
-
return
|
|
1854
|
+
return "You need to rent a lane or subscribe to AdaptiqAI to continue.";
|
|
1846
1855
|
case "collection_not_found":
|
|
1847
1856
|
return "This collection no longer exists.";
|
|
1848
1857
|
case "sources_not_exportable":
|
|
@@ -2505,9 +2514,10 @@ var Workspace = class {
|
|
|
2505
2514
|
};
|
|
2506
2515
|
}
|
|
2507
2516
|
/**
|
|
2508
|
-
* Read the newest published version. It is announced
|
|
2509
|
-
*
|
|
2510
|
-
*
|
|
2517
|
+
* Read the newest published version. It is announced at once where the
|
|
2518
|
+
* plugin installs it itself and the harness exempts it from its package
|
|
2519
|
+
* manager's wait; otherwise only once it is old enough (pnpm refuses a
|
|
2520
|
+
* version younger than a day), and the check comes back when it is.
|
|
2511
2521
|
*/
|
|
2512
2522
|
async checkForUpdate() {
|
|
2513
2523
|
if (!this.deps.updateCheck || this.now() - this.updateCheckedAt < 24 * 36e5)
|
|
@@ -2526,7 +2536,7 @@ var Workspace = class {
|
|
|
2526
2536
|
const published = Date.parse(str4(obj4(body.time)?.[version]) ?? "");
|
|
2527
2537
|
if (!Number.isFinite(published))
|
|
2528
2538
|
return;
|
|
2529
|
-
if (this.now() - published < RELEASE_AGE_MS) {
|
|
2539
|
+
if (this.now() - published < RELEASE_AGE_MS && !await this.installsFreshReleases()) {
|
|
2530
2540
|
this.updateCheckedAt = published + RELEASE_AGE_MS - 24 * 36e5 + 6e4;
|
|
2531
2541
|
return;
|
|
2532
2542
|
}
|
|
@@ -2536,6 +2546,13 @@ var Workspace = class {
|
|
|
2536
2546
|
} catch {
|
|
2537
2547
|
}
|
|
2538
2548
|
}
|
|
2549
|
+
/** Whether the one-click update installs a release younger than the package manager's wait. */
|
|
2550
|
+
async installsFreshReleases() {
|
|
2551
|
+
const updater = this.deps.updater;
|
|
2552
|
+
if (updater?.canInstall !== true || updater.installsFreshReleases === void 0)
|
|
2553
|
+
return false;
|
|
2554
|
+
return await updater.installsFreshReleases().catch(() => false);
|
|
2555
|
+
}
|
|
2539
2556
|
/** The update toast: once a newer version is out and not installed yet. */
|
|
2540
2557
|
announceUpdate() {
|
|
2541
2558
|
const plugin = this.pluginState();
|
|
@@ -2725,13 +2742,13 @@ var Workspace = class {
|
|
|
2725
2742
|
this.publish();
|
|
2726
2743
|
}
|
|
2727
2744
|
/** A browser approval completed. */
|
|
2728
|
-
signedIn(
|
|
2745
|
+
signedIn(label2) {
|
|
2729
2746
|
if (this.state.defaultModel === void 0) {
|
|
2730
2747
|
this.state = { ...this.state, defaultModel: "pending" };
|
|
2731
2748
|
void this.persist();
|
|
2732
2749
|
}
|
|
2733
2750
|
this.clearNotices("sign-in");
|
|
2734
|
-
this.raise({ kind: "connected", tone: "success", ...say("connectedTo", "n_connected_body", { workspace:
|
|
2751
|
+
this.raise({ kind: "connected", tone: "success", ...say("connectedTo", "n_connected_body", { workspace: label2 }), actions: [] });
|
|
2735
2752
|
this.summaryMode = "unknown";
|
|
2736
2753
|
this.summaryMissingAt = null;
|
|
2737
2754
|
void this.refresh();
|
|
@@ -2742,11 +2759,11 @@ var Workspace = class {
|
|
|
2742
2759
|
* Waits while no model is running yet; never fails a refresh.
|
|
2743
2760
|
*/
|
|
2744
2761
|
async applyFirstDefault() {
|
|
2745
|
-
const
|
|
2746
|
-
if (this.state.defaultModel !== "pending" ||
|
|
2762
|
+
const access2 = this.deps.defaultModel;
|
|
2763
|
+
if (this.state.defaultModel !== "pending" || access2 === void 0)
|
|
2747
2764
|
return;
|
|
2748
2765
|
try {
|
|
2749
|
-
const current =
|
|
2766
|
+
const current = access2.current();
|
|
2750
2767
|
if (current === void 0)
|
|
2751
2768
|
return;
|
|
2752
2769
|
let choice = firstDefaultModel(current, this.deps.route, this.catalog);
|
|
@@ -2764,7 +2781,7 @@ var Workspace = class {
|
|
|
2764
2781
|
}
|
|
2765
2782
|
if (choice === null)
|
|
2766
2783
|
return;
|
|
2767
|
-
await
|
|
2784
|
+
await access2.save(choice);
|
|
2768
2785
|
this.deps.log?.("info", `adaptiq: default model set to ${choice.model}`);
|
|
2769
2786
|
} catch (error) {
|
|
2770
2787
|
this.deps.log?.("warn", `adaptiq: could not set the default model: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -3317,6 +3334,14 @@ var Workspace = class {
|
|
|
3317
3334
|
actions: [button("open-console", "n_openConsole", { url: this.links.console, primary: true })]
|
|
3318
3335
|
});
|
|
3319
3336
|
}
|
|
3337
|
+
/**
|
|
3338
|
+
* Say that a message's images were not sent because the model reads text only.
|
|
3339
|
+
* @param sessionId - the conversation, when known.
|
|
3340
|
+
* @param modelName - the model's display name.
|
|
3341
|
+
*/
|
|
3342
|
+
imagesNotSent(sessionId2, modelName) {
|
|
3343
|
+
this.raise({ kind: "images", tone: "warning", ...say("n_imagesTextOnly_title", "n_imagesTextOnly_body", { model: modelName }), actions: [], ...sessionId2 === void 0 ? {} : { sessionId: sessionId2 } });
|
|
3344
|
+
}
|
|
3320
3345
|
failed(sessionId2, model2, failure) {
|
|
3321
3346
|
if (failure.code === CODES.compaction) {
|
|
3322
3347
|
this.raise({ kind: "compaction", tone: "info", ...say("n_compaction_title", "n_compaction_body"), actions: [], ...sessionId2 === void 0 ? {} : { sessionId: sessionId2 } });
|
|
@@ -3358,11 +3383,13 @@ var Workspace = class {
|
|
|
3358
3383
|
break;
|
|
3359
3384
|
case "no-lanes": {
|
|
3360
3385
|
const offer = this.offers.find((item) => item.model === model2) ?? this.offers.find((item) => item.name.toLowerCase() === name2.toLowerCase());
|
|
3386
|
+
const body = failure.serverCode === "rental_stopped_unused" ? "n_laneStopped_body" : failure.planRenewsAt !== void 0 ? "n_planUsedUp_body" : failure.serverCode === "plan_usage_exhausted" ? "n_planUsedUpNoDate_body" : "n_noLanes_body";
|
|
3387
|
+
const until = failure.planRenewsAt === void 0 ? "" : `${new Date(failure.planRenewsAt * 1e3).toISOString().slice(0, 16).replace("T", " ")} UTC`;
|
|
3361
3388
|
this.raise({
|
|
3362
3389
|
kind: "no-lanes",
|
|
3363
3390
|
tone: "warning",
|
|
3364
3391
|
modal: true,
|
|
3365
|
-
...say("n_noLanes_title",
|
|
3392
|
+
...say("n_noLanes_title", body, { until }),
|
|
3366
3393
|
actions: [button("get-access", "getAccess", { primary: true, ...offer === void 0 ? {} : { offerId: offer.id } }), button("dismiss", "notNow")]
|
|
3367
3394
|
});
|
|
3368
3395
|
break;
|
|
@@ -3372,7 +3399,7 @@ var Workspace = class {
|
|
|
3372
3399
|
kind: "out-of-credit",
|
|
3373
3400
|
tone: "error",
|
|
3374
3401
|
modal: true,
|
|
3375
|
-
...failure.minutesLeft === void 0 ? say("n_credit_title", "n_credit_body"
|
|
3402
|
+
...failure.minutesLeft === void 0 ? say("n_credit_title", "n_credit_body") : say("n_credit_title", "n_creditMinutes_body", { minutes: String(failure.minutesLeft) }),
|
|
3376
3403
|
actions: [button("add-funds", "n_addFunds", { url: this.links.models, primary: true }), button("dismiss", "notNow")]
|
|
3377
3404
|
});
|
|
3378
3405
|
break;
|
|
@@ -3552,7 +3579,7 @@ var Workspace = class {
|
|
|
3552
3579
|
if (target === void 0)
|
|
3553
3580
|
throw new Error("Choose an AdaptiqAI model first.");
|
|
3554
3581
|
const modelName = this.modelName(target);
|
|
3555
|
-
const
|
|
3582
|
+
const label2 = modelName ?? target;
|
|
3556
3583
|
let body;
|
|
3557
3584
|
try {
|
|
3558
3585
|
body = await this.deps.api.json(`/v1/memories/${encodeURIComponent(id)}/copies`, {
|
|
@@ -3568,7 +3595,7 @@ var Workspace = class {
|
|
|
3568
3595
|
this.copies.set(copyKey(id, target), { source: id, from, target, copy: null, status: "building" });
|
|
3569
3596
|
return { status: "building", model: target, modelName };
|
|
3570
3597
|
}
|
|
3571
|
-
throw new Error(copyFailure(error,
|
|
3598
|
+
throw new Error(copyFailure(error, label2));
|
|
3572
3599
|
}
|
|
3573
3600
|
const copy = obj4(body?.copy);
|
|
3574
3601
|
const status = copyStatus(str4(copy?.status));
|
|
@@ -3815,9 +3842,9 @@ var Workspace = class {
|
|
|
3815
3842
|
if (this.memoryModel(session) === void 0)
|
|
3816
3843
|
await this.ensureModels().catch(() => {
|
|
3817
3844
|
});
|
|
3818
|
-
const
|
|
3819
|
-
if (
|
|
3820
|
-
throw new Error(createRefusal(
|
|
3845
|
+
const access2 = await this.deps.api.json("/v1/cli-auth/knowledge/status", { allow: [404] }).catch(() => null);
|
|
3846
|
+
if (access2 !== null && access2.create_allowed === false)
|
|
3847
|
+
throw new Error(createRefusal(access2));
|
|
3821
3848
|
const body = await this.deps.api.json("/v1/memories", {
|
|
3822
3849
|
method: "POST",
|
|
3823
3850
|
headers: { ...this.memoryHeaders(session), "idempotency-key": idempotencyKey },
|
|
@@ -4663,7 +4690,70 @@ async function* translate(events, hooks) {
|
|
|
4663
4690
|
};
|
|
4664
4691
|
}
|
|
4665
4692
|
|
|
4693
|
+
// src/host/images.ts
|
|
4694
|
+
var ENGINE_IMAGE_LIMITS = Object.freeze({
|
|
4695
|
+
maxImages: 8,
|
|
4696
|
+
maxImageBytes: 20 * 1024 * 1024,
|
|
4697
|
+
maxPixels: 16e6
|
|
4698
|
+
});
|
|
4699
|
+
var ImageProblem = class extends Error {
|
|
4700
|
+
name = "ImageProblem";
|
|
4701
|
+
};
|
|
4702
|
+
var startsWith = (data, bytes, at = 0) => data.length >= at + bytes.length && bytes.every((byte, index) => data[at + index] === byte);
|
|
4703
|
+
var ascii = (text2) => [...text2].map((char) => char.charCodeAt(0));
|
|
4704
|
+
function sniffImageType(data) {
|
|
4705
|
+
if (startsWith(data, [137, 80, 78, 71, 13, 10, 26, 10])) return "image/png";
|
|
4706
|
+
if (startsWith(data, [255, 216, 255])) return "image/jpeg";
|
|
4707
|
+
if (startsWith(data, ascii("GIF87a")) || startsWith(data, ascii("GIF89a"))) return "image/gif";
|
|
4708
|
+
if (startsWith(data, ascii("RIFF")) && startsWith(data, ascii("WEBP"), 8)) return "image/webp";
|
|
4709
|
+
return null;
|
|
4710
|
+
}
|
|
4711
|
+
function fitPixels(width, height, maxPixels) {
|
|
4712
|
+
if (width * height <= maxPixels) return { width, height };
|
|
4713
|
+
const scale = Math.sqrt(maxPixels / (width * height));
|
|
4714
|
+
let w = Math.max(1, Math.floor(width * scale));
|
|
4715
|
+
let h = Math.max(1, Math.floor(height * scale));
|
|
4716
|
+
while (w * h > maxPixels) {
|
|
4717
|
+
if (w >= h) w--;
|
|
4718
|
+
else h--;
|
|
4719
|
+
}
|
|
4720
|
+
return { width: w, height: h };
|
|
4721
|
+
}
|
|
4722
|
+
var carriesImages = (message) => message.role === "user" || message.role === "tool";
|
|
4723
|
+
function sentImages(messages) {
|
|
4724
|
+
const out = [];
|
|
4725
|
+
for (const message of messages) {
|
|
4726
|
+
if (!carriesImages(message)) continue;
|
|
4727
|
+
for (const block of message.content) if (block.type === "image" && block.offloaded !== true) out.push(block);
|
|
4728
|
+
}
|
|
4729
|
+
return out;
|
|
4730
|
+
}
|
|
4731
|
+
function hasImages(messages) {
|
|
4732
|
+
return messages.some((message) => message.content.some((block) => block.type === "image"));
|
|
4733
|
+
}
|
|
4734
|
+
var mib = (bytes) => `${Math.round(bytes / (1024 * 1024) * 10) / 10} MB`;
|
|
4735
|
+
var label = (ref) => ref.name === void 0 ? "An image" : `The image "${ref.name}"`;
|
|
4736
|
+
async function prepareImages(messages, source, limits, signal) {
|
|
4737
|
+
const refs = /* @__PURE__ */ new Map();
|
|
4738
|
+
for (const block of sentImages(messages)) refs.set(String(block.attachment.attachmentId), block.attachment);
|
|
4739
|
+
const entries = await Promise.all([...refs].map(async ([id, ref]) => {
|
|
4740
|
+
const target = { ...fitPixels(ref.width, ref.height, limits.maxPixels), maxBytes: limits.maxImageBytes };
|
|
4741
|
+
const version = await source.readImageRequest(ref, target, signal);
|
|
4742
|
+
const mediaType = sniffImageType(version.data);
|
|
4743
|
+
if (mediaType === null) throw new ImageProblem(`${label(ref)} is not a PNG, JPEG, WebP or GIF file, so AdaptiqAI can't read it. Attach it in one of those formats.`);
|
|
4744
|
+
if (version.data.byteLength > limits.maxImageBytes) {
|
|
4745
|
+
throw new ImageProblem(`${label(ref)} is ${mib(version.data.byteLength)}; AdaptiqAI takes images up to ${mib(limits.maxImageBytes)}. Attach a smaller copy.`);
|
|
4746
|
+
}
|
|
4747
|
+
if (version.width * version.height > limits.maxPixels) {
|
|
4748
|
+
throw new ImageProblem(`${label(ref)} is ${version.width}\xD7${version.height} pixels, more than AdaptiqAI takes. Attach a smaller copy.`);
|
|
4749
|
+
}
|
|
4750
|
+
return [id, { url: `data:${mediaType};base64,${Buffer.from(version.data).toString("base64")}`, width: version.width, height: version.height }];
|
|
4751
|
+
}));
|
|
4752
|
+
return new Map(entries);
|
|
4753
|
+
}
|
|
4754
|
+
|
|
4666
4755
|
// src/host/wire.ts
|
|
4756
|
+
import { offloadedImageText, requestImageHandleText, textOnlyImageText } from "@deepseek-ai/dsh-llm";
|
|
4667
4757
|
function sessionReferences(message) {
|
|
4668
4758
|
if (message.role !== "user") return null;
|
|
4669
4759
|
const source = message.source;
|
|
@@ -4755,16 +4845,62 @@ function userTurns(messages) {
|
|
|
4755
4845
|
}
|
|
4756
4846
|
var text = (blocks) => blocks.filter((block) => block.type === "text").map((block) => block.text).join("");
|
|
4757
4847
|
var reasoning = (blocks) => blocks.filter((block) => block.type === "reasoning").map((block) => block.text).join("");
|
|
4848
|
+
var Parts = class {
|
|
4849
|
+
parts = [];
|
|
4850
|
+
glue = false;
|
|
4851
|
+
text(value, own = false) {
|
|
4852
|
+
if (value === "") return;
|
|
4853
|
+
const last = this.parts.at(-1);
|
|
4854
|
+
if (last?.type === "text") last.text += (own || this.glue ? "\n" : "") + value;
|
|
4855
|
+
else this.parts.push({ type: "text", text: value });
|
|
4856
|
+
this.glue = own;
|
|
4857
|
+
}
|
|
4858
|
+
image(url) {
|
|
4859
|
+
this.parts.push({ type: "image_url", image_url: { url } });
|
|
4860
|
+
this.glue = false;
|
|
4861
|
+
}
|
|
4862
|
+
get hasImage() {
|
|
4863
|
+
return this.parts.some((part) => part.type === "image_url");
|
|
4864
|
+
}
|
|
4865
|
+
get joined() {
|
|
4866
|
+
return this.parts.map((part) => part.type === "text" ? part.text : "").join("");
|
|
4867
|
+
}
|
|
4868
|
+
};
|
|
4869
|
+
function putImage(block, images, parts, inline) {
|
|
4870
|
+
const access2 = images?.access?.(block.attachment);
|
|
4871
|
+
if (block.offloaded === true) {
|
|
4872
|
+
parts.text(offloadedImageText(block.attachment, access2), true);
|
|
4873
|
+
return null;
|
|
4874
|
+
}
|
|
4875
|
+
const sent = images?.sent?.get(String(block.attachment.attachmentId));
|
|
4876
|
+
if (sent === void 0) {
|
|
4877
|
+
parts.text(textOnlyImageText(block.attachment), true);
|
|
4878
|
+
return null;
|
|
4879
|
+
}
|
|
4880
|
+
parts.text(requestImageHandleText(block.attachment, sent, access2), true);
|
|
4881
|
+
if (!inline) return sent;
|
|
4882
|
+
parts.image(sent.url);
|
|
4883
|
+
return null;
|
|
4884
|
+
}
|
|
4758
4885
|
function replayField(message) {
|
|
4759
4886
|
const source = message.source;
|
|
4760
4887
|
const state2 = source?.replayState;
|
|
4761
4888
|
const field = state2?.response?.reasoningField;
|
|
4762
4889
|
return typeof field === "string" && /^[a-z_]{1,32}$/u.test(field) ? field : "reasoning_content";
|
|
4763
4890
|
}
|
|
4764
|
-
function wireMessages(options, recalled = /* @__PURE__ */ new Map()) {
|
|
4891
|
+
function wireMessages(options, recalled = /* @__PURE__ */ new Map(), images) {
|
|
4765
4892
|
const out = [];
|
|
4766
4893
|
if (options.system !== void 0 && options.system !== "") out.push({ role: "system", content: options.system });
|
|
4894
|
+
let toolImages = [];
|
|
4895
|
+
const flushToolImages = () => {
|
|
4896
|
+
if (toolImages.length === 0) return;
|
|
4897
|
+
const parts = [{ type: "text", text: toolImages.length === 1 ? "The image from the tool result above:" : "The images from the tool results above, in order:" }];
|
|
4898
|
+
for (const image of toolImages) parts.push({ type: "image_url", image_url: { url: image.url } });
|
|
4899
|
+
out.push({ role: "user", content: parts });
|
|
4900
|
+
toolImages = [];
|
|
4901
|
+
};
|
|
4767
4902
|
options.messages.forEach((message, index) => {
|
|
4903
|
+
if (message.role !== "tool") flushToolImages();
|
|
4768
4904
|
switch (message.role) {
|
|
4769
4905
|
case "system": {
|
|
4770
4906
|
const content = text(message.content);
|
|
@@ -4776,6 +4912,15 @@ function wireMessages(options, recalled = /* @__PURE__ */ new Map()) {
|
|
|
4776
4912
|
return;
|
|
4777
4913
|
}
|
|
4778
4914
|
case "user": {
|
|
4915
|
+
if (message.content.some((block) => block.type === "image")) {
|
|
4916
|
+
const parts = new Parts();
|
|
4917
|
+
for (const block of message.content) {
|
|
4918
|
+
if (block.type === "text") parts.text(block.text);
|
|
4919
|
+
else if (block.type === "image") putImage(block, images, parts, true);
|
|
4920
|
+
}
|
|
4921
|
+
out.push({ role: "user", content: parts.hasImage ? parts.parts : parts.joined });
|
|
4922
|
+
return;
|
|
4923
|
+
}
|
|
4779
4924
|
const references = recalled.size === 0 ? null : sessionReferences(message);
|
|
4780
4925
|
const content = text(message.content);
|
|
4781
4926
|
out.push({ role: "user", content: references === null ? content : recallSnapshot(content, references, recalled) });
|
|
@@ -4797,7 +4942,15 @@ function wireMessages(options, recalled = /* @__PURE__ */ new Map()) {
|
|
|
4797
4942
|
return;
|
|
4798
4943
|
}
|
|
4799
4944
|
case "tool": {
|
|
4800
|
-
const
|
|
4945
|
+
const parts = new Parts();
|
|
4946
|
+
for (const block of message.content) {
|
|
4947
|
+
if (block.type === "text") parts.text(block.text);
|
|
4948
|
+
else if (block.type === "image") {
|
|
4949
|
+
const deferred = putImage(block, images, parts, false);
|
|
4950
|
+
if (deferred !== null) toolImages.push(deferred);
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
const content = parts.joined;
|
|
4801
4954
|
out.push({ role: "tool", tool_call_id: message.toolCallId, content: content === "" ? "(no output)" : content });
|
|
4802
4955
|
return;
|
|
4803
4956
|
}
|
|
@@ -4805,12 +4958,13 @@ function wireMessages(options, recalled = /* @__PURE__ */ new Map()) {
|
|
|
4805
4958
|
return;
|
|
4806
4959
|
}
|
|
4807
4960
|
});
|
|
4961
|
+
flushToolImages();
|
|
4808
4962
|
return out;
|
|
4809
4963
|
}
|
|
4810
4964
|
function buildChatBody(options, model2, extras) {
|
|
4811
4965
|
const body = {
|
|
4812
4966
|
model: options.model,
|
|
4813
|
-
messages: wireMessages(options, extras.recalled),
|
|
4967
|
+
messages: wireMessages(options, extras.recalled, extras.images),
|
|
4814
4968
|
stream: true,
|
|
4815
4969
|
stream_options: { include_usage: extras.includeUsage ?? true }
|
|
4816
4970
|
};
|
|
@@ -4962,6 +5116,41 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
4962
5116
|
stream(options) {
|
|
4963
5117
|
return this.generate(options);
|
|
4964
5118
|
}
|
|
5119
|
+
/**
|
|
5120
|
+
* The request's images, read from the harness's stored copies, when the
|
|
5121
|
+
* model's card says it reads images. Otherwise each image goes as a short
|
|
5122
|
+
* note and the person is told.
|
|
5123
|
+
*/
|
|
5124
|
+
async images(options, model2, sessionId2, fail2, signal) {
|
|
5125
|
+
if (!hasImages(options.messages)) return void 0;
|
|
5126
|
+
const access2 = this.deps.imageAccess === void 0 ? void 0 : (ref) => {
|
|
5127
|
+
try {
|
|
5128
|
+
return this.deps.imageAccess?.(ref);
|
|
5129
|
+
} catch {
|
|
5130
|
+
return void 0;
|
|
5131
|
+
}
|
|
5132
|
+
};
|
|
5133
|
+
const withAccess = access2 === void 0 ? {} : { access: access2 };
|
|
5134
|
+
const problem = (message) => fail2({ code: CODES.invalidRequest, message, status: null, requestId: null, retryAfterMs: null, serverType: null, serverCode: null, notice: null });
|
|
5135
|
+
if (model2?.input.includes("image") !== true) {
|
|
5136
|
+
if (sentImages(options.messages).length > 0) this.deps.events.imagesNotSent?.(sessionId2, model2?.name ?? options.model);
|
|
5137
|
+
return { sent: null, ...withAccess };
|
|
5138
|
+
}
|
|
5139
|
+
const limits = this.deps.imageLimits ?? ENGINE_IMAGE_LIMITS;
|
|
5140
|
+
const excess = sentImages(options.messages).length - limits.maxImages;
|
|
5141
|
+
if (excess > 0) {
|
|
5142
|
+
throw new LlmError(`AdaptiqAI takes up to ${limits.maxImages} images per request; the ${excess} oldest ${excess === 1 ? "one goes" : "go"} as a note naming ${excess === 1 ? "it" : "them"}.`, IMAGE_OFFLOAD_REQUIRED_CODE, { offloadImages: excess });
|
|
5143
|
+
}
|
|
5144
|
+
const source = this.deps.attachments?.();
|
|
5145
|
+
if (source === void 0) throw problem("This DeepSeek Harness has no attachment service, so images can't be sent. Update DeepSeek Harness and try again.");
|
|
5146
|
+
try {
|
|
5147
|
+
return { sent: await prepareImages(options.messages, source, limits, signal), ...withAccess };
|
|
5148
|
+
} catch (error) {
|
|
5149
|
+
if (error instanceof ImageProblem) throw problem(error.message);
|
|
5150
|
+
if (signal.aborted) throw new LlmError("Request stopped.", CODES.aborted, { cause: error });
|
|
5151
|
+
throw problem(`An attached image could not be read: ${error instanceof Error ? error.message : String(error)}. Attach it again.`);
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
4965
5154
|
async *generate(options) {
|
|
4966
5155
|
if (options.purpose === "compaction") {
|
|
4967
5156
|
const message = "AdaptiqAI keeps the whole conversation in native memory, so it never needs compacting. Nothing was removed.";
|
|
@@ -5036,7 +5225,8 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
5036
5225
|
if (references.length > 0) recalled = await this.deps.recall(sessionId2, options.model, references, signal).catch(() => NOTHING_RECALLED);
|
|
5037
5226
|
}
|
|
5038
5227
|
const parent = options.sessionId === void 0 ? void 0 : this.deps.parentSession?.(String(options.sessionId));
|
|
5039
|
-
|
|
5228
|
+
const images = await this.images(options, model2, sessionId2, fail2, signal);
|
|
5229
|
+
let body = JSON.stringify(buildChatBody(options, model2, { remember, stored, recalled, images }));
|
|
5040
5230
|
this.deps.debug?.(`adaptiq: request ${sessionId2 ?? "-"}: ${options.messages.length} messages, ${body.length} bytes, ${recalled.size} read from memory, transcripts sent: ${body.includes("<referenced-sessions>") ? "yes" : "no"}`);
|
|
5041
5231
|
let response;
|
|
5042
5232
|
let refreshed = false;
|
|
@@ -5077,7 +5267,7 @@ var AdaptiqAdapter = class extends LlmAdapter {
|
|
|
5077
5267
|
await response.body?.cancel().catch(() => {
|
|
5078
5268
|
});
|
|
5079
5269
|
stored = false;
|
|
5080
|
-
body = JSON.stringify(buildChatBody(options, model2, { remember, stored, recalled }));
|
|
5270
|
+
body = JSON.stringify(buildChatBody(options, model2, { remember, stored, recalled, images }));
|
|
5081
5271
|
continue;
|
|
5082
5272
|
}
|
|
5083
5273
|
break;
|
|
@@ -5881,6 +6071,150 @@ ${hash}`).digest("hex").slice(0, 48);
|
|
|
5881
6071
|
})), "adaptiq: adaptiq_create_knowledge tool");
|
|
5882
6072
|
}
|
|
5883
6073
|
|
|
6074
|
+
// src/host/release-age.ts
|
|
6075
|
+
import { constants } from "node:fs";
|
|
6076
|
+
import { access, readFile as readFile3, rename as rename2, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
6077
|
+
import { isAbsolute as isAbsolute2, join } from "node:path";
|
|
6078
|
+
import { randomBytes } from "node:crypto";
|
|
6079
|
+
var KEY = "minimumReleaseAgeExclude";
|
|
6080
|
+
var FILE = "pnpm-workspace.yaml";
|
|
6081
|
+
var PACKAGE_NAME = /^(?:@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*$/u;
|
|
6082
|
+
var TOP_KEY = /^(?:([A-Za-z_][\w-]*)|'([^']*)'|"([^"\\]*)") *:(?: +(.*))?$/u;
|
|
6083
|
+
var ITEM = /^( *)- +(\S.*)$/u;
|
|
6084
|
+
var ENTRY = /^(?:'([^']*)'|"([^"\\]*)"|([\w.][\w@./~^<>=*|+ -]*?)) *(?: #.*)?$/u;
|
|
6085
|
+
var COMMENT = /^ *(?:#.*)?$/u;
|
|
6086
|
+
function singleLineValue(value) {
|
|
6087
|
+
if (value.startsWith('"')) return /^"(?:[^"\\]|\\.)*" *(?:#.*)?$/u.test(value);
|
|
6088
|
+
if (value.startsWith("'")) return /^'(?:[^']|'')*' *(?:#.*)?$/u.test(value);
|
|
6089
|
+
if (value.startsWith("{")) return /^\{[^{}[\]]*\} *(?:#.*)?$/u.test(value);
|
|
6090
|
+
if (value.startsWith("[")) return /^\[[^{}[\]]*\] *(?:#.*)?$/u.test(value);
|
|
6091
|
+
return !/^[|>]/u.test(value) || /^[|>][-+]?\d? *(?:#.*)?$/u.test(value);
|
|
6092
|
+
}
|
|
6093
|
+
function readExcludeList(text2) {
|
|
6094
|
+
if (/[\r\t\uFEFF]/u.test(text2)) return null;
|
|
6095
|
+
const lines = text2.split("\n");
|
|
6096
|
+
if (lines.at(-1) === "") lines.pop();
|
|
6097
|
+
let keyLine = -1;
|
|
6098
|
+
let blockKey = null;
|
|
6099
|
+
let listOpen = false;
|
|
6100
|
+
let blockValue = false;
|
|
6101
|
+
const entries = [];
|
|
6102
|
+
let indent = null;
|
|
6103
|
+
for (const [index, line] of lines.entries()) {
|
|
6104
|
+
if (COMMENT.test(line)) continue;
|
|
6105
|
+
if (line.startsWith(" ")) {
|
|
6106
|
+
if (!listOpen) continue;
|
|
6107
|
+
const item = ITEM.exec(line);
|
|
6108
|
+
if (item === null || indent !== null && item[1] !== indent) return null;
|
|
6109
|
+
const entry = ENTRY.exec(item[2]);
|
|
6110
|
+
if (entry === null) return null;
|
|
6111
|
+
indent = item[1];
|
|
6112
|
+
entries.push({ line: index, value: (entry[1] ?? entry[2] ?? entry[3]).trim() });
|
|
6113
|
+
continue;
|
|
6114
|
+
}
|
|
6115
|
+
if (line.startsWith("- ")) {
|
|
6116
|
+
if (!blockValue) return null;
|
|
6117
|
+
if (listOpen) {
|
|
6118
|
+
if (indent !== null && indent !== "") return null;
|
|
6119
|
+
const entry = ENTRY.exec(line.slice(2).trimStart());
|
|
6120
|
+
if (entry === null) return null;
|
|
6121
|
+
indent = "";
|
|
6122
|
+
entries.push({ line: index, value: (entry[1] ?? entry[2] ?? entry[3]).trim() });
|
|
6123
|
+
}
|
|
6124
|
+
continue;
|
|
6125
|
+
}
|
|
6126
|
+
const key = TOP_KEY.exec(line);
|
|
6127
|
+
if (key === null) return null;
|
|
6128
|
+
const name2 = key[1] ?? key[2] ?? key[3];
|
|
6129
|
+
const value = key[4] ?? "";
|
|
6130
|
+
listOpen = false;
|
|
6131
|
+
blockValue = COMMENT.test(value);
|
|
6132
|
+
if (name2 !== KEY) {
|
|
6133
|
+
if (!blockValue && !singleLineValue(value)) return null;
|
|
6134
|
+
continue;
|
|
6135
|
+
}
|
|
6136
|
+
if (keyLine !== -1) return null;
|
|
6137
|
+
keyLine = index;
|
|
6138
|
+
const flow = /^\[\] *(#.*)?$/u.exec(value);
|
|
6139
|
+
if (flow !== null) blockKey = `${line.slice(0, line.indexOf(":"))}:${flow[1] === void 0 ? "" : ` ${flow[1]}`}`;
|
|
6140
|
+
else if (!blockValue) return null;
|
|
6141
|
+
listOpen = blockValue;
|
|
6142
|
+
}
|
|
6143
|
+
return { lines, keyLine, blockKey, entries, indent: indent ?? " " };
|
|
6144
|
+
}
|
|
6145
|
+
function excludeRelease(text2, name2, version) {
|
|
6146
|
+
if (!PACKAGE_NAME.test(name2) || !RELEASE_VERSION.test(version)) return null;
|
|
6147
|
+
const list = readExcludeList(text2);
|
|
6148
|
+
if (list === null) return null;
|
|
6149
|
+
const spec = `${name2}@${version}`;
|
|
6150
|
+
const ours = list.entries.filter((entry) => entry.value.startsWith(`${name2}@`));
|
|
6151
|
+
if (ours.length === 1 && ours[0].value === spec) return text2;
|
|
6152
|
+
const item = `${list.indent}- '${spec}'`;
|
|
6153
|
+
const drop = new Set(ours.map((entry) => entry.line));
|
|
6154
|
+
const out = [];
|
|
6155
|
+
if (list.keyLine === -1) {
|
|
6156
|
+
out.push(...list.lines, `${KEY}:`, ` - '${spec}'`);
|
|
6157
|
+
} else {
|
|
6158
|
+
const after = list.entries.length > 0 ? list.entries.at(-1).line : list.keyLine;
|
|
6159
|
+
for (const [index, line] of list.lines.entries()) {
|
|
6160
|
+
if (index === list.keyLine && list.blockKey !== null) out.push(list.blockKey);
|
|
6161
|
+
else if (!drop.has(index)) out.push(line);
|
|
6162
|
+
if (index === after) out.push(item);
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
return `${out.join("\n")}
|
|
6166
|
+
`;
|
|
6167
|
+
}
|
|
6168
|
+
function profileDir(ctx) {
|
|
6169
|
+
const profile = ctx.get("profileContext");
|
|
6170
|
+
return typeof profile?.dir === "string" && isAbsolute2(profile.dir) ? profile.dir : null;
|
|
6171
|
+
}
|
|
6172
|
+
async function canExcludeRelease(dir, name2) {
|
|
6173
|
+
try {
|
|
6174
|
+
const file = join(dir, FILE);
|
|
6175
|
+
if (excludeRelease(await readFile3(file, "utf8"), name2, "0.0.0") === null) return false;
|
|
6176
|
+
await access(file, constants.W_OK);
|
|
6177
|
+
await access(dir, constants.W_OK);
|
|
6178
|
+
return true;
|
|
6179
|
+
} catch {
|
|
6180
|
+
return false;
|
|
6181
|
+
}
|
|
6182
|
+
}
|
|
6183
|
+
async function writeReleaseExclusion(dir, name2, version, waitMs = 5e3) {
|
|
6184
|
+
const file = join(dir, FILE);
|
|
6185
|
+
const lock = join(dir, "package.json.lock");
|
|
6186
|
+
const deadline = Date.now() + waitMs;
|
|
6187
|
+
for (; ; ) {
|
|
6188
|
+
try {
|
|
6189
|
+
await writeFile2(lock, `${process.pid}
|
|
6190
|
+
`, { mode: 384, flag: "wx" });
|
|
6191
|
+
break;
|
|
6192
|
+
} catch (error) {
|
|
6193
|
+
if (error.code !== "EEXIST" || Date.now() >= deadline) return false;
|
|
6194
|
+
await new Promise((resolve2) => setTimeout(resolve2, 100));
|
|
6195
|
+
}
|
|
6196
|
+
}
|
|
6197
|
+
try {
|
|
6198
|
+
const before = await readFile3(file, "utf8");
|
|
6199
|
+
const after = excludeRelease(before, name2, version);
|
|
6200
|
+
if (after === null) return false;
|
|
6201
|
+
if (after === before) return true;
|
|
6202
|
+
const temp = `${file}.${randomBytes(6).toString("hex")}.tmp`;
|
|
6203
|
+
try {
|
|
6204
|
+
await writeFile2(temp, after, { mode: (await stat2(file)).mode & 511, flag: "wx" });
|
|
6205
|
+
await rename2(temp, file);
|
|
6206
|
+
} catch (error) {
|
|
6207
|
+
await rm(temp, { force: true });
|
|
6208
|
+
throw error;
|
|
6209
|
+
}
|
|
6210
|
+
return true;
|
|
6211
|
+
} catch {
|
|
6212
|
+
return false;
|
|
6213
|
+
} finally {
|
|
6214
|
+
await rm(lock, { force: true });
|
|
6215
|
+
}
|
|
6216
|
+
}
|
|
6217
|
+
|
|
5884
6218
|
// src/host/updater.ts
|
|
5885
6219
|
function pluginManager(ctx) {
|
|
5886
6220
|
const service = ctx.get("pluginManager");
|
|
@@ -5905,6 +6239,10 @@ function harnessUpdater(ctx, name2, runtime) {
|
|
|
5905
6239
|
get canInstall() {
|
|
5906
6240
|
return pluginManager(ctx) !== void 0;
|
|
5907
6241
|
},
|
|
6242
|
+
async installsFreshReleases() {
|
|
6243
|
+
const dir = profileDir(ctx);
|
|
6244
|
+
return pluginManager(ctx) !== void 0 && dir !== null && await canExcludeRelease(dir, name2);
|
|
6245
|
+
},
|
|
5908
6246
|
async installed() {
|
|
5909
6247
|
const local = runtime?.installedVersion() ?? null;
|
|
5910
6248
|
if (local !== null) return local;
|
|
@@ -5915,6 +6253,8 @@ function harnessUpdater(ctx, name2, runtime) {
|
|
|
5915
6253
|
if (!RELEASE_VERSION.test(version)) throw new UpdateFailure("failed", `${version} is not a release version`);
|
|
5916
6254
|
const manager = pluginManager(ctx);
|
|
5917
6255
|
if (manager === void 0) throw new UpdateFailure("failed", "this harness has no plugin manager");
|
|
6256
|
+
const dir = profileDir(ctx);
|
|
6257
|
+
if (dir !== null) await writeReleaseExclusion(dir, name2, version);
|
|
5918
6258
|
const result = await manager.installBundle(`${name2}@${version}`, { enabled: true });
|
|
5919
6259
|
if (result.application === "failed" || result.application === "cancelled" || result.error !== void 0) throw installFailure(result);
|
|
5920
6260
|
},
|
|
@@ -5933,7 +6273,7 @@ Open **Settings \u2192 AdaptiqAI** to connect, or run \`/adaptiq signin\`.
|
|
|
5933
6273
|
var ENTRY_PROTOCOL = 1;
|
|
5934
6274
|
var RELOAD_SIGNATURE = true ? "ada3dfffa1b3d7b1" : "source";
|
|
5935
6275
|
function pluginVersion() {
|
|
5936
|
-
if (true) return "0.2.
|
|
6276
|
+
if (true) return "0.2.13";
|
|
5937
6277
|
try {
|
|
5938
6278
|
return createRequire(import.meta.url)("../package.json").version;
|
|
5939
6279
|
} catch {
|
|
@@ -5956,14 +6296,25 @@ async function harnessSessions(ctx) {
|
|
|
5956
6296
|
return new Map(records.map((record) => {
|
|
5957
6297
|
let title = null;
|
|
5958
6298
|
try {
|
|
5959
|
-
const
|
|
5960
|
-
if (typeof
|
|
6299
|
+
const label2 = typeof labels?.projectedLabels === "function" ? labels.projectedLabels(record).label : void 0;
|
|
6300
|
+
if (typeof label2 === "string" && label2.trim() !== "" && label2 !== record.header.id) title = label2.trim();
|
|
5961
6301
|
} catch {
|
|
5962
6302
|
}
|
|
5963
6303
|
const subagent = record.header.origin === "subagent" || (record.header.delegationDepth ?? 0) > 0;
|
|
5964
6304
|
return [record.header.id, { title, subagent }];
|
|
5965
6305
|
}));
|
|
5966
6306
|
}
|
|
6307
|
+
function attachmentService(ctx) {
|
|
6308
|
+
const service = ctx.get("attachments");
|
|
6309
|
+
return typeof service?.readImageRequest === "function" ? service : void 0;
|
|
6310
|
+
}
|
|
6311
|
+
function imageAccess(ctx, ref) {
|
|
6312
|
+
const host = attachmentService(ctx)?.imageHostPath?.(ref);
|
|
6313
|
+
if (host === void 0) return void 0;
|
|
6314
|
+
const fs = ctx.get("fs");
|
|
6315
|
+
const readonlyPath = fs?.processPathFromHostPath?.(host);
|
|
6316
|
+
return readonlyPath === void 0 ? void 0 : { readonlyPath };
|
|
6317
|
+
}
|
|
5967
6318
|
var VERSION = pluginVersion();
|
|
5968
6319
|
async function apply(ctx, config) {
|
|
5969
6320
|
await applyWith(ctx, config, void 0);
|
|
@@ -5988,8 +6339,8 @@ async function applyWith(ctx, raw, runtime) {
|
|
|
5988
6339
|
onChange: () => {
|
|
5989
6340
|
workspace?.authChanged();
|
|
5990
6341
|
},
|
|
5991
|
-
onSignedIn: (
|
|
5992
|
-
workspace?.signedIn(
|
|
6342
|
+
onSignedIn: (label2) => {
|
|
6343
|
+
workspace?.signedIn(label2);
|
|
5993
6344
|
}
|
|
5994
6345
|
});
|
|
5995
6346
|
const api = new AdaptiqApi(apiBase, auth, () => ({
|
|
@@ -6071,6 +6422,8 @@ async function applyWith(ctx, raw, runtime) {
|
|
|
6071
6422
|
attachPending: (sessionId2) => owned.attachPending(sessionId2),
|
|
6072
6423
|
events: owned,
|
|
6073
6424
|
autoSleep: (model2) => owned.autoSleep(model2),
|
|
6425
|
+
attachments: () => attachmentService(ctx),
|
|
6426
|
+
imageAccess: (ref) => imageAccess(ctx, ref),
|
|
6074
6427
|
...process.env.DSH_ADAPTIQ_DEBUG_LOG === void 0 || process.env.DSH_ADAPTIQ_DEBUG_LOG === "" ? {} : { debug: (message) => {
|
|
6075
6428
|
log("info", message);
|
|
6076
6429
|
} }
|