stratagate-dsh 0.3.15 → 0.3.16
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 +9 -0
- package/dist/client.js +7 -7
- package/dist/plugin.js +568 -102
- package/dist/plugin.js.map +1 -1
- package/docs/feedback.md +50 -0
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -8521,6 +8521,329 @@ function parseJsonResponse(value, requiredKeys = []) {
|
|
|
8521
8521
|
throw new ModelJsonResponseError(void 0, { response: value });
|
|
8522
8522
|
}
|
|
8523
8523
|
|
|
8524
|
+
// src/llm.ts
|
|
8525
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
8526
|
+
|
|
8527
|
+
// src/diagnostics.ts
|
|
8528
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
8529
|
+
import { createRequire as createRequire2 } from "node:module";
|
|
8530
|
+
import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
|
|
8531
|
+
var DAY = 864e5;
|
|
8532
|
+
var VERSION = (() => {
|
|
8533
|
+
try {
|
|
8534
|
+
return String(createRequire2(import.meta.url)("../package.json").version);
|
|
8535
|
+
} catch {
|
|
8536
|
+
return "unknown";
|
|
8537
|
+
}
|
|
8538
|
+
})();
|
|
8539
|
+
var DIAGNOSTIC_STAGES = ["summarizer", "extractor", "projector", "graphProjector", "topicProjector", "externalMemoryExtractor", "externalMemoryDecider", "profileMaintenance", "dreamingStep", "chat", "ingestion", "autoContext", "directory", "tools", "frontend", "retrieval"];
|
|
8540
|
+
function diagnosticText(value, limit = 1500) {
|
|
8541
|
+
return String(value instanceof Error ? value.message : value ?? "").slice(0, 8e3).split(/\nRaw response(?: preview| \(full\))/i)[0].replace(/\b(?:sk[-_]|gh[opasu]_|github_pat_)[A-Za-z0-9_-]{8,}\b/g, "[credential]").replace(/(["']?\b(?:api[_-]?key|token|password|passwd|secret|authorization|access[_-]?token|refresh[_-]?token)["']?\s*[:=]\s*)(["'])([\s\S]*?)\2/gi, "$1[credential]").replace(/\b(?:Bearer|Basic|Token)\s+[^\s,;}]+/gi, "[credential]").replace(/\b(?:api[_-]?key|token|password|passwd|secret|authorization)\s*[:=]\s*[^\s,;}]+/gi, "[credential]").replace(/https?:\/\/[^\s<>"']+/gi, "[url]").replace(/[A-Z]:[\\/][^\s"'<>]+/gi, "[path]").replace(/[\w.+-]+@[\w.-]+\.[a-z]{2,}/gi, "[email]").replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f]/g, "").slice(0, limit).replace(/[\uD800-\uDBFF]$/, "");
|
|
8542
|
+
}
|
|
8543
|
+
function isAbortError(error) {
|
|
8544
|
+
return typeof error === "object" && error !== null && (error.name === "AbortError" || error.code === "ABORT_ERR");
|
|
8545
|
+
}
|
|
8546
|
+
function diagnosticCategory(error) {
|
|
8547
|
+
if (isAbortError(error)) return "cancelled";
|
|
8548
|
+
const text3 = String(error instanceof Error ? error.message : error ?? "");
|
|
8549
|
+
if (/timeout|timed out|超时/i.test(text3)) return "timeout";
|
|
8550
|
+
if (/429|rate.?limit/i.test(text3)) return "rate-limit";
|
|
8551
|
+
if (/401|403|unauthori|forbidden|credential/i.test(text3)) return "authentication";
|
|
8552
|
+
if (/token.*limit|truncat|max-tokens|context.*(window|length|limit)/i.test(text3)) return "token-limit";
|
|
8553
|
+
if (/json|schema|invalid|validation/i.test(text3)) return "validation";
|
|
8554
|
+
if (/sqlite|database|storage|EACCES|ENOSPC|write failed/i.test(text3)) return "storage";
|
|
8555
|
+
if (/abort|cancel/i.test(text3)) return "cancelled";
|
|
8556
|
+
if (/network|fetch|ECONN|ENOTFOUND/i.test(text3)) return "network";
|
|
8557
|
+
return "internal";
|
|
8558
|
+
}
|
|
8559
|
+
var SCHEMA2 = `
|
|
8560
|
+
CREATE TABLE IF NOT EXISTS stratagate_dsh_diagnostic_records (
|
|
8561
|
+
id TEXT PRIMARY KEY, at TEXT NOT NULL, namespace TEXT NOT NULL, record_json TEXT NOT NULL
|
|
8562
|
+
) STRICT;
|
|
8563
|
+
CREATE INDEX IF NOT EXISTS stratagate_dsh_diagnostic_scope ON stratagate_dsh_diagnostic_records(namespace, at);
|
|
8564
|
+
CREATE TABLE IF NOT EXISTS stratagate_dsh_diagnostic_daily (
|
|
8565
|
+
namespace TEXT NOT NULL, day TEXT NOT NULL, stage TEXT NOT NULL, model TEXT NOT NULL,
|
|
8566
|
+
version TEXT NOT NULL, counters_json TEXT NOT NULL,
|
|
8567
|
+
PRIMARY KEY(namespace, day, stage, model, version)
|
|
8568
|
+
) STRICT;
|
|
8569
|
+
CREATE TABLE IF NOT EXISTS stratagate_dsh_diagnostic_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL) STRICT;
|
|
8570
|
+
`;
|
|
8571
|
+
var DiagnosticsRecorder = class {
|
|
8572
|
+
constructor(filename) {
|
|
8573
|
+
this.filename = filename;
|
|
8574
|
+
}
|
|
8575
|
+
filename;
|
|
8576
|
+
database;
|
|
8577
|
+
pending = [];
|
|
8578
|
+
timer;
|
|
8579
|
+
closed = false;
|
|
8580
|
+
dropped = 0;
|
|
8581
|
+
writeFailures = 0;
|
|
8582
|
+
startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
8583
|
+
record(scope, counters, options = {}) {
|
|
8584
|
+
if (this.closed) return;
|
|
8585
|
+
const bounded2 = Object.fromEntries(Object.entries(counters).filter(([, n]) => Number.isFinite(n) && n >= 0));
|
|
8586
|
+
this.pending.push({
|
|
8587
|
+
id: `diag_${randomUUID3()}`,
|
|
8588
|
+
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8589
|
+
namespace: scope.namespace,
|
|
8590
|
+
stage: scope.stage,
|
|
8591
|
+
model: diagnosticText(options.model ?? "", 160),
|
|
8592
|
+
version: VERSION,
|
|
8593
|
+
counters: bounded2,
|
|
8594
|
+
...scope.taskId ? { taskId: scope.taskId } : {},
|
|
8595
|
+
...options.error !== void 0 ? { category: diagnosticCategory(options.error), detail: diagnosticText(options.error) } : {}
|
|
8596
|
+
});
|
|
8597
|
+
if (this.pending.length > 256) {
|
|
8598
|
+
this.pending.shift();
|
|
8599
|
+
this.dropped++;
|
|
8600
|
+
}
|
|
8601
|
+
if (!this.timer) {
|
|
8602
|
+
this.timer = setTimeout(() => {
|
|
8603
|
+
this.timer = void 0;
|
|
8604
|
+
this.flush();
|
|
8605
|
+
}, 5e3);
|
|
8606
|
+
this.timer.unref?.();
|
|
8607
|
+
}
|
|
8608
|
+
}
|
|
8609
|
+
open() {
|
|
8610
|
+
if (this.database) return this.database;
|
|
8611
|
+
const db = new DatabaseSync2(this.filename);
|
|
8612
|
+
try {
|
|
8613
|
+
db.exec("PRAGMA busy_timeout=0");
|
|
8614
|
+
db.exec(SCHEMA2);
|
|
8615
|
+
db.prepare("INSERT OR IGNORE INTO stratagate_dsh_diagnostic_meta VALUES ('startedAt', ?)").run(this.startedAt);
|
|
8616
|
+
this.database = db;
|
|
8617
|
+
return db;
|
|
8618
|
+
} catch (error) {
|
|
8619
|
+
db.close();
|
|
8620
|
+
throw error;
|
|
8621
|
+
}
|
|
8622
|
+
}
|
|
8623
|
+
flush() {
|
|
8624
|
+
if (!this.pending.length) return;
|
|
8625
|
+
try {
|
|
8626
|
+
const db = this.open();
|
|
8627
|
+
db.exec("BEGIN IMMEDIATE");
|
|
8628
|
+
try {
|
|
8629
|
+
const get = db.prepare("SELECT counters_json FROM stratagate_dsh_diagnostic_daily WHERE namespace=? AND day=? AND stage=? AND model=? AND version=?");
|
|
8630
|
+
const put = db.prepare("INSERT OR REPLACE INTO stratagate_dsh_diagnostic_daily VALUES (?, ?, ?, ?, ?, ?)");
|
|
8631
|
+
const insert = db.prepare("INSERT INTO stratagate_dsh_diagnostic_records VALUES (?, ?, ?, ?)");
|
|
8632
|
+
for (const item of this.pending) {
|
|
8633
|
+
const keys = [item.namespace, item.at.slice(0, 10), item.stage, item.model, item.version];
|
|
8634
|
+
const row = get.get(...keys);
|
|
8635
|
+
const counters = row ? JSON.parse(row.counters_json) : {};
|
|
8636
|
+
for (const [key, value] of Object.entries(item.counters)) counters[key] = (counters[key] ?? 0) + value;
|
|
8637
|
+
put.run(...keys, JSON.stringify(counters));
|
|
8638
|
+
insert.run(item.id, item.at, item.namespace, JSON.stringify(item));
|
|
8639
|
+
}
|
|
8640
|
+
db.prepare("DELETE FROM stratagate_dsh_diagnostic_records WHERE at < ? OR id NOT IN (SELECT id FROM stratagate_dsh_diagnostic_records ORDER BY at DESC, id DESC LIMIT 2000)").run(new Date(Date.now() - 7 * DAY).toISOString());
|
|
8641
|
+
db.prepare("DELETE FROM stratagate_dsh_diagnostic_daily WHERE day < ?").run(new Date(Date.now() - 90 * DAY).toISOString().slice(0, 10));
|
|
8642
|
+
db.exec("DELETE FROM stratagate_dsh_diagnostic_daily WHERE rowid NOT IN (SELECT rowid FROM stratagate_dsh_diagnostic_daily ORDER BY day DESC LIMIT 10000)");
|
|
8643
|
+
db.exec("COMMIT");
|
|
8644
|
+
this.pending = [];
|
|
8645
|
+
} catch (error) {
|
|
8646
|
+
db.exec("ROLLBACK");
|
|
8647
|
+
throw error;
|
|
8648
|
+
}
|
|
8649
|
+
} catch {
|
|
8650
|
+
this.writeFailures++;
|
|
8651
|
+
}
|
|
8652
|
+
}
|
|
8653
|
+
snapshot(namespace, options = {}) {
|
|
8654
|
+
this.flush();
|
|
8655
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
8656
|
+
const since = new Date(Date.parse(today) - 6 * DAY).toISOString().slice(0, 10);
|
|
8657
|
+
const totals = {};
|
|
8658
|
+
const stages = {};
|
|
8659
|
+
let startedAt = this.startedAt;
|
|
8660
|
+
let available = false;
|
|
8661
|
+
let rows = [];
|
|
8662
|
+
let records = [];
|
|
8663
|
+
let totalRecords = 0;
|
|
8664
|
+
let corruptRollups = 0;
|
|
8665
|
+
let corruptRecords = 0;
|
|
8666
|
+
let scannedRecords = 0;
|
|
8667
|
+
const offset = Math.max(0, Math.min(2e3, Math.floor(options.offset ?? 0)));
|
|
8668
|
+
const readCounters = (text3) => {
|
|
8669
|
+
try {
|
|
8670
|
+
const value = JSON.parse(text3);
|
|
8671
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Invalid counters");
|
|
8672
|
+
const entries = Object.entries(value);
|
|
8673
|
+
if (entries.some(([, n]) => typeof n !== "number" || !Number.isFinite(n) || n < 0)) throw new Error("Invalid counter value");
|
|
8674
|
+
return Object.fromEntries(entries);
|
|
8675
|
+
} catch {
|
|
8676
|
+
corruptRollups++;
|
|
8677
|
+
return {};
|
|
8678
|
+
}
|
|
8679
|
+
};
|
|
8680
|
+
try {
|
|
8681
|
+
const db = this.open();
|
|
8682
|
+
available = true;
|
|
8683
|
+
startedAt = db.prepare("SELECT value FROM stratagate_dsh_diagnostic_meta WHERE key='startedAt'").get().value;
|
|
8684
|
+
rows = db.prepare("SELECT day, stage, model, version, counters_json FROM stratagate_dsh_diagnostic_daily WHERE namespace=? AND day>=? ORDER BY day, stage, model, version LIMIT 2001").all(namespace, since);
|
|
8685
|
+
const where = options.id ? "namespace=? AND id=?" : "namespace=? AND at>=? AND json_extract(record_json, '$.category') IS NOT NULL";
|
|
8686
|
+
const values = options.id ? [namespace, options.id] : [namespace, since];
|
|
8687
|
+
totalRecords = Number(db.prepare(`SELECT count(*) AS count FROM stratagate_dsh_diagnostic_records WHERE ${where}`).get(...values).count);
|
|
8688
|
+
const raw = db.prepare(`SELECT record_json FROM stratagate_dsh_diagnostic_records WHERE ${where} ORDER BY at DESC, id DESC LIMIT 20 OFFSET ?`).all(...values, offset);
|
|
8689
|
+
scannedRecords = raw.length;
|
|
8690
|
+
for (const row of raw) {
|
|
8691
|
+
try {
|
|
8692
|
+
const item = JSON.parse(row.record_json);
|
|
8693
|
+
if (!item || item.namespace !== namespace || !DIAGNOSTIC_STAGES.includes(item.stage) || ["id", "at", "model", "version"].some((key) => typeof item[key] !== "string") || !item.counters || typeof item.counters !== "object" || Array.isArray(item.counters) || Object.values(item.counters).some((n) => typeof n !== "number" || !Number.isFinite(n) || n < 0)) throw new Error("Invalid diagnostic record");
|
|
8694
|
+
records.push({
|
|
8695
|
+
id: item.id,
|
|
8696
|
+
at: item.at,
|
|
8697
|
+
namespace,
|
|
8698
|
+
stage: item.stage,
|
|
8699
|
+
model: diagnosticText(item.model, 160),
|
|
8700
|
+
version: item.version,
|
|
8701
|
+
counters: item.counters,
|
|
8702
|
+
...typeof item.taskId === "string" ? { taskId: item.taskId } : {},
|
|
8703
|
+
...typeof item.category === "string" ? { category: diagnosticText(item.category, 80) } : {},
|
|
8704
|
+
...typeof item.detail === "string" ? { detail: diagnosticText(item.detail) } : {}
|
|
8705
|
+
});
|
|
8706
|
+
} catch {
|
|
8707
|
+
corruptRecords++;
|
|
8708
|
+
}
|
|
8709
|
+
}
|
|
8710
|
+
} catch {
|
|
8711
|
+
available = false;
|
|
8712
|
+
}
|
|
8713
|
+
const parsedRows = rows.slice(0, 2e3).map((row) => ({ ...row, counters: readCounters(row.counters_json) }));
|
|
8714
|
+
for (const row of parsedRows) {
|
|
8715
|
+
const counters = row.counters;
|
|
8716
|
+
const stage = stages[row.stage] ??= {};
|
|
8717
|
+
for (const [key, value] of Object.entries(counters)) {
|
|
8718
|
+
totals[key] = (totals[key] ?? 0) + value;
|
|
8719
|
+
stage[key] = (stage[key] ?? 0) + value;
|
|
8720
|
+
}
|
|
8721
|
+
}
|
|
8722
|
+
const routes = /* @__PURE__ */ new Map();
|
|
8723
|
+
for (const row of parsedRows) {
|
|
8724
|
+
const key = JSON.stringify([row.stage, row.model, row.version]);
|
|
8725
|
+
const route = routes.get(key) ?? { stage: row.stage, model: row.model, version: row.version, counters: {} };
|
|
8726
|
+
for (const [name2, n] of Object.entries(row.counters)) route.counters[name2] = (route.counters[name2] ?? 0) + n;
|
|
8727
|
+
routes.set(key, route);
|
|
8728
|
+
}
|
|
8729
|
+
const rates = Object.fromEntries(Object.entries(stages).map(([stage, counts]) => [stage, {
|
|
8730
|
+
sampledOperations: counts.operations ?? 0,
|
|
8731
|
+
operationFailureRate: counts.operations ? (counts.operationsFailed ?? 0) / counts.operations : null,
|
|
8732
|
+
firstAttemptSuccessRate: counts.operations ? (counts.firstAttemptSucceeded ?? 0) / counts.operations : null,
|
|
8733
|
+
recoveredOperationRate: counts.operations ? (counts.operationsRecovered ?? 0) / counts.operations : null,
|
|
8734
|
+
meanOperationMs: counts.operations ? (counts.operationMs ?? 0) / counts.operations : null,
|
|
8735
|
+
meanModelMs: counts.modelCalls ? (counts.modelMs ?? 0) / counts.modelCalls : null
|
|
8736
|
+
}]));
|
|
8737
|
+
const chatTokens = stages.chat?.totalTokens ?? 0;
|
|
8738
|
+
const backgroundTokens = (totals.totalTokens ?? 0) - chatTokens;
|
|
8739
|
+
const totalsComplete = available && !corruptRollups && !this.dropped && totals.modelCalls && totals.totalTokenCalls === totals.modelCalls && !this.pending.length && rows.length <= 2e3;
|
|
8740
|
+
return {
|
|
8741
|
+
schemaVersion: 1,
|
|
8742
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8743
|
+
since,
|
|
8744
|
+
through: today,
|
|
8745
|
+
timezone: "UTC",
|
|
8746
|
+
startedAt,
|
|
8747
|
+
coverage: {
|
|
8748
|
+
available,
|
|
8749
|
+
corruptRollups,
|
|
8750
|
+
corruptRecords,
|
|
8751
|
+
processStartedAt: this.startedAt,
|
|
8752
|
+
pendingRecords: this.pending.length,
|
|
8753
|
+
droppedRecords: this.dropped,
|
|
8754
|
+
writeFailures: this.writeFailures,
|
|
8755
|
+
rollupTruncated: rows.length > 2e3,
|
|
8756
|
+
historicalBackfill: false,
|
|
8757
|
+
rawRetentionDays: 7,
|
|
8758
|
+
rollupRetentionDays: 90,
|
|
8759
|
+
totalChatCostRatio: null,
|
|
8760
|
+
netSavings: null,
|
|
8761
|
+
note: "\u7EDF\u8BA1\u4ECE\u91C7\u96C6\u542F\u7528\u540E\u5F00\u59CB\uFF1BToken \u4E3A\u9002\u914D\u5668\u62A5\u544A\u503C\uFF0C\u7F3A\u5931\u53E6\u8BA1\uFF1BmemoryInputEstimate \u4EC5\u4F30\u7B97\u5E38\u9A7B\u89C4\u5219\u3001\u5DE5\u5177\u5B9A\u4E49\u3001\u753B\u50CF\u548C\u81EA\u52A8\u4E0A\u4E0B\u6587\uFF0C\u5C1A\u672A\u5B8C\u6574\u5F52\u56E0\u5386\u53F2\u5DE5\u5177\u7ED3\u679C\u53CA\u5206\u5C42\u5BF9\u8BDD\u3002\u51C0\u6536\u76CA\u4E0E\u8D39\u7528\u5360\u6BD4\u5F85\u6D4B\u3002\u4E3B\u804A\u5929\u8986\u76D6\u5DF2\u89C2\u6D4B\u8BF7\u6C42\uFF0C\u65E0\u6CD5\u8BC1\u660E\u8D26\u5355\u5B8C\u6574\u3002"
|
|
8762
|
+
},
|
|
8763
|
+
totals,
|
|
8764
|
+
stages,
|
|
8765
|
+
rates,
|
|
8766
|
+
observedBackgroundTokenShare: totalsComplete && totals.totalTokens ? backgroundTokens / totals.totalTokens : null,
|
|
8767
|
+
definitions: "operations=\u4E00\u6B21\u8BB0\u5FC6\u6A21\u578B\u64CD\u4F5C\uFF08\u542B\u5185\u90E8\u91CD\u8BD5\uFF09\uFF1BmodelCalls=\u6D41\u5F0F\u8BF7\u6C42\u5C1D\u8BD5\uFF1Bpipeline=\u73B0\u5B58\u6301\u4E45\u4EFB\u52A1\u72B6\u6001\u3002\u540E\u53F0Token\u5360\u6BD4\u4EC5\u9488\u5BF9\u5F53\u524D\u7A7A\u95F4\u5DF2\u89C2\u6D4B\u8BF7\u6C42\uFF0C\u5E38\u9A7B\u8F93\u5165\u4F30\u7B97\u5355\u5217\uFF0C\u8D39\u7528\u4E0E\u51C0\u6536\u76CA\u672A\u6D4B\u3002",
|
|
8768
|
+
routes: [...routes.values()].slice(0, 40),
|
|
8769
|
+
omittedRoutes: Math.max(0, routes.size - 40),
|
|
8770
|
+
totalRecords,
|
|
8771
|
+
nextOffset: offset + scannedRecords < totalRecords ? offset + scannedRecords : null,
|
|
8772
|
+
records: records.map(({ namespace: _namespace, detail, ...record3 }) => ({ ...record3, ...options.details && detail ? { detail } : {} }))
|
|
8773
|
+
};
|
|
8774
|
+
}
|
|
8775
|
+
close() {
|
|
8776
|
+
if (this.closed) return;
|
|
8777
|
+
if (this.timer) clearTimeout(this.timer);
|
|
8778
|
+
this.timer = void 0;
|
|
8779
|
+
this.flush();
|
|
8780
|
+
this.closed = true;
|
|
8781
|
+
try {
|
|
8782
|
+
this.database?.close();
|
|
8783
|
+
} catch {
|
|
8784
|
+
}
|
|
8785
|
+
this.database = void 0;
|
|
8786
|
+
}
|
|
8787
|
+
};
|
|
8788
|
+
async function* observeModelStream(recorder, scope, options, next) {
|
|
8789
|
+
const start = Date.now();
|
|
8790
|
+
let usage;
|
|
8791
|
+
let finished = false;
|
|
8792
|
+
let failure;
|
|
8793
|
+
let cancelled = false;
|
|
8794
|
+
scope.calls = (scope.calls ?? 0) + 1;
|
|
8795
|
+
try {
|
|
8796
|
+
for await (const chunk of next()) {
|
|
8797
|
+
if (chunk.type === "usage") usage = chunk.usage;
|
|
8798
|
+
if (chunk.type === "finish") {
|
|
8799
|
+
finished = true;
|
|
8800
|
+
if (chunk.reason.kind === "error" || chunk.reason.kind === "aborted") {
|
|
8801
|
+
cancelled = chunk.reason.kind === "aborted";
|
|
8802
|
+
failure = cancelled ? Object.assign(new Error(chunk.reason.failure?.message ?? "aborted"), { name: "AbortError" }) : chunk.reason.failure.message;
|
|
8803
|
+
} else if (chunk.reason.kind === "max-tokens") failure = "max-tokens";
|
|
8804
|
+
}
|
|
8805
|
+
yield chunk;
|
|
8806
|
+
}
|
|
8807
|
+
} catch (error) {
|
|
8808
|
+
failure = error;
|
|
8809
|
+
cancelled = isAbortError(error);
|
|
8810
|
+
throw error;
|
|
8811
|
+
} finally {
|
|
8812
|
+
const valid = (n) => typeof n === "number" && Number.isFinite(n) && n >= 0;
|
|
8813
|
+
const known = usage && valid(usage.inputTokens) && valid(usage.outputTokens);
|
|
8814
|
+
const counters = {
|
|
8815
|
+
modelCalls: 1,
|
|
8816
|
+
modelFailed: failure !== void 0 && !cancelled ? 1 : 0,
|
|
8817
|
+
modelCancelled: cancelled || !finished && failure === void 0 ? 1 : 0,
|
|
8818
|
+
modelMs: Date.now() - start,
|
|
8819
|
+
usageCalls: known ? 1 : 0,
|
|
8820
|
+
missingUsageCalls: known ? 0 : 1
|
|
8821
|
+
};
|
|
8822
|
+
if (scope.stage === "chat" && scope.memoryInputEstimate !== void 0) {
|
|
8823
|
+
counters.memoryInputEstimate = scope.memoryInputEstimate;
|
|
8824
|
+
counters.memoryInputEstimateCalls = 1;
|
|
8825
|
+
}
|
|
8826
|
+
if (known && usage) {
|
|
8827
|
+
counters.inputTokens = usage.inputTokens;
|
|
8828
|
+
counters.outputTokens = usage.outputTokens;
|
|
8829
|
+
if (valid(usage.cacheReadTokens)) {
|
|
8830
|
+
counters.cacheReadTokens = usage.cacheReadTokens;
|
|
8831
|
+
counters.cacheReadKnownCalls = 1;
|
|
8832
|
+
}
|
|
8833
|
+
if (valid(usage.cacheWriteTokens)) {
|
|
8834
|
+
counters.cacheWriteTokens = usage.cacheWriteTokens;
|
|
8835
|
+
counters.cacheWriteKnownCalls = 1;
|
|
8836
|
+
}
|
|
8837
|
+
if (valid(usage.reasoningTokens)) counters.reasoningTokens = usage.reasoningTokens;
|
|
8838
|
+
if (valid(usage.totalTokens) || valid(usage.cacheReadTokens) && valid(usage.cacheWriteTokens)) {
|
|
8839
|
+
counters.totalTokens = valid(usage.totalTokens) ? usage.totalTokens : counters.inputTokens + counters.outputTokens + counters.cacheReadTokens + counters.cacheWriteTokens;
|
|
8840
|
+
counters.totalTokenCalls = 1;
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
recorder.record(scope, counters, { model: `${options.provider}/${options.model}`, ...failure !== void 0 ? { error: failure } : {} });
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
|
|
8524
8847
|
// src/llm.ts
|
|
8525
8848
|
var ELEMENT_TYPES2 = /* @__PURE__ */ new Set(["person", "project", "organization", "tool", "place"]);
|
|
8526
8849
|
var CRITICALITIES = /* @__PURE__ */ new Set(["routine", "preference", "identity", "safety"]);
|
|
@@ -9085,6 +9408,16 @@ var DshModelBridge = class {
|
|
|
9085
9408
|
ctx;
|
|
9086
9409
|
config;
|
|
9087
9410
|
liveStructuredReasoningEffort;
|
|
9411
|
+
diagnosticScopes = new AsyncLocalStorage();
|
|
9412
|
+
diagnostics;
|
|
9413
|
+
diagnosticNamespace = () => "@shared";
|
|
9414
|
+
setDiagnostics(recorder, namespace) {
|
|
9415
|
+
this.diagnostics = recorder;
|
|
9416
|
+
this.diagnosticNamespace = namespace;
|
|
9417
|
+
}
|
|
9418
|
+
currentDiagnosticScope() {
|
|
9419
|
+
return this.diagnosticScopes.getStore();
|
|
9420
|
+
}
|
|
9088
9421
|
contextWindows = /* @__PURE__ */ new Map();
|
|
9089
9422
|
sessions = new AsyncLocalStorage();
|
|
9090
9423
|
successfulResponses = [];
|
|
@@ -9117,8 +9450,8 @@ var DshModelBridge = class {
|
|
|
9117
9450
|
run(session, operation) {
|
|
9118
9451
|
return this.sessions.run({ session, sessionId: session.id }, operation);
|
|
9119
9452
|
}
|
|
9120
|
-
runDetached(sessionId, operation, signal) {
|
|
9121
|
-
return this.sessions.run({ sessionId, ...signal ? { signal } : {} }, operation);
|
|
9453
|
+
runDetached(sessionId, operation, signal, namespace) {
|
|
9454
|
+
return this.sessions.run({ sessionId, ...signal ? { signal } : {}, ...namespace ? { namespace } : {} }, operation);
|
|
9122
9455
|
}
|
|
9123
9456
|
dreamingModelOptions() {
|
|
9124
9457
|
return { ...this.resolveRoute(), maxTokens: TOPIC_OUTPUT_TOKEN_BUDGET };
|
|
@@ -9399,6 +9732,40 @@ Use project scope for repository decisions, user scope for stable preferences/id
|
|
|
9399
9732
|
return proposed;
|
|
9400
9733
|
}
|
|
9401
9734
|
async callStructured(kind, system, payload, validate, topicMetadata) {
|
|
9735
|
+
const execution = this.sessions.getStore();
|
|
9736
|
+
const scope = {
|
|
9737
|
+
namespace: execution?.namespace ?? this.diagnosticNamespace(execution?.session, String(execution?.sessionId ?? "")),
|
|
9738
|
+
stage: kind,
|
|
9739
|
+
taskId: `task_${randomUUID4()}`,
|
|
9740
|
+
calls: 0
|
|
9741
|
+
};
|
|
9742
|
+
const start = Date.now();
|
|
9743
|
+
return this.diagnosticScopes.run(scope, async () => {
|
|
9744
|
+
try {
|
|
9745
|
+
const result = await this.callStructuredInner(kind, system, payload, validate, topicMetadata);
|
|
9746
|
+
this.diagnostics?.record(scope, {
|
|
9747
|
+
operations: 1,
|
|
9748
|
+
operationsSucceeded: 1,
|
|
9749
|
+
operationsFailed: 0,
|
|
9750
|
+
operationsRecovered: (scope.calls ?? 0) > 1 ? 1 : 0,
|
|
9751
|
+
firstAttemptSucceeded: (scope.calls ?? 0) === 1 ? 1 : 0,
|
|
9752
|
+
retries: Math.max(0, (scope.calls ?? 0) - 1),
|
|
9753
|
+
operationMs: Date.now() - start
|
|
9754
|
+
});
|
|
9755
|
+
return result;
|
|
9756
|
+
} catch (error) {
|
|
9757
|
+
this.diagnostics?.record(scope, {
|
|
9758
|
+
operations: 1,
|
|
9759
|
+
operationsSucceeded: 0,
|
|
9760
|
+
operationsFailed: 1,
|
|
9761
|
+
retries: Math.max(0, (scope.calls ?? 0) - 1),
|
|
9762
|
+
operationMs: Date.now() - start
|
|
9763
|
+
}, { error });
|
|
9764
|
+
throw error;
|
|
9765
|
+
}
|
|
9766
|
+
});
|
|
9767
|
+
}
|
|
9768
|
+
async callStructuredInner(kind, system, payload, validate, topicMetadata) {
|
|
9402
9769
|
const execution = this.sessions.getStore();
|
|
9403
9770
|
if (!execution) throw new Error("StrataGate model callback ran without an execution context");
|
|
9404
9771
|
const baseRoute = this.resolveRoute(execution.session);
|
|
@@ -9633,6 +10000,8 @@ Correct these canonical-name provenance fields: ${[...new Set(paths)].slice(0, 2
|
|
|
9633
10000
|
return parsed;
|
|
9634
10001
|
} catch (error) {
|
|
9635
10002
|
if (!(error instanceof ModelJsonResponseError) && !(isTopic && error instanceof TopicProjectionError)) throw error;
|
|
10003
|
+
const scope = this.diagnosticScopes.getStore();
|
|
10004
|
+
if (scope) this.diagnostics?.record(scope, { validationFailures: 1 }, { error });
|
|
9636
10005
|
let retryError = error;
|
|
9637
10006
|
if (isTopic && error instanceof TopicProjectionError) {
|
|
9638
10007
|
const safe = new TopicProjectionError(error.diagnostics.category, error.diagnostics.reason, { ...topicDiagnostics, ...error.diagnostics });
|
|
@@ -9734,7 +10103,9 @@ Correct the previous Topic output using these validation errors: ${JSON.stringif
|
|
|
9734
10103
|
try {
|
|
9735
10104
|
await Promise.race([
|
|
9736
10105
|
(async () => {
|
|
9737
|
-
|
|
10106
|
+
const scope = this.diagnosticScopes.getStore();
|
|
10107
|
+
const stream = this.diagnostics && scope ? observeModelStream(this.diagnostics, scope, timedRequest, () => this.ctx.llm.stream(timedRequest)) : this.ctx.llm.stream(timedRequest);
|
|
10108
|
+
for await (const chunk of stream) assembler.push(chunk);
|
|
9738
10109
|
})(),
|
|
9739
10110
|
timeout,
|
|
9740
10111
|
aborted
|
|
@@ -9776,7 +10147,7 @@ function isOffRejection(error) {
|
|
|
9776
10147
|
}
|
|
9777
10148
|
|
|
9778
10149
|
// src/metadata.ts
|
|
9779
|
-
import { DatabaseSync as
|
|
10150
|
+
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
9780
10151
|
var TOPIC_BOOTSTRAP_WINDOW_MS = 10 * 6e4;
|
|
9781
10152
|
var TOPIC_BOOTSTRAP_WINDOW_CALLS = 2;
|
|
9782
10153
|
var METADATA_SCHEMA = `
|
|
@@ -9799,7 +10170,7 @@ CREATE TABLE IF NOT EXISTS stratagate_dsh_feedback_drafts (
|
|
|
9799
10170
|
) STRICT;
|
|
9800
10171
|
`;
|
|
9801
10172
|
function dropLegacyAgentMemoriesTable(filename) {
|
|
9802
|
-
const database = new
|
|
10173
|
+
const database = new DatabaseSync3(filename);
|
|
9803
10174
|
try {
|
|
9804
10175
|
const legacyTable = database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'stratagate_dsh_agent_memories'").get();
|
|
9805
10176
|
if (!legacyTable) return;
|
|
@@ -9812,7 +10183,7 @@ function dropLegacyAgentMemoriesTable(filename) {
|
|
|
9812
10183
|
var DshMetadataStore = class {
|
|
9813
10184
|
database;
|
|
9814
10185
|
constructor(filename) {
|
|
9815
|
-
this.database = new
|
|
10186
|
+
this.database = new DatabaseSync3(filename);
|
|
9816
10187
|
this.database.exec(METADATA_SCHEMA);
|
|
9817
10188
|
}
|
|
9818
10189
|
/** Database-wide, durable reservation before any historical model attempt.
|
|
@@ -9942,15 +10313,10 @@ var DshMetadataStore = class {
|
|
|
9942
10313
|
};
|
|
9943
10314
|
|
|
9944
10315
|
// src/runtime.ts
|
|
9945
|
-
import { createHash as createHash3, randomUUID as
|
|
9946
|
-
|
|
9947
|
-
// src/feedback-policy.ts
|
|
9948
|
-
var AGENT_FEEDBACK_ENABLED = false;
|
|
9949
|
-
|
|
9950
|
-
// src/runtime.ts
|
|
10316
|
+
import { createHash as createHash3, randomUUID as randomUUID5 } from "node:crypto";
|
|
9951
10317
|
import { existsSync } from "node:fs";
|
|
9952
10318
|
import { dirname, resolve as resolve2 } from "node:path";
|
|
9953
|
-
import { DatabaseSync as
|
|
10319
|
+
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
9954
10320
|
import { createUserMessage as createUserMessage2 } from "@deepseek-ai/dsh-llm";
|
|
9955
10321
|
import { openNativePath } from "@deepseek-ai/dsh-native-command";
|
|
9956
10322
|
import { validateArgs as validateArgs2 } from "@deepseek-ai/dsh-tools";
|
|
@@ -10507,7 +10873,6 @@ function graphProjectionCanRun(job, now = Date.now()) {
|
|
|
10507
10873
|
var AUTO_EVENT_LIMIT = 4;
|
|
10508
10874
|
var AUTO_ELEMENT_LIMIT = 4;
|
|
10509
10875
|
var AUTO_MEMORY_TOKEN_BUDGET = 900;
|
|
10510
|
-
var FEEDBACK_PROMPT_COOLDOWN_MS = 5 * 24 * 60 * 60 * 1e3;
|
|
10511
10876
|
function projectKey(cwd) {
|
|
10512
10877
|
const canonical2 = resolve2(cwd ?? process.cwd()).replaceAll("\\", "/").toLowerCase();
|
|
10513
10878
|
return createHash3("sha256").update(canonical2).digest("hex").slice(0, 20);
|
|
@@ -10590,6 +10955,8 @@ function normalizeFeedbackDraft(input, previous) {
|
|
|
10590
10955
|
expected: replacesStructuredBody ? "" : has("expected") ? feedbackText(input.expected, 1e4) : previous?.expected ?? "",
|
|
10591
10956
|
actual: replacesStructuredBody ? "" : has("actual") ? feedbackText(input.actual, 1e4) : previous?.actual ?? "",
|
|
10592
10957
|
errorContext: replacesStructuredBody ? "" : has("errorContext") ? feedbackText(input.errorContext, 2e4) : previous?.errorContext ?? "",
|
|
10958
|
+
...previous?.aiPrepared ? { aiPrepared: true } : {},
|
|
10959
|
+
...previous?.diagnostics ? { diagnostics: previous.diagnostics } : {},
|
|
10593
10960
|
...bodyMarkdown ? { bodyMarkdown } : {},
|
|
10594
10961
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10595
10962
|
};
|
|
@@ -10613,6 +10980,8 @@ var StrataGateRuntime = class {
|
|
|
10613
10980
|
this.flushNativeSession = flushNativeSession;
|
|
10614
10981
|
this.feedbackOrigin = feedbackOrigin;
|
|
10615
10982
|
this.openPath = openPath;
|
|
10983
|
+
this.diagnostics = new DiagnosticsRecorder(config.database);
|
|
10984
|
+
this.models.setDiagnostics?.(this.diagnostics, (session, sessionId) => session ? this.namespaceFor(session) : this.diagnosticNamespaceForSession(sessionId ?? "") ?? "@shared");
|
|
10616
10985
|
this.blockTurnSize = config.blockTurnSize;
|
|
10617
10986
|
this.blockDecayLambda = config.blockDecayLambda;
|
|
10618
10987
|
this.agentMemoryRetrievalWeight = config.agentMemoryRetrievalWeight ?? 1;
|
|
@@ -10626,6 +10995,9 @@ var StrataGateRuntime = class {
|
|
|
10626
10995
|
flushNativeSession;
|
|
10627
10996
|
feedbackOrigin;
|
|
10628
10997
|
openPath;
|
|
10998
|
+
diagnostics;
|
|
10999
|
+
diagnosticSessionNamespaces = /* @__PURE__ */ new Map();
|
|
11000
|
+
diagnosticMemoryEstimates = /* @__PURE__ */ new Map();
|
|
10629
11001
|
profileStorage;
|
|
10630
11002
|
folder = new TurnFolder();
|
|
10631
11003
|
spaces = /* @__PURE__ */ new Map();
|
|
@@ -10642,11 +11014,10 @@ var StrataGateRuntime = class {
|
|
|
10642
11014
|
externalImportRuns = /* @__PURE__ */ new Map();
|
|
10643
11015
|
dreamingRuns = /* @__PURE__ */ new Map();
|
|
10644
11016
|
dreamingControllers = /* @__PURE__ */ new Map();
|
|
10645
|
-
dreamingOwner =
|
|
11017
|
+
dreamingOwner = randomUUID5();
|
|
10646
11018
|
dreamingHost;
|
|
10647
11019
|
adminJobRetryRuns = /* @__PURE__ */ new Map();
|
|
10648
11020
|
feedbackDrafts = /* @__PURE__ */ new Map();
|
|
10649
|
-
pendingFeedbackSuggestionSessions = /* @__PURE__ */ new Set();
|
|
10650
11021
|
pendingTurns = /* @__PURE__ */ new Map();
|
|
10651
11022
|
drainTimers = /* @__PURE__ */ new Map();
|
|
10652
11023
|
drainBackoffMs = /* @__PURE__ */ new Map();
|
|
@@ -10666,7 +11037,6 @@ var StrataGateRuntime = class {
|
|
|
10666
11037
|
blockTurnSize;
|
|
10667
11038
|
blockDecayLambda;
|
|
10668
11039
|
agentMemoryRetrievalWeight;
|
|
10669
|
-
transientLastFeedbackPromptAt = null;
|
|
10670
11040
|
get agentMemoryEnabled() {
|
|
10671
11041
|
return this.config.agentMemoryEnabled !== false;
|
|
10672
11042
|
}
|
|
@@ -10827,7 +11197,9 @@ var StrataGateRuntime = class {
|
|
|
10827
11197
|
}
|
|
10828
11198
|
}
|
|
10829
11199
|
return resumed2;
|
|
10830
|
-
}
|
|
11200
|
+
},
|
|
11201
|
+
void 0,
|
|
11202
|
+
namespace
|
|
10831
11203
|
);
|
|
10832
11204
|
await this.persistSuccessfulResponses(memory);
|
|
10833
11205
|
const sessionsToSync = /* @__PURE__ */ new Set();
|
|
@@ -11200,6 +11572,12 @@ var StrataGateRuntime = class {
|
|
|
11200
11572
|
}
|
|
11201
11573
|
const memory = await this.space(session);
|
|
11202
11574
|
const assessment = memory.assessRetrieval(input, new Set(batch.refs.keys()));
|
|
11575
|
+
this.diagnostics.record({ namespace: this.namespaceFor(session), stage: "retrieval" }, {
|
|
11576
|
+
assessments: 1,
|
|
11577
|
+
sufficient: assessment.verdict === "sufficient" ? 1 : 0,
|
|
11578
|
+
partial: assessment.verdict === "partial" ? 1 : 0,
|
|
11579
|
+
wrong: assessment.verdict === "wrong" ? 1 : 0
|
|
11580
|
+
});
|
|
11203
11581
|
batch.assessment = assessment;
|
|
11204
11582
|
return {
|
|
11205
11583
|
batchId: batch.id,
|
|
@@ -11516,10 +11894,10 @@ var StrataGateRuntime = class {
|
|
|
11516
11894
|
await Promise.allSettled(this.externalImportRuns.values());
|
|
11517
11895
|
await Promise.allSettled(this.dreamingRuns.values());
|
|
11518
11896
|
await this.dreamingHost?.close();
|
|
11897
|
+
this.diagnostics.close();
|
|
11519
11898
|
await Promise.all(settled.flatMap((result) => result.status === "fulfilled" ? [result.value.close()] : []));
|
|
11520
11899
|
if (this.profileStorage) await this.profileStorage.close();
|
|
11521
11900
|
this.sessionsById.clear();
|
|
11522
|
-
this.pendingFeedbackSuggestionSessions.clear();
|
|
11523
11901
|
if (flushError !== void 0) throw flushError;
|
|
11524
11902
|
}
|
|
11525
11903
|
namespaceFor(session) {
|
|
@@ -11528,10 +11906,75 @@ var StrataGateRuntime = class {
|
|
|
11528
11906
|
if (this.config.namespaceMode === "session") return `${prefix}:session:${String(session.id)}`;
|
|
11529
11907
|
return `${prefix}:project:${projectKey(session.header.cwd)}`;
|
|
11530
11908
|
}
|
|
11909
|
+
trackDiagnosticSession(sessionId, namespace, memoryInputEstimate) {
|
|
11910
|
+
this.diagnosticSessionNamespaces.set(sessionId, namespace);
|
|
11911
|
+
if (memoryInputEstimate !== void 0) this.diagnosticMemoryEstimates.set(sessionId, memoryInputEstimate);
|
|
11912
|
+
if (this.diagnosticSessionNamespaces.size > 256) {
|
|
11913
|
+
const oldest = this.diagnosticSessionNamespaces.keys().next().value;
|
|
11914
|
+
this.diagnosticSessionNamespaces.delete(oldest);
|
|
11915
|
+
this.diagnosticMemoryEstimates.delete(oldest);
|
|
11916
|
+
}
|
|
11917
|
+
}
|
|
11918
|
+
diagnosticMemoryEstimate(sessionId) {
|
|
11919
|
+
return this.diagnosticMemoryEstimates.get(sessionId);
|
|
11920
|
+
}
|
|
11921
|
+
diagnosticNamespaceForSession(sessionId) {
|
|
11922
|
+
const session = this.knownSessions.get(sessionId)?.deref();
|
|
11923
|
+
return session ? this.namespaceFor(session) : this.diagnosticSessionNamespaces.get(sessionId);
|
|
11924
|
+
}
|
|
11925
|
+
async diagnosticReport(namespace, options = {}) {
|
|
11926
|
+
const collected = this.diagnostics.snapshot(namespace, options);
|
|
11927
|
+
const shared = this.diagnostics.snapshot("@shared");
|
|
11928
|
+
const base = { ...collected, sharedOrUnattributed: {
|
|
11929
|
+
stages: shared.stages,
|
|
11930
|
+
note: "\u6570\u636E\u5E93\u5171\u4EAB\u753B\u50CF\u7EF4\u62A4\u6216\u65E0\u6CD5\u5F52\u5C5E\u7684\u6A21\u578B\u64CD\u4F5C\uFF0C\u5355\u5217\u5C55\u793A\uFF0C\u672A\u5206\u644A\u5230\u5F53\u524D\u5DE5\u4F5C\u533A\u3002"
|
|
11931
|
+
} };
|
|
11932
|
+
try {
|
|
11933
|
+
const snapshot = await this.adminSnapshot(namespace);
|
|
11934
|
+
if (!snapshot) return { ...base, pipeline: { available: false } };
|
|
11935
|
+
const stages = {
|
|
11936
|
+
summarizer: snapshot.summaryJobs,
|
|
11937
|
+
extractor: snapshot.extractionJobs,
|
|
11938
|
+
graphProjector: snapshot.graphProjectionJobs,
|
|
11939
|
+
topicProjector: (snapshot.memoryTopicState?.jobs ?? []).filter((job) => !job.superseded),
|
|
11940
|
+
externalMemoryImport: snapshot.externalMemoryImportJobs
|
|
11941
|
+
};
|
|
11942
|
+
const pipeline = Object.fromEntries(Object.entries(stages).map(([stage, jobs]) => [stage, {
|
|
11943
|
+
total: jobs.length,
|
|
11944
|
+
failed: jobs.filter((j) => j.status === "failed").length,
|
|
11945
|
+
succeeded: jobs.filter((j) => ["succeeded", "completed"].includes(j.status)).length,
|
|
11946
|
+
skipped: jobs.filter((j) => j.status === "skipped").length,
|
|
11947
|
+
pending: jobs.filter((j) => ["pending", "running", "processing", "extracting", "deciding"].includes(j.status)).length,
|
|
11948
|
+
oldestPendingUpdatedAt: jobs.filter((j) => ["pending", "running", "processing"].includes(j.status)).map((j) => j.updatedAt).sort()[0] ?? null
|
|
11949
|
+
}]));
|
|
11950
|
+
const adoptions = snapshot.usageReceipts.filter((r) => r.createdAt >= collected.since);
|
|
11951
|
+
const adopted = adoptions.filter((r) => r.eventIds.length > 0 || r.elementIds.length > 0);
|
|
11952
|
+
const sampledBlocks = snapshot.blocks.slice(-64);
|
|
11953
|
+
const layerTokenEstimates = Object.fromEntries([0, 1, 2, 3, 4, 5].map((level) => [
|
|
11954
|
+
`L${level}`,
|
|
11955
|
+
sampledBlocks.reduce((sum, block) => sum + estimateTokens(renderBlock(block, level)), 0)
|
|
11956
|
+
]));
|
|
11957
|
+
return { ...base, pipeline: { available: true, stages: pipeline }, benefits: {
|
|
11958
|
+
retrievalReceipts: adoptions.length,
|
|
11959
|
+
adoptionReceipts: adopted.length,
|
|
11960
|
+
adoptedEvents: adopted.reduce((n, r) => n + r.eventIds.length, 0),
|
|
11961
|
+
blocks: snapshot.blocks.length,
|
|
11962
|
+
events: snapshot.events.length,
|
|
11963
|
+
graphNodes: snapshot.graphNodes.length,
|
|
11964
|
+
sampledBlocks: sampledBlocks.length,
|
|
11965
|
+
layerTokenEstimates,
|
|
11966
|
+
note: "\u5206\u5C42Token\u4E3A\u6700\u8FD1\u6700\u591A64\u4E2A\u5B58\u50A8\u5757\u7684\u5185\u5BB9\u4F53\u79EF\u4F30\u7B97\uFF0C\u5404\u4F1A\u8BDD\u5B9E\u9645\u5C42\u7EA7\u4E0D\u540C\uFF1B\u91C7\u7528\u6B21\u6570\u4E0E\u5185\u5BB9\u538B\u7F29\u6BD4\u4F8B\u4E0D\u7B49\u4E8E\u7B54\u6848\u8D28\u91CF\u6216\u8D26\u5355\u51C0\u6536\u76CA\u3002"
|
|
11967
|
+
} };
|
|
11968
|
+
} catch {
|
|
11969
|
+
return { ...base, pipeline: { available: false } };
|
|
11970
|
+
}
|
|
11971
|
+
}
|
|
11531
11972
|
async prepareFeedback(session, input) {
|
|
11532
11973
|
const namespace = this.namespaceFor(session);
|
|
11533
|
-
const previous = this.loadFeedbackDraft(namespace);
|
|
11974
|
+
const previous = input.newDraft ? null : this.loadFeedbackDraft(namespace);
|
|
11534
11975
|
const draft = normalizeFeedbackDraft(input, previous);
|
|
11976
|
+
draft.aiPrepared = true;
|
|
11977
|
+
draft.diagnostics = await this.diagnosticReport(namespace);
|
|
11535
11978
|
this.saveFeedbackDraft(namespace, draft);
|
|
11536
11979
|
const feedbackUrl = feedbackDraftUrl(namespace, this.feedbackOrigin());
|
|
11537
11980
|
return {
|
|
@@ -11540,7 +11983,7 @@ var StrataGateRuntime = class {
|
|
|
11540
11983
|
submitted: false,
|
|
11541
11984
|
namespace,
|
|
11542
11985
|
feedbackUrl,
|
|
11543
|
-
message: `\u53CD\u9988\u8349\u7A3F\u5DF2\
|
|
11986
|
+
message: `\u53CD\u9988\u8349\u7A3F\u5DF2\u4FDD\u5B58\u5728\u672C\u5730\uFF0C\u90AE\u4EF6\u5C1A\u672A\u53D1\u9001\u3002
|
|
11544
11987
|
|
|
11545
11988
|
[\u6253\u5F00\u53CD\u9988\u8349\u7A3F](${feedbackUrl})`
|
|
11546
11989
|
};
|
|
@@ -11645,46 +12088,13 @@ var StrataGateRuntime = class {
|
|
|
11645
12088
|
items.sort((left, right) => String(right.createdAt).localeCompare(String(left.createdAt)));
|
|
11646
12089
|
return { items, total: items.length };
|
|
11647
12090
|
}
|
|
11648
|
-
notePluginError(session,
|
|
11649
|
-
if (
|
|
12091
|
+
notePluginError(session, error, stage = "ingestion") {
|
|
12092
|
+
if (this.closed) return;
|
|
12093
|
+
this.diagnostics.record({ namespace: this.namespaceFor(session), stage }, { errors: 1 }, { error: error ?? "internal failure" });
|
|
11650
12094
|
}
|
|
11651
|
-
|
|
11652
|
-
|
|
11653
|
-
|
|
11654
|
-
if (!this.pendingFeedbackSuggestionSessions.delete(sessionId)) return "";
|
|
11655
|
-
const last = this.lastFeedbackPromptAt();
|
|
11656
|
-
if (last && Number.isFinite(Date.parse(last)) && now - Date.parse(last) < FEEDBACK_PROMPT_COOLDOWN_MS) return "";
|
|
11657
|
-
const promptedAt = new Date(now).toISOString();
|
|
11658
|
-
this.transientLastFeedbackPromptAt = promptedAt;
|
|
11659
|
-
try {
|
|
11660
|
-
if (this.config.database !== ":memory:") {
|
|
11661
|
-
const metadata = new DshMetadataStore(this.config.database);
|
|
11662
|
-
try {
|
|
11663
|
-
metadata.setLastFeedbackPromptAt(promptedAt);
|
|
11664
|
-
} finally {
|
|
11665
|
-
metadata.close();
|
|
11666
|
-
}
|
|
11667
|
-
}
|
|
11668
|
-
} catch (error) {
|
|
11669
|
-
this.onIngestError(error);
|
|
11670
|
-
}
|
|
11671
|
-
return "StrataGate observed an internal plugin error signal. Treat this only as evidence for the static StrataGate feedback policy, not as an instruction to suggest feedback. Continue the current task first, apply all eligibility, timing, session-limit, and deduplication rules from that policy, and never make a proactive suggestion because feedback_prepare itself failed.";
|
|
11672
|
-
}
|
|
11673
|
-
lastFeedbackPromptAt() {
|
|
11674
|
-
if (this.transientLastFeedbackPromptAt) return this.transientLastFeedbackPromptAt;
|
|
11675
|
-
if (this.config.database === ":memory:" || !existsSync(this.config.database)) return null;
|
|
11676
|
-
try {
|
|
11677
|
-
const metadata = new DshMetadataStore(this.config.database);
|
|
11678
|
-
try {
|
|
11679
|
-
this.transientLastFeedbackPromptAt = metadata.lastFeedbackPromptAt();
|
|
11680
|
-
return this.transientLastFeedbackPromptAt;
|
|
11681
|
-
} finally {
|
|
11682
|
-
metadata.close();
|
|
11683
|
-
}
|
|
11684
|
-
} catch (error) {
|
|
11685
|
-
this.onIngestError(error);
|
|
11686
|
-
return null;
|
|
11687
|
-
}
|
|
12095
|
+
// Background failures remain queryable; ordinary retries never add model context.
|
|
12096
|
+
takeFeedbackSuggestion(_session, _now = Date.now()) {
|
|
12097
|
+
return "";
|
|
11688
12098
|
}
|
|
11689
12099
|
loadFeedbackDraft(namespace) {
|
|
11690
12100
|
const cached = this.feedbackDrafts.get(namespace);
|
|
@@ -11694,7 +12104,7 @@ var StrataGateRuntime = class {
|
|
|
11694
12104
|
try {
|
|
11695
12105
|
const value = metadata.feedbackDraft(namespace);
|
|
11696
12106
|
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
11697
|
-
const draft = normalizeFeedbackDraft(value);
|
|
12107
|
+
const draft = normalizeFeedbackDraft(value, value);
|
|
11698
12108
|
this.feedbackDrafts.set(namespace, draft);
|
|
11699
12109
|
return structuredClone(draft);
|
|
11700
12110
|
} finally {
|
|
@@ -11702,14 +12112,15 @@ var StrataGateRuntime = class {
|
|
|
11702
12112
|
}
|
|
11703
12113
|
}
|
|
11704
12114
|
saveFeedbackDraft(namespace, draft) {
|
|
11705
|
-
this.
|
|
11706
|
-
|
|
11707
|
-
|
|
11708
|
-
|
|
11709
|
-
|
|
11710
|
-
|
|
11711
|
-
|
|
12115
|
+
if (this.config.database !== ":memory:") {
|
|
12116
|
+
const metadata = new DshMetadataStore(this.config.database);
|
|
12117
|
+
try {
|
|
12118
|
+
metadata.setFeedbackDraft(namespace, draft);
|
|
12119
|
+
} finally {
|
|
12120
|
+
metadata.close();
|
|
12121
|
+
}
|
|
11712
12122
|
}
|
|
12123
|
+
this.feedbackDrafts.set(namespace, structuredClone(draft));
|
|
11713
12124
|
}
|
|
11714
12125
|
async adminNamespaces() {
|
|
11715
12126
|
if (this.config.database === ":memory:" || !existsSync(this.config.database)) return [];
|
|
@@ -11964,7 +12375,7 @@ var StrataGateRuntime = class {
|
|
|
11964
12375
|
} finally {
|
|
11965
12376
|
if (owned) await memory.close();
|
|
11966
12377
|
}
|
|
11967
|
-
const action = await this.models.runDetached(`dreaming:${run.id}`, () => this.models.dreamingStep(payload), controller.signal);
|
|
12378
|
+
const action = await this.models.runDetached(`dreaming:${run.id}`, () => this.models.dreamingStep(payload), controller.signal, namespace);
|
|
11968
12379
|
if (controller.signal.aborted) return;
|
|
11969
12380
|
const repeated = run.trace.filter((entry) => entry.tool === action.tool && JSON.stringify(entry.args) === JSON.stringify(action.args)).length;
|
|
11970
12381
|
if (repeated >= 3) {
|
|
@@ -12058,7 +12469,7 @@ var StrataGateRuntime = class {
|
|
|
12058
12469
|
}
|
|
12059
12470
|
try {
|
|
12060
12471
|
if (job.status === "extracting") {
|
|
12061
|
-
const recovered = await this.models.runDetached(`admin-import-recovery:${jobId}`, () => this.models.externalMemoryExtractor({ text: job.text, importedAt: job.importedAt }));
|
|
12472
|
+
const recovered = await this.models.runDetached(`admin-import-recovery:${jobId}`, () => this.models.externalMemoryExtractor({ text: job.text, importedAt: job.importedAt }), void 0, namespace);
|
|
12062
12473
|
const responses2 = this.takeSuccessfulResponses();
|
|
12063
12474
|
await this.retryExternalImportWrite(namespace, (memory) => memory.completeExternalMemoryFallback(jobId, recovered));
|
|
12064
12475
|
await this.persistExternalImportResponses(namespace, responses2);
|
|
@@ -12073,7 +12484,7 @@ var StrataGateRuntime = class {
|
|
|
12073
12484
|
decision = await this.models.runDetached(`admin-import:${jobId}`, () => this.models.externalMemoryDecider({
|
|
12074
12485
|
candidate: structuredClone(work.candidate),
|
|
12075
12486
|
matches: structuredClone(work.matches)
|
|
12076
|
-
}));
|
|
12487
|
+
}), void 0, namespace);
|
|
12077
12488
|
responses = this.takeSuccessfulResponses();
|
|
12078
12489
|
}
|
|
12079
12490
|
await this.retryExternalImportWrite(namespace, (memory) => memory.completeNextExternalMemoryImport(
|
|
@@ -12214,7 +12625,7 @@ var StrataGateRuntime = class {
|
|
|
12214
12625
|
const remembered = this.workspaceNames.get(namespace);
|
|
12215
12626
|
if (remembered) return remembered;
|
|
12216
12627
|
if (this.config.database === ":memory:" || !existsSync(this.config.database)) return null;
|
|
12217
|
-
const database = new
|
|
12628
|
+
const database = new DatabaseSync4(this.config.database, { readOnly: true });
|
|
12218
12629
|
try {
|
|
12219
12630
|
if (!database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'stratagate_dsh_workspaces'").get()) {
|
|
12220
12631
|
return null;
|
|
@@ -12344,7 +12755,7 @@ var StrataGateRuntime = class {
|
|
|
12344
12755
|
if (!this.models.isReady(session)) {
|
|
12345
12756
|
throw new Error("StrataGate model adapter is not ready; retry after DSH finishes registering adapters");
|
|
12346
12757
|
}
|
|
12347
|
-
const result = session && this.namespaceFor(session) === key ? await this.models.run(session, retry) : await this.models.runDetached(threadId, retry);
|
|
12758
|
+
const result = session && this.namespaceFor(session) === key ? await this.models.run(session, retry) : await this.models.runDetached(threadId, retry, void 0, namespace);
|
|
12348
12759
|
await this.persistSuccessfulResponses(memory);
|
|
12349
12760
|
const currentBlock = blockId ? memory.listBlocks().find(({ id: candidateId }) => candidateId === blockId) : void 0;
|
|
12350
12761
|
if (kind !== "graph-projection" && currentBlock?.processingStatus === "ready" && currentBlock.threadId) {
|
|
@@ -12719,6 +13130,12 @@ var StrataGateRuntime = class {
|
|
|
12719
13130
|
}
|
|
12720
13131
|
sessionBatches.set(id, { id, sequence, refs, status: "unresolved" });
|
|
12721
13132
|
this.latestBatchIds.set(key, id);
|
|
13133
|
+
this.diagnostics.record({ namespace: this.namespaceFor(session), stage: "retrieval" }, {
|
|
13134
|
+
batches: 1,
|
|
13135
|
+
emptyBatches: evidence.length === 0 ? 1 : 0,
|
|
13136
|
+
returnedRefs: refs.size,
|
|
13137
|
+
resultTokensEstimate: estimateTokens(JSON.stringify(output))
|
|
13138
|
+
});
|
|
12722
13139
|
return output;
|
|
12723
13140
|
}
|
|
12724
13141
|
requireBatch(session, batchId, operation) {
|
|
@@ -13308,6 +13725,7 @@ ${profile}
|
|
|
13308
13725
|
throw new Error("\u672A\u627E\u5230\u672C\u76EE\u5F55\u6240\u5C5E\u4F1A\u8BDD\u7684\u5DE5\u4F5C\u533A\u8DEF\u5F84\uFF0C\u8BF7\u5148\u6253\u5F00\u8BE5\u5DE5\u4F5C\u533A\u7684\u666E\u901A\u4F1A\u8BDD\u540E\u91CD\u8BD5");
|
|
13309
13726
|
}
|
|
13310
13727
|
install(scoped, binding) {
|
|
13728
|
+
this.runtime.trackDiagnosticSession(String(binding.agent.id), binding.namespace);
|
|
13311
13729
|
if (typeof scoped.tools.restrict !== "function" || typeof scoped.tools.guard !== "function" || typeof DshTools.parameterSchemaSpecToJsonSchema !== "function" || !binding.agent.session.surface?.nodes || typeof binding.agent.whenIdle !== "function") throw new Error("\u5F53\u524D DSH \u7F3A\u5C11\u5B89\u5168\u7684 Dreaming Agent \u63A5\u53E3\uFF0C\u8BF7\u5347\u7EA7\u5BBF\u4E3B\u540E\u91CD\u8BD5");
|
|
13312
13730
|
const modelTools = TOOLS.map((tool) => ({
|
|
13313
13731
|
name: tool.name,
|
|
@@ -13566,6 +13984,11 @@ ${profile}
|
|
|
13566
13984
|
|
|
13567
13985
|
// src/tools.ts
|
|
13568
13986
|
import { defineTool as defineTool2 } from "@deepseek-ai/dsh-tools";
|
|
13987
|
+
|
|
13988
|
+
// src/feedback-policy.ts
|
|
13989
|
+
var AGENT_FEEDBACK_ENABLED = true;
|
|
13990
|
+
|
|
13991
|
+
// src/tools.ts
|
|
13569
13992
|
var jsonOutput = {
|
|
13570
13993
|
schema: { type: "json" },
|
|
13571
13994
|
render: (_args, value) => [{
|
|
@@ -13606,17 +14029,19 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
13606
14029
|
}));
|
|
13607
14030
|
if (AGENT_FEEDBACK_ENABLED) ctx.tools.register(defineTool2({
|
|
13608
14031
|
name: "feedback_prepare",
|
|
13609
|
-
description:
|
|
14032
|
+
description: "This tool is provided by the StrataGate plugin. \u6574\u7406 StrataGate \u63D2\u4EF6\u7684\u6545\u969C\u3001\u4F7F\u7528\u7591\u95EE\u548C\u6539\u8FDB\u5EFA\u8BAE\uFF0C\u751F\u6210\u672C\u5730\u90AE\u4EF6\u53CD\u9988\u8349\u7A3F\u5E76\u81EA\u52A8\u9644\u5E26\u8FD0\u884C\u6458\u8981\u3002\u7528\u6237\u76F4\u63A5\u8981\u6C42\u53EF\u8C03\u7528\uFF1B\u4E3B\u52A8\u5EFA\u8BAE\u987B\u5148\u83B7\u540C\u610F\u3002\u4F9D\u636E\u5F53\u524D\u4F1A\u8BDD\u4E8B\u5B9E\u586B\u5199\uFF0C\u672A\u77E5\u7559\u7A7A\uFF0C\u53BB\u9664\u51ED\u636E\u3002\u7701\u7565\u5B57\u6BB5\u4FDD\u7559\u539F\u503C\uFF0C\u7A7A\u5B57\u7B26\u4E32\u6216\u7A7A\u6570\u7EC4\u6E05\u7A7A\uFF1B\u65B0\u95EE\u9898\u4F20 new_draft=true\u3002\u6210\u529F\u540E\u8BF4\u660E\u8349\u7A3F\u5728\u672C\u5730\u3001\u90AE\u4EF6\u5C1A\u672A\u53D1\u9001\uFF0C\u5E76\u5C06 feedbackUrl \u663E\u793A\u4E3A\u201C\u6253\u5F00\u53CD\u9988\u8349\u7A3F\u201D\u94FE\u63A5\uFF0C\u4F9B\u7528\u6237\u68C0\u67E5\u540E\u624B\u52A8\u53D1\u90AE\u4EF6\u3002",
|
|
13610
14033
|
parameters: {
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13616
|
-
|
|
14034
|
+
new_draft: { type: "boolean", description: "\u65B0\u95EE\u9898\u4E3A true\uFF1B\u4FEE\u6539\u5DF2\u6709\u8349\u7A3F\u65F6\u7701\u7565\u3002" },
|
|
14035
|
+
title: { type: "string", description: "\u7B80\u77ED\u95EE\u9898\u6807\u9898\u3002" },
|
|
14036
|
+
description: { type: "string", description: "\u5DF2\u77E5\u95EE\u9898\u3001\u5EFA\u8BAE\u6216\u7591\u95EE\u3002" },
|
|
14037
|
+
reproduction: { type: "array", items: { type: "string" }, description: "\u5B9E\u9645\u53D1\u751F\u8FC7\u7684\u590D\u73B0\u6B65\u9AA4\u3002" },
|
|
14038
|
+
expected: { type: "string", description: "\u5DF2\u77E5\u9884\u671F\u7ED3\u679C\u3002" },
|
|
14039
|
+
actual: { type: "string", description: "\u5B9E\u9645\u89C2\u5BDF\u5230\u7684\u7ED3\u679C\u3002" },
|
|
14040
|
+
error_context: { type: "string", description: "\u5F53\u524D\u4F1A\u8BDD\u7684\u76F8\u5173\u9519\u8BEF\uFF1B\u672C\u5730\u8BCA\u65AD\u7531\u7A0B\u5E8F\u81EA\u52A8\u8865\u5145\u3002" }
|
|
13617
14041
|
},
|
|
13618
14042
|
output: jsonOutput,
|
|
13619
14043
|
execute: async (args, exec) => runtime.prepareFeedback(sessionOf(exec), {
|
|
14044
|
+
...args.new_draft !== void 0 ? { newDraft: args.new_draft } : {},
|
|
13620
14045
|
...args.title !== void 0 ? { title: args.title } : {},
|
|
13621
14046
|
...args.description !== void 0 ? { description: args.description } : {},
|
|
13622
14047
|
...args.reproduction !== void 0 ? { reproduction: args.reproduction } : {},
|
|
@@ -13625,6 +14050,19 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
13625
14050
|
...args.error_context !== void 0 ? { errorContext: args.error_context } : {}
|
|
13626
14051
|
})
|
|
13627
14052
|
}));
|
|
14053
|
+
if (AGENT_FEEDBACK_ENABLED) ctx.tools.register(defineTool2({
|
|
14054
|
+
name: "stratagate_diagnostics",
|
|
14055
|
+
description: "This tool is provided by the StrataGate plugin. \u53EA\u8BFB\u67E5\u8BE2 StrataGate \u63D2\u4EF6\u5F53\u524D\u8BB0\u5FC6\u7A7A\u95F4\u7684\u8FD0\u884C\u8BCA\u65AD\uFF1A\u8FD1\u671F\u5931\u8D25\u3001\u4EFB\u52A1\u72B6\u6001\u3001\u8017\u65F6\u3001Token \u7528\u91CF\u4E0E\u91C7\u96C6\u8986\u76D6\u5EA6\u3002\u9ED8\u8BA4\u7ED9\u6458\u8981\uFF1B\u7528\u8FD4\u56DE\u7684\u8BCA\u65AD id \u8BFB\u53D6\u8131\u654F\u9519\u8BEF\u8BE6\u60C5\uFF0Coffset \u5206\u9875\u3002\u7528\u4E8E\u6392\u67E5\u6216\u56DE\u5E94\u7528\u6237\u7591\u95EE\uFF1B\u53CD\u9988\u8349\u7A3F\u4F1A\u81EA\u52A8\u9644\u5E26\u6458\u8981\u3002",
|
|
14056
|
+
parameters: {
|
|
14057
|
+
id: { type: "string", description: "\u6458\u8981\u4E2D\u8FD4\u56DE\u7684\u8BCA\u65AD ID\uFF1B\u63D0\u4F9B\u65F6\u8BFB\u53D6\u8BE5\u6761\u8BE6\u60C5\u3002" },
|
|
14058
|
+
offset: { type: "integer", description: "\u4F7F\u7528\u8FD4\u56DE\u7684 nextOffset \u7EE7\u7EED\u8BFB\u53D6\u8FD1\u671F\u5F02\u5E38\u3002" }
|
|
14059
|
+
},
|
|
14060
|
+
output: jsonOutput,
|
|
14061
|
+
execute: async (args, exec) => runtime.diagnosticReport(runtime.namespaceFor(sessionOf(exec)), {
|
|
14062
|
+
...args.id !== void 0 ? { id: args.id, details: true } : {},
|
|
14063
|
+
...args.offset !== void 0 ? { offset: args.offset } : {}
|
|
14064
|
+
})
|
|
14065
|
+
}));
|
|
13628
14066
|
ctx.tools.register(defineTool2({
|
|
13629
14067
|
name: "memory_list_topics",
|
|
13630
14068
|
description: "This tool is provided by the StrataGate plugin. \u6D4F\u89C8\u5F53\u524D\u8BB0\u5FC6\u7A7A\u95F4\u7684\u4E3B\u9898\u76EE\u5F55\u3002\u53EF\u6309\u5206\u7C7B\u5206\u9875\uFF0C\u6216\u7528 query \u67E5\u4E3B\u9898\u540D\u79F0\u53CA\u7B80\u4ECB\u3002\u672A\u6574\u7406\u7684\u4E8B\u4EF6\u4E5F\u6709\u5165\u53E3\u3002\u76EE\u5F55\u4EC5\u4F9B\u5BFC\u822A\uFF0C\u4E0D\u521B\u5EFA\u8BC1\u636E\u6279\u6B21\uFF0C\u4E0D\u5F3A\u5316\u8BB0\u5FC6\uFF1B\u9700\u8981\u4E3B\u9898\u8109\u7EDC\u65F6\u8C03\u7528 memory_expand_topic\uFF1B\u9700\u8981\u4E8B\u5B9E\u8BC1\u636E\u53EF\u76F4\u63A5 memory_search_events(topic_id)\uFF0C\u5E76\u8BC4\u4F30\u6765\u6E90\u4E8B\u4EF6\u3002",
|
|
@@ -13803,7 +14241,7 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
13803
14241
|
|
|
13804
14242
|
// src/web.ts
|
|
13805
14243
|
import { createHash as createHash4 } from "node:crypto";
|
|
13806
|
-
import { createRequire as
|
|
14244
|
+
import { createRequire as createRequire3 } from "node:module";
|
|
13807
14245
|
|
|
13808
14246
|
// src/graph-clustering.ts
|
|
13809
14247
|
import createGraph from "ngraph.graph";
|
|
@@ -13917,7 +14355,7 @@ function clusterKnowledgeGraph(rawNodes, rawEdges) {
|
|
|
13917
14355
|
|
|
13918
14356
|
// src/web.ts
|
|
13919
14357
|
var LEGACY_THREAD_ID = "__legacy__";
|
|
13920
|
-
var nodeRequire2 =
|
|
14358
|
+
var nodeRequire2 = createRequire3(import.meta.url);
|
|
13921
14359
|
function currentPluginVersion() {
|
|
13922
14360
|
try {
|
|
13923
14361
|
const value = nodeRequire2("../package.json");
|
|
@@ -14676,7 +15114,8 @@ async function feedback(runtime, req, url) {
|
|
|
14676
15114
|
if (req.method === "GET") {
|
|
14677
15115
|
const namespace2 = url.searchParams.get("namespace")?.trim() ?? "";
|
|
14678
15116
|
if (!namespace2) throw new AdminHttpError(400, "namespace is required");
|
|
14679
|
-
|
|
15117
|
+
const result = runtime.adminFeedbackDraft(namespace2);
|
|
15118
|
+
return { ...result, diagnostics: result.draft?.diagnostics ?? await runtime.diagnosticReport?.(namespace2) };
|
|
14680
15119
|
}
|
|
14681
15120
|
if (req.method !== "PUT") throw new AdminHttpError(405, "StrataGate feedback requires GET or PUT");
|
|
14682
15121
|
let suppliedBody = req.body;
|
|
@@ -15328,6 +15767,19 @@ async function handleAdminRequest(runtime, req, res) {
|
|
|
15328
15767
|
const path = url.pathname.replace(/\/$/, "");
|
|
15329
15768
|
if (path === "/api/stratagate/feedback") {
|
|
15330
15769
|
sendJson(res, 200, await feedback(runtime, req, url));
|
|
15770
|
+
} else if (path === "/api/stratagate/diagnostics") {
|
|
15771
|
+
const namespace = url.searchParams.get("namespace")?.trim() ?? "";
|
|
15772
|
+
if (!namespace) throw new AdminHttpError(400, "namespace is required");
|
|
15773
|
+
if (req.method === "POST") {
|
|
15774
|
+
const category = url.searchParams.get("category") ?? "";
|
|
15775
|
+
if (!["timeout", "network", "request-failed"].includes(category)) throw new AdminHttpError(400, "Unknown frontend diagnostic category");
|
|
15776
|
+
runtime.diagnostics.record({ namespace, stage: "frontend" }, { errors: 1 }, { error: category });
|
|
15777
|
+
sendJson(res, 200, { recorded: true });
|
|
15778
|
+
return;
|
|
15779
|
+
}
|
|
15780
|
+
if (req.method !== "GET") throw new AdminHttpError(405, "StrataGate diagnostics require GET or POST");
|
|
15781
|
+
const id = url.searchParams.get("id") ?? void 0;
|
|
15782
|
+
sendJson(res, 200, await runtime.diagnosticReport(namespace, { ...id ? { id, details: true } : {}, offset: numeric(url.searchParams.get("offset"), 0, 0, 2e3) }));
|
|
15331
15783
|
} else if (path === "/api/stratagate/profile") {
|
|
15332
15784
|
sendJson(res, 200, await persistentProfile(runtime, req), true);
|
|
15333
15785
|
} else if (path === "/api/stratagate/settings") {
|
|
@@ -15494,7 +15946,7 @@ import {
|
|
|
15494
15946
|
writeFile
|
|
15495
15947
|
} from "node:fs/promises";
|
|
15496
15948
|
import { basename, dirname as dirname2, join } from "node:path";
|
|
15497
|
-
import { createHash as createHash5, randomUUID as
|
|
15949
|
+
import { createHash as createHash5, randomUUID as randomUUID6 } from "node:crypto";
|
|
15498
15950
|
import { encodeSeqRanges, KNOWN_SESSION_EVENT_TYPES } from "@deepseek-ai/dsh-session";
|
|
15499
15951
|
var LEGACY_EVENT_TYPE = "stratagate/memory-citations";
|
|
15500
15952
|
var COMPAT_EVENT_TYPE = "feedback/record";
|
|
@@ -15715,7 +16167,7 @@ async function exists(path) {
|
|
|
15715
16167
|
}
|
|
15716
16168
|
async function publishExclusive(path, bytes) {
|
|
15717
16169
|
await mkdir(dirname2(path), { recursive: true });
|
|
15718
|
-
const temporary = join(dirname2(path), `.${basename(path)}.stratagate-${
|
|
16170
|
+
const temporary = join(dirname2(path), `.${basename(path)}.stratagate-${randomUUID6()}.tmp`);
|
|
15719
16171
|
const handle = await open(temporary, "wx", 384);
|
|
15720
16172
|
try {
|
|
15721
16173
|
await handle.writeFile(bytes);
|
|
@@ -15840,15 +16292,8 @@ Memory writing:
|
|
|
15840
16292
|
- Current city (currentCity) also belongs in the always-on Profile. Travel or business-trip location can be temporary while its saved value persists across sessions until the user updates or clears it; do not expire it automatically. A user request to remember their current trip city belongs here, not in retrieval-dependent memory_remember. Future trip plans, completed trips, and historical locations do not establish current whereabouts. Never copy currentCity into defaultLocation or homeCity. For local tasks use an explicit task location first, otherwise currentCity when set, then defaultLocation. Follow the same Profile consent rule for updates and clearing.
|
|
15841
16293
|
- Use memory_remember for durable project facts, past decisions, corrections, experiences, and context-specific preferences. Record one self-contained, grounded fact per call, with necessary project, time, and scope. Never record speculation, secrets, credentials, or transient task state.`;
|
|
15842
16294
|
var FEEDBACK_PROTOCOL = `[StrataGate feedback policy]
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
- Consider proactively suggesting a feedback draft only when the current conversation contains a clear error signal: a tool call threw or returned an error; a result is clearly contrary to expectations and the user expresses confusion or dissatisfaction; or the same problem remains after the user retries it. Normal use, casual conversation, general complaints, and suspected problems without clear error evidence are not eligible.
|
|
15846
|
-
- An eligible error does not require a suggestion. Suggest only when the problem remains unresolved, recurs, or materially interferes with the user's task. Do not suggest for a minor failure that recovered automatically without affecting the task.
|
|
15847
|
-
- Always troubleshoot, solve the current problem, or offer a workaround first. If it cannot be solved, explain the blocker first. Only at the end of that turn may you add one unobtrusive sentence in the user's language, such as: "\u5982\u679C\u4F60\u613F\u610F\uFF0C\u6211\u53EF\u4EE5\u628A\u8FD9\u6B21\u5F02\u5E38\u6574\u7406\u6210\u53CD\u9988\u8349\u7A3F\uFF0C\u4F9B\u4F60\u68C0\u67E5\u540E\u81EA\u884C\u63D0\u4EA4\u3002" Do not use a popup, heading, interactive-question tool, or interruption for the suggestion.
|
|
15848
|
-
- Across the entire current conversation, make at most one proactive feedback suggestion in total, across all namespaces and problems. The suggestion consumes this allowance as soon as it is sent, whether the user accepts, declines, or does not reply. Use the conversation history to remember this; do not expose internal tracking or claim a cross-conversation, daily, or persistent limit.
|
|
15849
|
-
- A user's direct request to create or revise feedback is not a proactive suggestion, does not consume that allowance, and is not restricted by it. Necessary clarification for that request is also allowed. If the user says they are not interested, stop immediately and do not ask again.
|
|
15850
|
-
- Deduplicate a problem by namespace plus its substantive characteristics; changed wording or another retry does not make it a new problem. Never proactively suggest feedback for a problem that was already proactively suggested or already has a draft. A draft created at the user's request still makes that problem ineligible for a later proactive suggestion.
|
|
15851
|
-
- After a proactive suggestion, call feedback_prepare only if the user explicitly agrees. A direct request to create feedback is already authorization, so do not ask again. A failure of feedback_prepare itself must never trigger another proactive feedback suggestion.`;
|
|
16295
|
+
\u9488\u5BF9 StrataGate \u63D2\u4EF6\u7684\u6545\u969C\u3001\u4F7F\u7528\u7591\u95EE\u548C\u6539\u8FDB\u5EFA\u8BAE\uFF0C\u7528\u6237\u8981\u6C42\u65F6\u7528 feedback_prepare \u751F\u6210\u672C\u5730\u90AE\u4EF6\u53CD\u9988\u8349\u7A3F\u3002\u9700\u8981\u8FD0\u884C\u8BC1\u636E\u65F6\u7528 stratagate_diagnostics\uFF0C\u8349\u7A3F\u4F1A\u81EA\u52A8\u9644\u5E26\u672C\u5730\u8BCA\u65AD\u6458\u8981\u4F9B\u7528\u6237\u68C0\u67E5\u3002
|
|
16296
|
+
\u4EC5\u5728\u5F53\u524D\u4F1A\u8BDD\u5DF2\u6709\u660E\u786E\u7684 StrataGate \u9519\u8BEF\u8BC1\u636E\uFF0C\u4E14\u95EE\u9898\u6301\u7EED\u5F71\u54CD\u5F53\u524D\u4EFB\u52A1\u65F6\uFF0C\u5148\u5904\u7406\u95EE\u9898\uFF0C\u518D\u4E8E\u56DE\u590D\u672B\u5C3E\u8F7B\u58F0\u5EFA\u8BAE\u6574\u7406\u53CD\u9988\u3002\u6574\u4E2A\u4F1A\u8BDD\u6700\u591A\u4E3B\u52A8\u5EFA\u8BAE\u4E00\u6B21\uFF1B\u7528\u6237\u660E\u786E\u540C\u610F\u540E\u8C03\u7528\u3002\u7528\u6237\u76F4\u63A5\u8981\u6C42\u53EF\u76F4\u63A5\u6267\u884C\uFF1B\u62D2\u7EDD\u6216\u672A\u56DE\u5E94\u5C31\u7ED3\u675F\u5EFA\u8BAE\u3002\u6309\u8BB0\u5FC6\u7A7A\u95F4\u4E0E\u5B9E\u8D28\u95EE\u9898\u53BB\u91CD\u3002\u666E\u901A\u540E\u53F0\u91CD\u8BD5\u4FDD\u6301\u5B89\u9759\uFF1B\u53CD\u9988\u5DE5\u5177\u81EA\u8EAB\u5931\u8D25\u7EE7\u7EED\u539F\u4EFB\u52A1\u3002`;
|
|
15852
16297
|
function renderError(error) {
|
|
15853
16298
|
return error instanceof Error ? error.message : String(error);
|
|
15854
16299
|
}
|
|
@@ -15929,27 +16374,48 @@ async function apply(ctx, config) {
|
|
|
15929
16374
|
autoMemory = { name: "stratagate:auto-memory", text: text3 };
|
|
15930
16375
|
} catch (error) {
|
|
15931
16376
|
ctx.logger.warn(`stratagate-memory auto-context failed: ${renderError(error)}`);
|
|
15932
|
-
|
|
16377
|
+
runtime.notePluginError(session, error, "autoContext");
|
|
15933
16378
|
}
|
|
15934
16379
|
try {
|
|
15935
16380
|
const directory = await runtime.buildMemoryDirectory(session);
|
|
15936
16381
|
if (directory) contexts.push({ name: "stratagate:memory-directory", text: directory });
|
|
15937
16382
|
} catch (error) {
|
|
15938
16383
|
ctx.logger.warn(`stratagate-memory directory failed: ${renderError(error)}`);
|
|
15939
|
-
|
|
16384
|
+
runtime.notePluginError(session, error, "directory");
|
|
15940
16385
|
}
|
|
15941
16386
|
if (autoMemory) contexts.push(autoMemory);
|
|
15942
|
-
const
|
|
15943
|
-
|
|
16387
|
+
const toolSchemas = ctx.tools.schemas(context.agent).filter(({ name: name2 }) => name2.startsWith("memory_") || name2 === "feedback_prepare" || name2 === "stratagate_diagnostics");
|
|
16388
|
+
runtime.trackDiagnosticSession(String(session.id), runtime.namespaceFor(session), estimateTokens(JSON.stringify({
|
|
16389
|
+
sections: assembled.sections.filter(({ name: name2 }) => name2.startsWith("tool:stratagate-")),
|
|
16390
|
+
contexts: contexts.filter(({ name: name2 }) => name2.startsWith("stratagate:")),
|
|
16391
|
+
tools: toolSchemas
|
|
16392
|
+
})));
|
|
15944
16393
|
return { ...assembled, contexts };
|
|
15945
16394
|
});
|
|
15946
16395
|
installRetrievalFinalization(ctx, runtime);
|
|
15947
16396
|
registerMemoryTools(ctx, runtime);
|
|
15948
|
-
ctx.on("
|
|
15949
|
-
if (
|
|
15950
|
-
|
|
15951
|
-
|
|
16397
|
+
ctx.on("llm/stream", async function* (options, next) {
|
|
16398
|
+
if (models.currentDiagnosticScope()) {
|
|
16399
|
+
yield* next();
|
|
16400
|
+
return;
|
|
16401
|
+
}
|
|
16402
|
+
const namespace = runtime.diagnosticNamespaceForSession(String(options.sessionId ?? ""));
|
|
16403
|
+
if (!namespace || options.purpose) {
|
|
16404
|
+
yield* next();
|
|
16405
|
+
return;
|
|
15952
16406
|
}
|
|
16407
|
+
const stage = String(options.sessionId).startsWith("stratagate-dreaming:") ? "dreamingStep" : "chat";
|
|
16408
|
+
const memoryInputEstimate = runtime.diagnosticMemoryEstimate(String(options.sessionId));
|
|
16409
|
+
yield* observeModelStream(runtime.diagnostics, { namespace, stage, ...memoryInputEstimate !== void 0 ? { memoryInputEstimate } : {} }, options, next);
|
|
16410
|
+
});
|
|
16411
|
+
ctx.on("tools/result", (exec, result) => {
|
|
16412
|
+
if (!exec.agent || !(exec.name === "feedback_prepare" || exec.name === "stratagate_diagnostics" || exec.name.startsWith("memory_"))) return;
|
|
16413
|
+
const namespace = runtime.namespaceFor(exec.agent.session);
|
|
16414
|
+
runtime.diagnostics.record(
|
|
16415
|
+
{ namespace, stage: "tools" },
|
|
16416
|
+
{ toolCalls: 1, toolFailures: result.isError ? 1 : 0 },
|
|
16417
|
+
result.isError ? { error: result.error.message } : {}
|
|
16418
|
+
);
|
|
15953
16419
|
});
|
|
15954
16420
|
const disposeAdminRoutes = registerAdminRoutes(ctx, runtime);
|
|
15955
16421
|
ctx.on("session/event", (session, event) => runtime.acceptEvent(session, event));
|