stratagate-dsh 0.2.58 → 0.2.61
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/CHANGELOG.md +10 -17
- package/LICENSE +21 -21
- package/README.zh-CN.md +43 -43
- package/dist/client.js +4 -4
- package/dist/index.d.ts +4 -1
- package/dist/index.js +188 -180
- package/dist/index.js.map +1 -1
- package/docs/ARCHITECTURE.md +29 -29
- package/docs/DSH.md +9 -8
- package/docs/DSH.zh-CN.md +7 -6
- package/docs/EXTERNAL_MEMORY_IMPORT.zh-CN.md +54 -54
- package/package.json +17 -14
- package/screenshots.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Context } from '@deepseek-ai/cordis';
|
|
|
2
2
|
import z from '@deepseek-ai/schemastery';
|
|
3
3
|
|
|
4
4
|
type NamespaceMode = 'project' | 'session' | 'global';
|
|
5
|
+
type StructuredReasoningEffortMode = 'auto' | 'force-off';
|
|
5
6
|
interface Config {
|
|
6
7
|
database?: string;
|
|
7
8
|
namespaceMode?: NamespaceMode;
|
|
@@ -14,12 +15,14 @@ interface Config {
|
|
|
14
15
|
model?: string;
|
|
15
16
|
maxOutputTokens?: number;
|
|
16
17
|
structuredTaskTimeoutMs?: number;
|
|
18
|
+
structuredReasoningEffort?: StructuredReasoningEffortMode;
|
|
17
19
|
}
|
|
18
20
|
declare const Config: z<Config>;
|
|
19
21
|
|
|
20
22
|
declare const name = "stratagate-memory";
|
|
21
23
|
declare const inject: string[];
|
|
24
|
+
declare const STRATAGATE_SETTINGS_NAMESPACE = "stratagate-memory";
|
|
22
25
|
|
|
23
26
|
declare function apply(ctx: Context, config: Config): Promise<() => Promise<void>>;
|
|
24
27
|
|
|
25
|
-
export { Config, Config as PluginConfig, apply, inject, name };
|
|
28
|
+
export { Config, Config as PluginConfig, STRATAGATE_SETTINGS_NAMESPACE, apply, inject, name };
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,9 @@ import { createUserMessage as createUserMessage3 } from "@deepseek-ai/dsh-llm";
|
|
|
5
5
|
|
|
6
6
|
// src/config.ts
|
|
7
7
|
import z from "@deepseek-ai/schemastery";
|
|
8
|
+
var StructuredReasoningEffortSettings = z.object({
|
|
9
|
+
structuredReasoningEffort: z.union(["auto", "force-off"]).default("auto").description("\u8BB0\u5FC6\u5904\u7406\u7ED3\u6784\u5316\u8C03\u7528\u7684\u63A8\u7406\u6863\u4F4D\u7B56\u7565").comment("auto\uFF1A\u4EC5\u5728\u6A21\u578B\u660E\u786E\u652F\u6301 off \u65F6\u4F7F\u7528\uFF1Bforce-off\uFF1A\u4F18\u5148\u4F7F\u7528 off\uFF0C\u4E0D\u652F\u6301\u6216\u80FD\u529B\u68C0\u67E5\u5931\u8D25\u65F6\u5B89\u5168\u964D\u7EA7\uFF0C\u5E76\u5BF9\u540C\u4E00\u6A21\u578B\u53EA\u544A\u8B66\u4E00\u6B21\u3002")
|
|
10
|
+
});
|
|
8
11
|
var Config = z.object({
|
|
9
12
|
database: z.string().required(),
|
|
10
13
|
namespaceMode: z.union(["project", "session", "global"]).default("project"),
|
|
@@ -16,7 +19,8 @@ var Config = z.object({
|
|
|
16
19
|
provider: z.string(),
|
|
17
20
|
model: z.string(),
|
|
18
21
|
maxOutputTokens: z.natural().min(256).default(2048),
|
|
19
|
-
structuredTaskTimeoutMs: z.natural().min(1e3).default(45e3)
|
|
22
|
+
structuredTaskTimeoutMs: z.natural().min(1e3).default(45e3),
|
|
23
|
+
structuredReasoningEffort: z.union(["auto", "force-off"]).default("auto")
|
|
20
24
|
});
|
|
21
25
|
function resolveConfig(config) {
|
|
22
26
|
const database = config.database?.trim() ?? "";
|
|
@@ -38,7 +42,8 @@ function resolveConfig(config) {
|
|
|
38
42
|
ingestSubagents: config.ingestSubagents ?? false,
|
|
39
43
|
...provider && model ? { provider, model } : {},
|
|
40
44
|
maxOutputTokens: Math.max(256, Math.floor(config.maxOutputTokens ?? 2048)),
|
|
41
|
-
structuredTaskTimeoutMs: Math.max(1e3, Math.floor(config.structuredTaskTimeoutMs ?? 45e3))
|
|
45
|
+
structuredTaskTimeoutMs: Math.max(1e3, Math.floor(config.structuredTaskTimeoutMs ?? 45e3)),
|
|
46
|
+
structuredReasoningEffort: config.structuredReasoningEffort ?? "auto"
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
|
|
@@ -2986,35 +2991,6 @@ var StrataGate = class _StrataGate {
|
|
|
2986
2991
|
listSummaryJobs() {
|
|
2987
2992
|
return [...this.summaryJobs.values()];
|
|
2988
2993
|
}
|
|
2989
|
-
/** Give one terminally failed Block Summary job a fresh, user-requested retry budget. */
|
|
2990
|
-
async retryBlockSummary(id) {
|
|
2991
|
-
const blockId = id.trim();
|
|
2992
|
-
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
2993
|
-
const block = this.blocks.find((candidate) => candidate.id === blockId);
|
|
2994
|
-
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
2995
|
-
if (block.processingStatus !== "pending") throw new Error(`Block ${blockId} is already ready`);
|
|
2996
|
-
await this.commitMutation(() => {
|
|
2997
|
-
const job = this.summaryJobs.get(blockId);
|
|
2998
|
-
if (!job) throw new Error(`Missing summary job for block: ${blockId}`);
|
|
2999
|
-
if (job.status !== "failed" || job.nextRetryAt !== null) {
|
|
3000
|
-
throw new Error(`Block ${blockId} Summary has not exhausted automatic retries`);
|
|
3001
|
-
}
|
|
3002
|
-
this.summaryJobs.set(blockId, {
|
|
3003
|
-
...job,
|
|
3004
|
-
status: "pending",
|
|
3005
|
-
attempts: 0,
|
|
3006
|
-
lastError: null,
|
|
3007
|
-
nextRetryAt: null,
|
|
3008
|
-
updatedAt: toUtc8Iso(this.now())
|
|
3009
|
-
});
|
|
3010
|
-
});
|
|
3011
|
-
const extractedEvents = await this.processBlock(block, { retryFailed: false });
|
|
3012
|
-
const processed = this.blocks.find((candidate) => candidate.id === blockId);
|
|
3013
|
-
const readyBlocks = processed?.processingStatus === "ready" ? [processed] : [];
|
|
3014
|
-
const projectedElements = await this.projectEligibleElements() ?? [];
|
|
3015
|
-
await this.projectEligibleGraph();
|
|
3016
|
-
return { sealedBlocks: [], readyBlocks, extractedEvents, projectedElements };
|
|
3017
|
-
}
|
|
3018
2994
|
listElementProjectionJobs() {
|
|
3019
2995
|
return [...this.elementProjectionJobs.values()];
|
|
3020
2996
|
}
|
|
@@ -4918,6 +4894,7 @@ var DshModelBridge = class {
|
|
|
4918
4894
|
constructor(ctx, config) {
|
|
4919
4895
|
this.ctx = ctx;
|
|
4920
4896
|
this.config = config;
|
|
4897
|
+
this.structuredReasoningEffort = config.structuredReasoningEffort ?? "auto";
|
|
4921
4898
|
this.ctx.on?.("llm/adapters-updated", () => {
|
|
4922
4899
|
this.offCapabilities.clear();
|
|
4923
4900
|
});
|
|
@@ -4927,6 +4904,11 @@ var DshModelBridge = class {
|
|
|
4927
4904
|
sessions = new AsyncLocalStorage();
|
|
4928
4905
|
successfulResponses = [];
|
|
4929
4906
|
offCapabilities = /* @__PURE__ */ new Map();
|
|
4907
|
+
warnedOffFallbackRoutes = /* @__PURE__ */ new Set();
|
|
4908
|
+
structuredReasoningEffort;
|
|
4909
|
+
setStructuredReasoningEffort(mode) {
|
|
4910
|
+
this.structuredReasoningEffort = mode;
|
|
4911
|
+
}
|
|
4930
4912
|
run(session, operation) {
|
|
4931
4913
|
return this.sessions.run({ session, sessionId: session.id }, operation);
|
|
4932
4914
|
}
|
|
@@ -5146,7 +5128,7 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
5146
5128
|
if (useOff && isOffRejection(error)) {
|
|
5147
5129
|
this.offCapabilities.set(routeKey, "unsupported");
|
|
5148
5130
|
useOff = false;
|
|
5149
|
-
this.
|
|
5131
|
+
this.warnOffFallbackOnce(routeKey, `${baseRoute.provider}/${baseRoute.model} rejected reasoningEffort=off; retrying once without it`);
|
|
5150
5132
|
attempt -= 1;
|
|
5151
5133
|
continue;
|
|
5152
5134
|
}
|
|
@@ -5158,7 +5140,7 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
5158
5140
|
if (useOff && isOffRejection(finish.failure)) {
|
|
5159
5141
|
this.offCapabilities.set(routeKey, "unsupported");
|
|
5160
5142
|
useOff = false;
|
|
5161
|
-
this.
|
|
5143
|
+
this.warnOffFallbackOnce(routeKey, `${baseRoute.provider}/${baseRoute.model} rejected reasoningEffort=off; retrying once without it`);
|
|
5162
5144
|
attempt -= 1;
|
|
5163
5145
|
continue;
|
|
5164
5146
|
}
|
|
@@ -5236,8 +5218,19 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
5236
5218
|
async shouldUseOff(route) {
|
|
5237
5219
|
const key = `${route.provider}\0${route.model}`;
|
|
5238
5220
|
const cached = this.offCapabilities.get(key);
|
|
5239
|
-
if (cached)
|
|
5240
|
-
|
|
5221
|
+
if (cached) {
|
|
5222
|
+
if (cached === "unsupported" && this.structuredReasoningEffort === "force-off") {
|
|
5223
|
+
this.warnOffFallbackOnce(key, `${route.provider}/${route.model} does not support reasoningEffort=off; using the model default`);
|
|
5224
|
+
}
|
|
5225
|
+
return cached === "supported";
|
|
5226
|
+
}
|
|
5227
|
+
if (typeof this.ctx.llm.resolveModelInfo !== "function") {
|
|
5228
|
+
this.offCapabilities.set(key, "unsupported");
|
|
5229
|
+
if (this.structuredReasoningEffort === "force-off") {
|
|
5230
|
+
this.warnOffFallbackOnce(key, `${route.provider}/${route.model} capabilities are unavailable; using the model default`);
|
|
5231
|
+
}
|
|
5232
|
+
return false;
|
|
5233
|
+
}
|
|
5241
5234
|
const controller = new AbortController();
|
|
5242
5235
|
const lookupTimeoutMs = Math.min(5e3, this.config.structuredTaskTimeoutMs ?? DEFAULT_STRUCTURED_TIMEOUT_MS);
|
|
5243
5236
|
let timer;
|
|
@@ -5252,16 +5245,28 @@ ${JSON_RETRY_INSTRUCTION}`,
|
|
|
5252
5245
|
timer.unref?.();
|
|
5253
5246
|
})
|
|
5254
5247
|
]);
|
|
5255
|
-
if (!info.reasoning) return
|
|
5248
|
+
if (!info.reasoning) return this.structuredReasoningEffort === "force-off";
|
|
5256
5249
|
const supported = info.reasoning.efforts.some(({ id }) => String(id) === "off");
|
|
5257
5250
|
this.offCapabilities.set(key, supported ? "supported" : "unsupported");
|
|
5251
|
+
if (!supported && this.structuredReasoningEffort === "force-off") {
|
|
5252
|
+
this.warnOffFallbackOnce(key, `${route.provider}/${route.model} does not support reasoningEffort=off; using the model default`);
|
|
5253
|
+
}
|
|
5258
5254
|
return supported;
|
|
5259
5255
|
} catch {
|
|
5260
|
-
|
|
5256
|
+
this.offCapabilities.set(key, "unsupported");
|
|
5257
|
+
if (this.structuredReasoningEffort === "force-off") {
|
|
5258
|
+
this.warnOffFallbackOnce(key, `${route.provider}/${route.model} capability lookup failed; using the model default`);
|
|
5259
|
+
}
|
|
5260
|
+
return false;
|
|
5261
5261
|
} finally {
|
|
5262
5262
|
if (timer) clearTimeout(timer);
|
|
5263
5263
|
}
|
|
5264
5264
|
}
|
|
5265
|
+
warnOffFallbackOnce(routeKey, message) {
|
|
5266
|
+
if (this.warnedOffFallbackRoutes.has(routeKey)) return;
|
|
5267
|
+
this.warnedOffFallbackRoutes.add(routeKey);
|
|
5268
|
+
this.ctx.logger.warn(`stratagate-memory ${message}`);
|
|
5269
|
+
}
|
|
5265
5270
|
async consumeStructuredStream(request, assembler) {
|
|
5266
5271
|
const timeoutMs = this.config.structuredTaskTimeoutMs ?? DEFAULT_STRUCTURED_TIMEOUT_MS;
|
|
5267
5272
|
const controller = new AbortController();
|
|
@@ -5529,6 +5534,10 @@ var DshMetadataStore = class {
|
|
|
5529
5534
|
};
|
|
5530
5535
|
|
|
5531
5536
|
// src/runtime.ts
|
|
5537
|
+
var DRAIN_THRESHOLD = 3;
|
|
5538
|
+
var DRAIN_EAGER_MS = 150;
|
|
5539
|
+
var DRAIN_BASE_BACKOFF_MS = 2e3;
|
|
5540
|
+
var DRAIN_MAX_BACKOFF_MS = 6e4;
|
|
5532
5541
|
var AUTO_EVENT_LIMIT = 4;
|
|
5533
5542
|
var AUTO_ELEMENT_LIMIT = 4;
|
|
5534
5543
|
var AUTO_MEMORY_TOKEN_BUDGET = 900;
|
|
@@ -5595,17 +5604,19 @@ var StrataGateRuntime = class {
|
|
|
5595
5604
|
migrationTimers = /* @__PURE__ */ new Map();
|
|
5596
5605
|
derivationTimers = /* @__PURE__ */ new Map();
|
|
5597
5606
|
derivationRuns = /* @__PURE__ */ new Map();
|
|
5598
|
-
knownSessions = /* @__PURE__ */ new Map();
|
|
5599
|
-
pendingSurfaceSync = /* @__PURE__ */ new Map();
|
|
5600
5607
|
adminSnapshotCache = /* @__PURE__ */ new Map();
|
|
5601
5608
|
externalImportRuns = /* @__PURE__ */ new Map();
|
|
5602
5609
|
feedbackDrafts = /* @__PURE__ */ new Map();
|
|
5603
5610
|
pendingFeedbackSuggestionSessions = /* @__PURE__ */ new Set();
|
|
5604
|
-
|
|
5611
|
+
pendingTurns = /* @__PURE__ */ new Map();
|
|
5612
|
+
drainTimers = /* @__PURE__ */ new Map();
|
|
5613
|
+
drainBackoffMs = /* @__PURE__ */ new Map();
|
|
5614
|
+
drainTails = /* @__PURE__ */ new Map();
|
|
5615
|
+
drainErrors = /* @__PURE__ */ new Map();
|
|
5616
|
+
sessionsById = /* @__PURE__ */ new Map();
|
|
5605
5617
|
settingsTail = Promise.resolve();
|
|
5606
5618
|
batchSequence = 0;
|
|
5607
5619
|
closed = false;
|
|
5608
|
-
ingestError;
|
|
5609
5620
|
blockTurnSize;
|
|
5610
5621
|
blockDecayLambda;
|
|
5611
5622
|
transientLastFeedbackPromptAt = null;
|
|
@@ -5614,20 +5625,86 @@ var StrataGateRuntime = class {
|
|
|
5614
5625
|
if (!this.config.ingestSubagents && session.header.origin === "subagent") return;
|
|
5615
5626
|
const turn = this.folder.accept(session, event);
|
|
5616
5627
|
if (!turn) return;
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
+
const key = String(session.id);
|
|
5629
|
+
this.sessionsById.set(key, session);
|
|
5630
|
+
const queued = this.pendingTurns.get(key) ?? [];
|
|
5631
|
+
queued.push(turn);
|
|
5632
|
+
this.pendingTurns.set(key, queued);
|
|
5633
|
+
this.scheduleDrain(session);
|
|
5634
|
+
}
|
|
5635
|
+
/** Serialize drains per session while allowing unrelated sessions to settle independently. */
|
|
5636
|
+
enqueueDrain(session) {
|
|
5637
|
+
const key = String(session.id);
|
|
5638
|
+
const prior = this.drainTails.get(key) ?? Promise.resolve();
|
|
5639
|
+
const next = prior.catch(() => {
|
|
5640
|
+
}).then(() => this.drain(session));
|
|
5641
|
+
this.drainTails.set(key, next);
|
|
5642
|
+
void next.then(() => {
|
|
5643
|
+
if ((this.pendingTurns.get(key)?.length ?? 0) === 0) this.drainErrors.delete(key);
|
|
5644
|
+
}, (error) => {
|
|
5645
|
+
this.drainErrors.set(key, error);
|
|
5628
5646
|
this.notePluginError(session, error);
|
|
5629
5647
|
this.onIngestError(error);
|
|
5630
5648
|
});
|
|
5649
|
+
return next;
|
|
5650
|
+
}
|
|
5651
|
+
/** Batch short bursts and retry failed drains with bounded exponential backoff. */
|
|
5652
|
+
scheduleDrain(session, overrideDelayMs) {
|
|
5653
|
+
const key = String(session.id);
|
|
5654
|
+
if (this.closed) return;
|
|
5655
|
+
const queued = this.pendingTurns.get(key)?.length ?? 0;
|
|
5656
|
+
if (queued === 0) return;
|
|
5657
|
+
const delay = overrideDelayMs ?? (queued >= DRAIN_THRESHOLD ? DRAIN_EAGER_MS : Math.min(this.drainBackoffMs.get(key) ?? DRAIN_BASE_BACKOFF_MS, DRAIN_MAX_BACKOFF_MS));
|
|
5658
|
+
const pending = this.drainTimers.get(key);
|
|
5659
|
+
if (pending) {
|
|
5660
|
+
if (delay >= DRAIN_BASE_BACKOFF_MS) return;
|
|
5661
|
+
clearTimeout(pending);
|
|
5662
|
+
this.drainTimers.delete(key);
|
|
5663
|
+
}
|
|
5664
|
+
const timer = setTimeout(() => {
|
|
5665
|
+
this.drainTimers.delete(key);
|
|
5666
|
+
if (this.closed) return;
|
|
5667
|
+
void this.enqueueDrain(session).then(() => {
|
|
5668
|
+
this.drainBackoffMs.delete(key);
|
|
5669
|
+
if ((this.pendingTurns.get(key)?.length ?? 0) > 0) {
|
|
5670
|
+
this.scheduleDrain(session, DRAIN_BASE_BACKOFF_MS);
|
|
5671
|
+
}
|
|
5672
|
+
}, () => {
|
|
5673
|
+
const backoff = this.drainBackoffMs.get(key) ?? DRAIN_BASE_BACKOFF_MS;
|
|
5674
|
+
this.drainBackoffMs.set(key, Math.min(backoff * 2, DRAIN_MAX_BACKOFF_MS));
|
|
5675
|
+
const pendingRetry = this.drainTimers.get(key);
|
|
5676
|
+
if (pendingRetry) clearTimeout(pendingRetry);
|
|
5677
|
+
this.drainTimers.delete(key);
|
|
5678
|
+
this.scheduleDrain(session);
|
|
5679
|
+
});
|
|
5680
|
+
}, delay);
|
|
5681
|
+
timer.unref?.();
|
|
5682
|
+
this.drainTimers.set(key, timer);
|
|
5683
|
+
}
|
|
5684
|
+
/** Restore failed and unvisited turns ahead of turns that arrived during the drain. */
|
|
5685
|
+
async drain(session) {
|
|
5686
|
+
const key = String(session.id);
|
|
5687
|
+
const turns = this.pendingTurns.get(key);
|
|
5688
|
+
if (!turns || turns.length === 0) return;
|
|
5689
|
+
this.pendingTurns.delete(key);
|
|
5690
|
+
let completed = 0;
|
|
5691
|
+
let memory;
|
|
5692
|
+
try {
|
|
5693
|
+
memory = await this.space(session);
|
|
5694
|
+
for (const turn of turns) {
|
|
5695
|
+
const result = await memory.appendTurn(turn, { deferDerivation: true });
|
|
5696
|
+
completed += 1;
|
|
5697
|
+
if (result.sealedBlock) this.scheduleBlockDerivation(session, memory);
|
|
5698
|
+
}
|
|
5699
|
+
} catch (error) {
|
|
5700
|
+
const remaining = turns.slice(completed);
|
|
5701
|
+
if (remaining.length > 0) {
|
|
5702
|
+
this.pendingTurns.set(key, [...remaining, ...this.pendingTurns.get(key) ?? []]);
|
|
5703
|
+
}
|
|
5704
|
+
throw error;
|
|
5705
|
+
} finally {
|
|
5706
|
+
if (memory) await this.persistSuccessfulResponses(memory);
|
|
5707
|
+
}
|
|
5631
5708
|
}
|
|
5632
5709
|
async searchEvents(session, query, options = {}) {
|
|
5633
5710
|
await this.flush();
|
|
@@ -5967,38 +6044,20 @@ var StrataGateRuntime = class {
|
|
|
5967
6044
|
}
|
|
5968
6045
|
return changed;
|
|
5969
6046
|
}
|
|
5970
|
-
/** Finish native-surface replacement when an admin retry ran without the target session loaded. */
|
|
5971
|
-
async syncPendingRetrySurface(session, memory) {
|
|
5972
|
-
const namespace = this.namespaceFor(session);
|
|
5973
|
-
const threadId = String(session.id);
|
|
5974
|
-
const pending = [...this.pendingSurfaceSync.entries()].filter(([, item]) => item.namespace === namespace);
|
|
5975
|
-
if (pending.length === 0) return;
|
|
5976
|
-
const contexts = new Map(memory.getBlockContext(threadId).map((context) => [context.id, context]));
|
|
5977
|
-
const existing = currentBlockSurfaceMessages(session);
|
|
5978
|
-
let changed = false;
|
|
5979
|
-
for (const [key, { blockId }] of pending) {
|
|
5980
|
-
if (existing.has(blockId)) {
|
|
5981
|
-
this.pendingSurfaceSync.delete(key);
|
|
5982
|
-
continue;
|
|
5983
|
-
}
|
|
5984
|
-
const block = memory.listBlocks().find((candidate) => candidate.id === blockId && candidate.threadId === threadId);
|
|
5985
|
-
const context = contexts.get(blockId);
|
|
5986
|
-
if (!block || block.processingStatus !== "ready" || !context) continue;
|
|
5987
|
-
try {
|
|
5988
|
-
this.replaceSealedSurface(session, block, context, dshTurnAtBlockEnd(session, block));
|
|
5989
|
-
this.pendingSurfaceSync.delete(key);
|
|
5990
|
-
changed = true;
|
|
5991
|
-
} catch (error) {
|
|
5992
|
-
this.onIngestError(error);
|
|
5993
|
-
}
|
|
5994
|
-
}
|
|
5995
|
-
if (changed) await this.flushNativeSession(session);
|
|
5996
|
-
}
|
|
5997
6047
|
// Keep the ingestion error for callers that explicitly require a flushed run.
|
|
5998
6048
|
async settleIngestion() {
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6049
|
+
do {
|
|
6050
|
+
for (const [key, session] of this.sessionsById) {
|
|
6051
|
+
if ((this.pendingTurns.get(key)?.length ?? 0) === 0) continue;
|
|
6052
|
+
const timer = this.drainTimers.get(key);
|
|
6053
|
+
if (timer) clearTimeout(timer);
|
|
6054
|
+
this.drainTimers.delete(key);
|
|
6055
|
+
this.enqueueDrain(session);
|
|
6056
|
+
}
|
|
6057
|
+
await Promise.allSettled(this.drainTails.values());
|
|
6058
|
+
} while (this.drainErrors.size === 0 && [...this.pendingTurns.values()].some((turns) => turns.length > 0));
|
|
6059
|
+
const error = this.drainErrors.values().next().value;
|
|
6060
|
+
this.drainErrors.clear();
|
|
6002
6061
|
return error;
|
|
6003
6062
|
}
|
|
6004
6063
|
async close() {
|
|
@@ -6006,6 +6065,8 @@ var StrataGateRuntime = class {
|
|
|
6006
6065
|
this.closed = true;
|
|
6007
6066
|
for (const timer of this.migrationTimers.values()) clearTimeout(timer);
|
|
6008
6067
|
this.migrationTimers.clear();
|
|
6068
|
+
for (const timer of this.drainTimers.values()) clearTimeout(timer);
|
|
6069
|
+
this.drainTimers.clear();
|
|
6009
6070
|
for (const timer of this.derivationTimers.values()) clearTimeout(timer);
|
|
6010
6071
|
this.derivationTimers.clear();
|
|
6011
6072
|
let flushError;
|
|
@@ -6018,6 +6079,7 @@ var StrataGateRuntime = class {
|
|
|
6018
6079
|
await Promise.allSettled(this.derivationRuns.values());
|
|
6019
6080
|
await Promise.allSettled(this.externalImportRuns.values());
|
|
6020
6081
|
await Promise.all(settled.flatMap((result) => result.status === "fulfilled" ? [result.value.close()] : []));
|
|
6082
|
+
this.sessionsById.clear();
|
|
6021
6083
|
if (flushError !== void 0) throw flushError;
|
|
6022
6084
|
}
|
|
6023
6085
|
namespaceFor(session) {
|
|
@@ -6513,44 +6575,6 @@ var StrataGateRuntime = class {
|
|
|
6513
6575
|
});
|
|
6514
6576
|
return update;
|
|
6515
6577
|
}
|
|
6516
|
-
async adminRetryBlockSummary(namespace, id) {
|
|
6517
|
-
const key = namespace.trim();
|
|
6518
|
-
const blockId = id.trim();
|
|
6519
|
-
if (!key) throw new TypeError("StrataGate admin namespace must not be empty");
|
|
6520
|
-
if (!blockId) throw new TypeError("Block id must not be empty");
|
|
6521
|
-
const update = this.settingsTail.catch(() => {
|
|
6522
|
-
}).then(async () => {
|
|
6523
|
-
await this.flush();
|
|
6524
|
-
const { memory, owned } = await this.openAdminMemory(key, { derivation: true });
|
|
6525
|
-
try {
|
|
6526
|
-
await this.refreshExternalImportMemory(key, memory);
|
|
6527
|
-
const block = memory.listBlocks().find((candidate) => candidate.id === blockId);
|
|
6528
|
-
if (!block) throw new Error(`Unknown block: ${blockId}`);
|
|
6529
|
-
const threadId = block.threadId ?? `admin-summary-retry:${blockId}`;
|
|
6530
|
-
const session = block.threadId ? this.knownSessions.get(block.threadId)?.deref() : void 0;
|
|
6531
|
-
const resumed = session && this.namespaceFor(session) === key ? await this.models.run(session, () => memory.retryBlockSummary(blockId)) : await this.models.runDetached(threadId, () => memory.retryBlockSummary(blockId));
|
|
6532
|
-
await this.persistSuccessfulResponses(memory);
|
|
6533
|
-
if (resumed.readyBlocks.some(({ id: readyId }) => readyId === blockId) && block.threadId) {
|
|
6534
|
-
this.pendingSurfaceSync.set(`${key}\0${blockId}`, { namespace: key, blockId });
|
|
6535
|
-
if (session && this.namespaceFor(session) === key) await this.syncPendingRetrySurface(session, memory);
|
|
6536
|
-
}
|
|
6537
|
-
const summaryJob = memory.listSummaryJobs().find(({ blockId: candidateId }) => candidateId === blockId);
|
|
6538
|
-
return {
|
|
6539
|
-
blockId,
|
|
6540
|
-
processingStatus: block.processingStatus,
|
|
6541
|
-
ready: block.processingStatus === "ready",
|
|
6542
|
-
summaryJob: summaryJob ?? null,
|
|
6543
|
-
surfaceUpdated: !this.pendingSurfaceSync.has(`${key}\0${blockId}`)
|
|
6544
|
-
};
|
|
6545
|
-
} finally {
|
|
6546
|
-
if (owned) await memory.close();
|
|
6547
|
-
}
|
|
6548
|
-
});
|
|
6549
|
-
this.settingsTail = update.then(() => {
|
|
6550
|
-
}, () => {
|
|
6551
|
-
});
|
|
6552
|
-
return update;
|
|
6553
|
-
}
|
|
6554
6578
|
async applyBlockDecayLambda(value) {
|
|
6555
6579
|
await this.flush();
|
|
6556
6580
|
this.blockDecayLambda = value;
|
|
@@ -6613,9 +6637,8 @@ var StrataGateRuntime = class {
|
|
|
6613
6637
|
}
|
|
6614
6638
|
}
|
|
6615
6639
|
}
|
|
6616
|
-
|
|
6640
|
+
space(session) {
|
|
6617
6641
|
const namespace = this.namespaceFor(session);
|
|
6618
|
-
this.knownSessions.set(String(session.id), new WeakRef(session));
|
|
6619
6642
|
this.rememberWorkspace(namespace, session.header.cwd);
|
|
6620
6643
|
let opening = this.spaces.get(namespace);
|
|
6621
6644
|
if (!opening) {
|
|
@@ -6628,20 +6651,20 @@ var StrataGateRuntime = class {
|
|
|
6628
6651
|
extractor: this.models.extractor,
|
|
6629
6652
|
graphProjector: this.models.graphProjector,
|
|
6630
6653
|
disableElementProjection: true
|
|
6631
|
-
}).then(async (
|
|
6654
|
+
}).then(async (memory) => {
|
|
6632
6655
|
try {
|
|
6633
6656
|
try {
|
|
6634
|
-
await
|
|
6635
|
-
const contexts =
|
|
6657
|
+
await memory.resumePendingWork({ deferDerivation: true, threadId: String(session.id) });
|
|
6658
|
+
const contexts = memory.getBlockContext(String(session.id));
|
|
6636
6659
|
this.syncDecayedBlockSurface(session, contexts);
|
|
6637
6660
|
} finally {
|
|
6638
|
-
await this.persistSuccessfulResponses(
|
|
6661
|
+
await this.persistSuccessfulResponses(memory);
|
|
6639
6662
|
}
|
|
6640
|
-
this.scheduleGraphMigration(session,
|
|
6641
|
-
this.scheduleBlockDerivation(session,
|
|
6642
|
-
return
|
|
6663
|
+
this.scheduleGraphMigration(session, memory);
|
|
6664
|
+
this.scheduleBlockDerivation(session, memory);
|
|
6665
|
+
return memory;
|
|
6643
6666
|
} catch (error) {
|
|
6644
|
-
await
|
|
6667
|
+
await memory.close().catch(() => {
|
|
6645
6668
|
});
|
|
6646
6669
|
throw error;
|
|
6647
6670
|
}
|
|
@@ -6651,9 +6674,7 @@ var StrataGateRuntime = class {
|
|
|
6651
6674
|
if (this.spaces.get(namespace) === opening) this.spaces.delete(namespace);
|
|
6652
6675
|
});
|
|
6653
6676
|
}
|
|
6654
|
-
|
|
6655
|
-
await this.syncPendingRetrySurface(session, memory);
|
|
6656
|
-
return memory;
|
|
6677
|
+
return opening;
|
|
6657
6678
|
}
|
|
6658
6679
|
async searchGraph(session, query, limit = 8) {
|
|
6659
6680
|
await this.flush();
|
|
@@ -6757,7 +6778,7 @@ var StrataGateRuntime = class {
|
|
|
6757
6778
|
noteNewCoreJobFailures(session, before, memory) {
|
|
6758
6779
|
if ([...this.failedCoreJobs(memory)].some((failure) => !before.has(failure))) this.notePluginError(session);
|
|
6759
6780
|
}
|
|
6760
|
-
async openAdminMemory(namespace
|
|
6781
|
+
async openAdminMemory(namespace) {
|
|
6761
6782
|
const active = this.spaces.get(namespace);
|
|
6762
6783
|
if (active) return { memory: await active, owned: false };
|
|
6763
6784
|
if (this.config.database === ":memory:" || !existsSync(this.config.database)) {
|
|
@@ -6769,10 +6790,6 @@ var StrataGateRuntime = class {
|
|
|
6769
6790
|
namespace,
|
|
6770
6791
|
blockTurnSize: this.blockTurnSize,
|
|
6771
6792
|
blockDecayLambda: this.blockDecayLambda,
|
|
6772
|
-
...options.derivation ? {
|
|
6773
|
-
summarizer: this.models.summarizer,
|
|
6774
|
-
extractor: this.models.extractor
|
|
6775
|
-
} : {},
|
|
6776
6793
|
graphProjector: this.models.graphProjector,
|
|
6777
6794
|
disableElementProjection: true
|
|
6778
6795
|
}),
|
|
@@ -6890,8 +6907,9 @@ function renderMessages(messages) {
|
|
|
6890
6907
|
}
|
|
6891
6908
|
function dshTurnAtBlockEnd(session, block) {
|
|
6892
6909
|
const blockEnd = Date.parse(block.createdAt);
|
|
6893
|
-
|
|
6894
|
-
|
|
6910
|
+
const events = session.snapshotEvents();
|
|
6911
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
6912
|
+
const event = events[index];
|
|
6895
6913
|
if (event?.type === "turn/end" && event.time === blockEnd) return event.data.turn;
|
|
6896
6914
|
}
|
|
6897
6915
|
throw new Error(`Cannot match StrataGate block ${block.id} to its completed DSH turn`);
|
|
@@ -6901,13 +6919,14 @@ function sealedSurfaceSeqs(session, endTurn, turnCount) {
|
|
|
6901
6919
|
const currentSet = new Set(currentSurface);
|
|
6902
6920
|
const completed = [];
|
|
6903
6921
|
let open;
|
|
6904
|
-
|
|
6922
|
+
const events = session.snapshotEvents();
|
|
6923
|
+
for (const event of events) {
|
|
6905
6924
|
if (event.type === "turn/start") {
|
|
6906
6925
|
open = { turn: event.data.turn, start: event.seq };
|
|
6907
6926
|
continue;
|
|
6908
6927
|
}
|
|
6909
6928
|
if (event.type !== "turn/end" || !open || event.data.turn !== open.turn) continue;
|
|
6910
|
-
const turnEvents =
|
|
6929
|
+
const turnEvents = events.slice(open.start + 1, event.seq);
|
|
6911
6930
|
const hasHumanMessage = turnEvents.some((candidate) => candidate.type === "user/message" && candidate.data.source.kind === "user");
|
|
6912
6931
|
if (hasHumanMessage && event.data.turn <= endTurn) {
|
|
6913
6932
|
completed.push({
|
|
@@ -7026,7 +7045,7 @@ function currentBlockSurfaceMessages(session) {
|
|
|
7026
7045
|
const blocks = /* @__PURE__ */ new Map();
|
|
7027
7046
|
if (!session.surface?.nodes) return blocks;
|
|
7028
7047
|
for (const seq of session.surface.nodes) {
|
|
7029
|
-
const event = session.
|
|
7048
|
+
const event = session.eventAt(seq);
|
|
7030
7049
|
if (event?.type !== "user/message" || event.data.source.kind !== "plugin" || event.data.source.plugin !== COMPACTION_SOURCE_PLUGIN) continue;
|
|
7031
7050
|
const text3 = event.data.content.flatMap((block) => block.type === "text" ? [block.text] : []).join("\n");
|
|
7032
7051
|
const blockId = text3.match(/^\[StrataGate conversation block\]\nBlock: ([^\n]+)/u)?.[1] ?? text3.match(/^\[StrataGate compressed conversation\]\nBlock ([^;\n]+);/u)?.[1];
|
|
@@ -7126,8 +7145,9 @@ KnowledgeGraph:
|
|
|
7126
7145
|
return lines.join("\n");
|
|
7127
7146
|
}
|
|
7128
7147
|
function activeTurn(session) {
|
|
7129
|
-
|
|
7130
|
-
|
|
7148
|
+
const events = session.snapshotEvents();
|
|
7149
|
+
for (let index = events.length - 1; index >= 0; index -= 1) {
|
|
7150
|
+
const event = events[index];
|
|
7131
7151
|
if (event?.type === "turn/start") return event.data.turn;
|
|
7132
7152
|
}
|
|
7133
7153
|
return void 0;
|
|
@@ -7418,7 +7438,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
|
|
|
7418
7438
|
}
|
|
7419
7439
|
|
|
7420
7440
|
// src/web.ts
|
|
7421
|
-
var STRATAGATE_DSH_VERSION = "0.2.
|
|
7441
|
+
var STRATAGATE_DSH_VERSION = "0.2.52";
|
|
7422
7442
|
var LEGACY_THREAD_ID = "__legacy__";
|
|
7423
7443
|
var nodeRequire = createRequire(import.meta.url);
|
|
7424
7444
|
function installedPackageVersion(names) {
|
|
@@ -7561,24 +7581,9 @@ async function overview(runtime, cachedEntries) {
|
|
|
7561
7581
|
const rows = [];
|
|
7562
7582
|
for (const { namespace, snapshot } of entries) {
|
|
7563
7583
|
if (!snapshot) continue;
|
|
7564
|
-
const failedJobs = snapshot.
|
|
7584
|
+
const failedJobs = snapshot.extractionJobs.filter(({ status }) => status === "failed").length + snapshot.graphProjectionJobs.filter(({ status }) => status === "failed").length;
|
|
7565
7585
|
const processingJobs = snapshot.summaryJobs.filter(({ status, nextRetryAt }) => status === "pending" || status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.extractionJobs.filter(({ status, nextRetryAt }) => status === "running" || status === "failed" && nextRetryAt !== null).length + snapshot.graphProjectionJobs.filter(({ status }) => status === "pending" || status === "running").length;
|
|
7566
7586
|
const failedJobDetails = [
|
|
7567
|
-
...snapshot.summaryJobs.filter(({ status }) => status === "failed").map((job) => {
|
|
7568
|
-
const block = snapshot.blocks.find(({ id }) => id === job.blockId);
|
|
7569
|
-
return {
|
|
7570
|
-
id: job.blockId,
|
|
7571
|
-
kind: "block-summary",
|
|
7572
|
-
attempts: job.attempts,
|
|
7573
|
-
nextRetryAt: job.nextRetryAt,
|
|
7574
|
-
lastError: job.lastError?.slice(0, 500) ?? null,
|
|
7575
|
-
lastErrorFull: job.lastError,
|
|
7576
|
-
updatedAt: job.updatedAt,
|
|
7577
|
-
threadId: block?.threadId ?? null,
|
|
7578
|
-
sequence: block?.sequence ?? null,
|
|
7579
|
-
turnRange: block ? [block.startTurn, block.endTurn] : null
|
|
7580
|
-
};
|
|
7581
|
-
}),
|
|
7582
7587
|
...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) => ({
|
|
7583
7588
|
id: job.blockId,
|
|
7584
7589
|
kind: "event-extraction",
|
|
@@ -7973,7 +7978,7 @@ async function memories(runtime, url) {
|
|
|
7973
7978
|
const failedProjection = projections.find(({ status: status2 }) => status2 === "failed");
|
|
7974
7979
|
const pendingProjection = projections.some(({ status: status2 }) => status2 === "pending" || status2 === "running");
|
|
7975
7980
|
const needsExtraction = source.shouldExtract === true;
|
|
7976
|
-
const status =
|
|
7981
|
+
const status = extraction?.status === "failed" || failedProjection ? "failed" : extraction?.status === "succeeded" || extraction?.status === "skipped" ? pendingProjection ? "processing" : "organized" : needsExtraction ? "waiting" : "organized";
|
|
7977
7982
|
const blockPosition = scopedBlocks.findIndex(({ id }) => id === block.id) + 1;
|
|
7978
7983
|
const latestBlockPosition = scopedBlocks.length;
|
|
7979
7984
|
const currentLevel = getDecayedBlockLevel(
|
|
@@ -8131,20 +8136,6 @@ async function expandBlock(runtime, url) {
|
|
|
8131
8136
|
if (!/^L?[0-5]$/i.test(target)) throw new AdminHttpError(400, "level must be L0 through L5");
|
|
8132
8137
|
return runtime.adminExpandBlock(namespace, blockId, target);
|
|
8133
8138
|
}
|
|
8134
|
-
async function retryBlockSummary(runtime, url) {
|
|
8135
|
-
const namespace = url.searchParams.get("namespace")?.trim() ?? "";
|
|
8136
|
-
const blockId = url.searchParams.get("blockId")?.trim() ?? "";
|
|
8137
|
-
if (!namespace) throw new AdminHttpError(400, "namespace is required");
|
|
8138
|
-
if (!blockId) throw new AdminHttpError(400, "blockId is required");
|
|
8139
|
-
if (blockId.startsWith("virtual:")) throw new AdminHttpError(409, "Recovered legacy fragments cannot be retried");
|
|
8140
|
-
const snapshot = await requiredSnapshot(runtime, namespace);
|
|
8141
|
-
const job = snapshot.summaryJobs.find(({ blockId: candidateId }) => candidateId === blockId);
|
|
8142
|
-
if (!job) throw new AdminHttpError(404, `Unknown Block Summary job: ${blockId}`);
|
|
8143
|
-
if (job.status !== "failed" || job.nextRetryAt !== null) {
|
|
8144
|
-
throw new AdminHttpError(409, "Block Summary is not in a terminal failed state");
|
|
8145
|
-
}
|
|
8146
|
-
return runtime.adminRetryBlockSummary(namespace, blockId);
|
|
8147
|
-
}
|
|
8148
8139
|
function receiptSources(snapshot, receipt) {
|
|
8149
8140
|
const events = snapshot.events.filter(({ id }) => receipt.eventIds.includes(id));
|
|
8150
8141
|
const elements = snapshot.elements.filter(({ id }) => receipt.elementIds.includes(id));
|
|
@@ -8257,9 +8248,6 @@ async function handleAdminRequest(runtime, req, res) {
|
|
|
8257
8248
|
} else if (path === "/api/stratagate/blocks/expand") {
|
|
8258
8249
|
if (req.method !== "PATCH") throw new AdminHttpError(405, "StrataGate Block expansion requires PATCH");
|
|
8259
8250
|
sendJson(res, 200, await expandBlock(runtime, url));
|
|
8260
|
-
} else if (path === "/api/stratagate/blocks/retry-summary") {
|
|
8261
|
-
if (req.method !== "POST") throw new AdminHttpError(405, "StrataGate Block Summary retry requires POST");
|
|
8262
|
-
sendJson(res, 200, await retryBlockSummary(runtime, url));
|
|
8263
8251
|
} else if (path === "/api/stratagate/import") {
|
|
8264
8252
|
if (req.method === "GET") {
|
|
8265
8253
|
const operation = url.searchParams.get("operation");
|
|
@@ -8299,6 +8287,7 @@ function registerAdminRoutes(ctx, runtime) {
|
|
|
8299
8287
|
// src/index.ts
|
|
8300
8288
|
var name = "stratagate-memory";
|
|
8301
8289
|
var inject = ["tools", "systemPrompt", "llm", "agentDefaultModel"];
|
|
8290
|
+
var STRATAGATE_SETTINGS_NAMESPACE = "stratagate-memory";
|
|
8302
8291
|
var MEMORY_PROTOCOL = `[StrataGate memory protocol]
|
|
8303
8292
|
StrataGate provides durable, evidence-gated memory through memory_* tools.
|
|
8304
8293
|
|
|
@@ -8336,6 +8325,24 @@ async function apply(ctx, config) {
|
|
|
8336
8325
|
await ctx.sessions.flush(session);
|
|
8337
8326
|
}, () => feedbackWebOrigin(ctx));
|
|
8338
8327
|
await runtime.syncConfiguredSettings();
|
|
8328
|
+
const effortEntry = {
|
|
8329
|
+
structuredReasoningEffort: resolved.structuredReasoningEffort ?? "auto"
|
|
8330
|
+
};
|
|
8331
|
+
let effortSource = () => effortEntry;
|
|
8332
|
+
ctx.inject(["settings"], (settingsCtx) => {
|
|
8333
|
+
settingsCtx.settings.installSection(
|
|
8334
|
+
ctx,
|
|
8335
|
+
STRATAGATE_SETTINGS_NAMESPACE,
|
|
8336
|
+
StructuredReasoningEffortSettings,
|
|
8337
|
+
effortEntry,
|
|
8338
|
+
{
|
|
8339
|
+
setSource: (current) => {
|
|
8340
|
+
effortSource = current;
|
|
8341
|
+
},
|
|
8342
|
+
onChange: () => models.setStructuredReasoningEffort(effortSource().structuredReasoningEffort)
|
|
8343
|
+
}
|
|
8344
|
+
);
|
|
8345
|
+
});
|
|
8339
8346
|
ctx.systemPrompt.section({ name: "tool:stratagate-memory", order: 113, text: MEMORY_PROTOCOL });
|
|
8340
8347
|
ctx.systemPrompt.section({ name: "tool:stratagate-feedback", order: 114, text: FEEDBACK_PROTOCOL });
|
|
8341
8348
|
ctx.on("system-prompt/assemble", async (_assembly, context, next) => {
|
|
@@ -8381,6 +8388,7 @@ async function apply(ctx, config) {
|
|
|
8381
8388
|
}
|
|
8382
8389
|
export {
|
|
8383
8390
|
Config,
|
|
8391
|
+
STRATAGATE_SETTINGS_NAMESPACE,
|
|
8384
8392
|
apply,
|
|
8385
8393
|
inject,
|
|
8386
8394
|
name
|