@adaptiqai/deepseek-harness 0.2.4 → 0.2.5
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 +115 -18
- package/package.json +2 -2
package/lib/index.js
CHANGED
|
@@ -1275,6 +1275,22 @@ var str4 = (value) => typeof value === "string" && value.trim() !== "" ? value.t
|
|
|
1275
1275
|
var count2 = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
|
|
1276
1276
|
var DEFAULT_PREFERENCES = { rememberByDefault: true, welcomed: false };
|
|
1277
1277
|
var PAGE = 50;
|
|
1278
|
+
var ATTACH_POLL_MS = 15e3;
|
|
1279
|
+
var ATTACH_BACKOFF_MAX_MS = 10 * 6e4;
|
|
1280
|
+
var ATTACH_DEADLINE_MS = 6 * 36e5;
|
|
1281
|
+
var MODEL_ROUTE_CODES = /* @__PURE__ */ new Set(["memory_route_required", "model_required", "model_mismatch"]);
|
|
1282
|
+
function attachBackoffMs(failures) {
|
|
1283
|
+
return Math.min(ATTACH_BACKOFF_MAX_MS, ATTACH_POLL_MS * 2 ** Math.min(Math.max(failures - 1, 0), 10));
|
|
1284
|
+
}
|
|
1285
|
+
function routeChoices(detail) {
|
|
1286
|
+
if (!Array.isArray(detail.models))
|
|
1287
|
+
return null;
|
|
1288
|
+
return detail.models.flatMap((raw) => {
|
|
1289
|
+
const entry = obj4(raw);
|
|
1290
|
+
const id = typeof raw === "string" ? raw : str4(entry?.id) ?? str4(entry?.model);
|
|
1291
|
+
return id === null || id === "" ? [] : [id];
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1278
1294
|
var TROUBLE_QUIET_MS = 6e4;
|
|
1279
1295
|
var SESSION_BACKOFF_MAX_MS = 5 * 6e4;
|
|
1280
1296
|
function sessionBackoffMs(failures) {
|
|
@@ -2699,7 +2715,10 @@ var Workspace = class {
|
|
|
2699
2715
|
if (session !== void 0 && this.now() - session.remoteAt > 1e4)
|
|
2700
2716
|
await this.loadSession(session).catch(() => {
|
|
2701
2717
|
});
|
|
2702
|
-
const
|
|
2718
|
+
const named = model2 !== void 0 && model2 !== "" && (this.catalog.length === 0 || this.catalog.some((entry) => entry.id === model2));
|
|
2719
|
+
const target = named ? model2 : this.targetModel(session) ?? null;
|
|
2720
|
+
if (target === null)
|
|
2721
|
+
return { model: null, modelName: null, items: [], nextCursor: null, hasMore: false, summary: null };
|
|
2703
2722
|
const attached = new Set(session?.knowledge.map((item) => item.id) ?? []);
|
|
2704
2723
|
const name2 = (id) => this.modelName(id);
|
|
2705
2724
|
const read = async (store, limit, after) => {
|
|
@@ -2708,7 +2727,7 @@ var Workspace = class {
|
|
|
2708
2727
|
params.set("query", query.trim().slice(0, 200));
|
|
2709
2728
|
if (after !== void 0 && after !== "")
|
|
2710
2729
|
params.set("cursor", after);
|
|
2711
|
-
const body = await this.deps.api.json(`/v1/memories?${params}`, { headers:
|
|
2730
|
+
const body = await this.deps.api.json(`/v1/memories?${params}`, { headers: { "x-adaptiq-model": store } });
|
|
2712
2731
|
const items = (Array.isArray(body?.data) ? body.data : []).flatMap((raw) => {
|
|
2713
2732
|
const memory = obj4(raw);
|
|
2714
2733
|
return memory === null ? [] : [knowledgeItem(memory, store === target && attached.has(String(memory.memory_id)), { store, target, name: name2 })];
|
|
@@ -2718,13 +2737,13 @@ var Workspace = class {
|
|
|
2718
2737
|
const here = await read(target, PAGE, cursor);
|
|
2719
2738
|
await this.followCopies(target);
|
|
2720
2739
|
let elsewhere = [];
|
|
2721
|
-
if (
|
|
2740
|
+
if (cursor === void 0 || cursor === "") {
|
|
2722
2741
|
const others = this.catalog.filter((entry) => entry.id !== target && entry.status !== "disabled").slice(0, 3);
|
|
2723
2742
|
const pages = await Promise.all(others.map((entry) => read(entry.id, 20).catch(() => ({ items: [], pagination: null }))));
|
|
2724
2743
|
const seen = new Set(here.items.map((item) => item.id));
|
|
2725
2744
|
const copied = new Set([...this.copies.values()].filter((copy) => copy.target === target && copy.status === "ready").map((copy) => copy.source));
|
|
2726
2745
|
const names = new Set(here.items.filter((item) => item.fits).map((item) => item.name));
|
|
2727
|
-
const copyable =
|
|
2746
|
+
const copyable = this.catalog.some((entry) => entry.id === target);
|
|
2728
2747
|
elsewhere = pages.flatMap((page) => page.items).filter((item) => !seen.has(item.id) && !copied.has(item.id) && !names.has(item.name)).map((item) => {
|
|
2729
2748
|
const copy = this.copies.get(copyKey(item.id, target));
|
|
2730
2749
|
return { ...item, fits: false, attached: false, convertible: copyable && item.kind === "collection", copying: copy === void 0 || copy.status === "ready" ? null : copy.status };
|
|
@@ -2735,7 +2754,7 @@ var Workspace = class {
|
|
|
2735
2754
|
const misfits = here.items.filter((item) => !item.fits);
|
|
2736
2755
|
return {
|
|
2737
2756
|
model: target,
|
|
2738
|
-
modelName:
|
|
2757
|
+
modelName: this.modelName(target),
|
|
2739
2758
|
items: [...fitting, ...misfits, ...elsewhere],
|
|
2740
2759
|
nextCursor: str4(here.pagination?.next_cursor),
|
|
2741
2760
|
hasMore: here.pagination?.has_more === true,
|
|
@@ -2934,7 +2953,8 @@ var Workspace = class {
|
|
|
2934
2953
|
await this.setKnowledge(input.attachToSession, id, true).catch(() => {
|
|
2935
2954
|
});
|
|
2936
2955
|
else {
|
|
2937
|
-
|
|
2956
|
+
const model2 = str4(memory.model) ?? this.memoryModel(session) ?? null;
|
|
2957
|
+
this.pendingAttach.set(id, { sessionId: input.attachToSession, at: this.now(), model: model2, failures: 0, next: this.now() });
|
|
2938
2958
|
this.scheduleAttach(1e4);
|
|
2939
2959
|
}
|
|
2940
2960
|
}
|
|
@@ -2949,25 +2969,102 @@ var Workspace = class {
|
|
|
2949
2969
|
}, ms);
|
|
2950
2970
|
this.attachTimer.unref?.();
|
|
2951
2971
|
}
|
|
2972
|
+
/**
|
|
2973
|
+
* Read the collections waiting to be attached, each in its own model's store,
|
|
2974
|
+
* and attach the ones that are ready.
|
|
2975
|
+
*/
|
|
2952
2976
|
async attachReady() {
|
|
2977
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2978
|
+
for (const [id, pending] of [...this.pendingAttach]) {
|
|
2979
|
+
if (this.now() - pending.at > ATTACH_DEADLINE_MS) {
|
|
2980
|
+
this.pendingAttach.delete(id);
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2983
|
+
if (pending.next > this.now())
|
|
2984
|
+
continue;
|
|
2985
|
+
const model2 = pending.model ?? this.targetModel(this.session(pending.sessionId));
|
|
2986
|
+
if (model2 === void 0)
|
|
2987
|
+
continue;
|
|
2988
|
+
groups.set(model2, [...groups.get(model2) ?? [], [id, pending]]);
|
|
2989
|
+
}
|
|
2990
|
+
for (const [model2, entries] of groups) {
|
|
2991
|
+
try {
|
|
2992
|
+
await this.attachCheck(model2, entries);
|
|
2993
|
+
} catch {
|
|
2994
|
+
}
|
|
2995
|
+
}
|
|
2996
|
+
if (this.pendingAttach.size === 0)
|
|
2997
|
+
return;
|
|
2998
|
+
const now = this.now();
|
|
2999
|
+
this.scheduleAttach(Math.min(...[...this.pendingAttach.values()].map((pending) => pending.next > now ? pending.next - now : ATTACH_POLL_MS)));
|
|
3000
|
+
}
|
|
3001
|
+
async attachCheck(model2, entries) {
|
|
3002
|
+
let items = null;
|
|
2953
3003
|
try {
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3004
|
+
items = await this.waitingKnowledge(model2);
|
|
3005
|
+
} catch (error) {
|
|
3006
|
+
const detail = error instanceof AdaptiqHttpError && error.status === 409 ? obj4(obj4(error.body)?.detail) : null;
|
|
3007
|
+
const code = str4(detail?.code);
|
|
3008
|
+
if (detail === null || code === null || !MODEL_ROUTE_CODES.has(code)) {
|
|
3009
|
+
for (const [, pending] of entries)
|
|
3010
|
+
pending.next = this.now() + ATTACH_POLL_MS;
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
const choices = routeChoices(detail);
|
|
3014
|
+
if (choices !== null && choices.length > 0 && !choices.includes(model2)) {
|
|
3015
|
+
const name2 = this.modelName(model2) ?? model2;
|
|
3016
|
+
for (const [id, pending] of entries) {
|
|
2962
3017
|
this.pendingAttach.delete(id);
|
|
2963
|
-
|
|
3018
|
+
this.raise({
|
|
3019
|
+
kind: "model-unavailable",
|
|
3020
|
+
tone: "info",
|
|
3021
|
+
title: `${name2} isn't available`,
|
|
3022
|
+
body: `Your new collection is saved. Add it from Knowledge once ${name2} is available again.`,
|
|
3023
|
+
actions: [{ id: "open-models", label: "See your models", url: this.links.models }],
|
|
3024
|
+
sessionId: pending.sessionId
|
|
2964
3025
|
});
|
|
2965
|
-
this.raise({ kind: "connected", tone: "success", title: `${item.name} is ready`, body: "It is now used in your conversation.", actions: [], sessionId: pending.sessionId });
|
|
2966
3026
|
}
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
const pick = choices?.find((choice) => choice === model2);
|
|
3030
|
+
if (pick !== void 0)
|
|
3031
|
+
items = await this.waitingKnowledge(pick).catch(() => null);
|
|
3032
|
+
if (items === null) {
|
|
3033
|
+
for (const [, pending] of entries) {
|
|
3034
|
+
pending.failures += 1;
|
|
3035
|
+
pending.next = this.now() + attachBackoffMs(pending.failures);
|
|
3036
|
+
}
|
|
3037
|
+
return;
|
|
2967
3038
|
}
|
|
2968
|
-
} catch {
|
|
2969
3039
|
}
|
|
2970
|
-
|
|
3040
|
+
for (const [id, pending] of entries) {
|
|
3041
|
+
const item = items.find((candidate) => candidate.id === id);
|
|
3042
|
+
pending.failures = 0;
|
|
3043
|
+
pending.next = this.now() + ATTACH_POLL_MS;
|
|
3044
|
+
if (item?.status === "failed") {
|
|
3045
|
+
this.pendingAttach.delete(id);
|
|
3046
|
+
continue;
|
|
3047
|
+
}
|
|
3048
|
+
if (item?.status === "ready") {
|
|
3049
|
+
this.pendingAttach.delete(id);
|
|
3050
|
+
await this.setKnowledge(pending.sessionId, id, true).catch(() => {
|
|
3051
|
+
});
|
|
3052
|
+
this.raise({ kind: "connected", tone: "success", title: `${item.name} is ready`, body: "It is now used in your conversation.", actions: [], sessionId: pending.sessionId });
|
|
3053
|
+
}
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
/**
|
|
3057
|
+
* One model's collections, for the ones waiting to be attached.
|
|
3058
|
+
* @param model - the store to read.
|
|
3059
|
+
* @returns the collections.
|
|
3060
|
+
*/
|
|
3061
|
+
async waitingKnowledge(model2) {
|
|
3062
|
+
const params = new URLSearchParams({ limit: String(PAGE), status: "all" });
|
|
3063
|
+
const body = await this.deps.api.json(`/v1/memories?${params}`, { headers: { "x-adaptiq-model": model2 } });
|
|
3064
|
+
return (Array.isArray(body?.data) ? body.data : []).flatMap((raw) => {
|
|
3065
|
+
const memory = obj4(raw);
|
|
3066
|
+
return memory === null ? [] : [knowledgeItem(memory, false)];
|
|
3067
|
+
});
|
|
2971
3068
|
}
|
|
2972
3069
|
// ---------------------------------------------------------------- conversations as knowledge
|
|
2973
3070
|
/** False once the server answered that it has no conversation routes. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adaptiqai/deepseek-harness",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "AdaptiqAI for DeepSeek Harness: models with 5M-token native memory and Knowledge. Sign up, get a model and work without leaving the harness",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"react-dom": "~18.3.1",
|
|
90
90
|
"typescript": "~5.9.3",
|
|
91
91
|
"vitest": "~3.2.7",
|
|
92
|
-
"@adaptiqai/core": "0.2.
|
|
92
|
+
"@adaptiqai/core": "0.2.5"
|
|
93
93
|
},
|
|
94
94
|
"repository": {
|
|
95
95
|
"type": "git",
|