stratagate-dsh 0.3.8 → 0.3.10
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 +596 -583
- package/LICENSE +21 -21
- package/dist/client.js +12 -7
- package/dist/index.js.map +1 -1
- package/dist/plugin.js +47 -45
- package/dist/plugin.js.map +1 -1
- package/docs/DSH.md +256 -256
- package/docs/DSH.zh-CN.md +233 -233
- package/docs/validation/issue119-after.json +30 -30
- package/docs/validation/issue119-before.json +94 -94
- package/docs/validation/issue119.md +41 -41
- package/package.json +1 -1
- package/screenshots.json +8 -8
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dsh-host-resolution.ts","../src/bootstrap.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\r\nimport { createRequire, registerHooks } from 'node:module'\r\nimport { dirname, isAbsolute, join, relative } from 'node:path'\r\nimport { fileURLToPath, pathToFileURL } from 'node:url'\r\n\r\nconst HOST_PACKAGES = [\r\n '@deepseek-ai/cordis',\r\n '@deepseek-ai/dsh-agent-default-model',\r\n '@deepseek-ai/dsh-client-ui-conversation',\r\n '@deepseek-ai/dsh-llm',\r\n '@deepseek-ai/dsh-native-command',\r\n '@deepseek-ai/dsh-session',\r\n '@deepseek-ai/dsh-session-format',\r\n '@deepseek-ai/dsh-session-format-catalog',\r\n '@deepseek-ai/dsh-session-format-v0-to-v1',\r\n '@deepseek-ai/dsh-settings',\r\n '@deepseek-ai/dsh-system-prompt',\r\n '@deepseek-ai/dsh-tools',\r\n '@deepseek-ai/schemastery',\r\n] as const\r\n\r\nconst installedHooks = Symbol.for('stratagate.dsh-host-resolution.v1')\r\n\r\nfunction isWithin(path: string, root: string): boolean {\r\n const child = relative(root, path)\r\n return child === '' || (!child.startsWith('..') && !isAbsolute(child))\r\n}\r\n\r\nfunction profileDirectory(start: string): string | undefined {\r\n let directory = start\r\n for (;;) {\r\n const manifestPath = join(directory, 'package.json')\r\n if (existsSync(manifestPath)) {\r\n try {\r\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { dsh?: { profile?: unknown } }\r\n if (manifest.dsh?.profile && typeof manifest.dsh.profile === 'object') return directory\r\n } catch {}\r\n }\r\n const parent = dirname(directory)\r\n if (parent === directory) return undefined\r\n directory = parent\r\n }\r\n}\r\n\r\nfunction hostPackage(specifier: string): boolean {\r\n return HOST_PACKAGES.some((name) => specifier === name || specifier.startsWith(`${name}/`))\r\n}\r\n\r\n/**\r\n * Force only StrataGate's DSH imports through the installation-owned fallback\r\n * created by DSH. The hook neither deletes nor rewrites the profile's package\r\n * tree, and imports belonging to the host or other plugins are untouched.\r\n */\r\nexport function installDshHostResolution(moduleUrl: string): boolean {\r\n const packageDirectory = dirname(dirname(fileURLToPath(moduleUrl)))\r\n const profile = profileDirectory(packageDirectory)\r\n if (!profile) return false\r\n\r\n const globalState = globalThis as typeof globalThis & { [installedHooks]?: Set<string> }\r\n const installed = globalState[installedHooks] ??= new Set<string>()\r\n const key = `${profile}\\u0000${packageDirectory}`\r\n if (installed.has(key)) return true\r\n\r\n const fallbackModules = join(dirname(profile), 'node_modules')\r\n const hostRequire = createRequire(join(fallbackModules, '.stratagate-host-resolution.cjs'))\r\n registerHooks({\r\n resolve(specifier, context, nextResolve) {\r\n const parent = context.parentURL?.startsWith('file:') ? fileURLToPath(context.parentURL) : undefined\r\n if (!hostPackage(specifier) || !parent || !isWithin(parent, packageDirectory)) {\r\n return nextResolve(specifier, context)\r\n }\r\n try {\r\n return { url: pathToFileURL(hostRequire.resolve(specifier)).href, shortCircuit: true }\r\n } catch (cause) {\r\n if (specifier === '@deepseek-ai/dsh-session-format-v0-to-v1'\r\n || specifier === '@deepseek-ai/dsh-session-format-catalog') {\r\n return nextResolve(specifier, context)\r\n }\r\n throw new Error(\r\n `StrataGate cannot resolve host-provided DSH package ${JSON.stringify(specifier)} from ${fallbackModules}. `\r\n + 'Start StrataGate through the DSH profile launcher so the host can prepare its module fallback.',\r\n { cause },\r\n )\r\n }\r\n },\r\n })\r\n installed.add(key)\r\n return true\r\n}\r\n","import { installDshHostResolution } from './dsh-host-resolution.js'\
|
|
1
|
+
{"version":3,"sources":["../src/dsh-host-resolution.ts","../src/bootstrap.ts"],"sourcesContent":["import { existsSync, readFileSync } from 'node:fs'\r\nimport { createRequire, registerHooks } from 'node:module'\r\nimport { dirname, isAbsolute, join, relative } from 'node:path'\r\nimport { fileURLToPath, pathToFileURL } from 'node:url'\r\n\r\nconst HOST_PACKAGES = [\r\n '@deepseek-ai/cordis',\r\n '@deepseek-ai/dsh-agent-default-model',\r\n '@deepseek-ai/dsh-client-ui-conversation',\r\n '@deepseek-ai/dsh-llm',\r\n '@deepseek-ai/dsh-native-command',\r\n '@deepseek-ai/dsh-session',\r\n '@deepseek-ai/dsh-session-format',\r\n '@deepseek-ai/dsh-session-format-catalog',\r\n '@deepseek-ai/dsh-session-format-v0-to-v1',\r\n '@deepseek-ai/dsh-settings',\r\n '@deepseek-ai/dsh-system-prompt',\r\n '@deepseek-ai/dsh-tools',\r\n '@deepseek-ai/schemastery',\r\n] as const\r\n\r\nconst installedHooks = Symbol.for('stratagate.dsh-host-resolution.v1')\r\n\r\nfunction isWithin(path: string, root: string): boolean {\r\n const child = relative(root, path)\r\n return child === '' || (!child.startsWith('..') && !isAbsolute(child))\r\n}\r\n\r\nfunction profileDirectory(start: string): string | undefined {\r\n let directory = start\r\n for (;;) {\r\n const manifestPath = join(directory, 'package.json')\r\n if (existsSync(manifestPath)) {\r\n try {\r\n const manifest = JSON.parse(readFileSync(manifestPath, 'utf8')) as { dsh?: { profile?: unknown } }\r\n if (manifest.dsh?.profile && typeof manifest.dsh.profile === 'object') return directory\r\n } catch {}\r\n }\r\n const parent = dirname(directory)\r\n if (parent === directory) return undefined\r\n directory = parent\r\n }\r\n}\r\n\r\nfunction hostPackage(specifier: string): boolean {\r\n return HOST_PACKAGES.some((name) => specifier === name || specifier.startsWith(`${name}/`))\r\n}\r\n\r\n/**\r\n * Force only StrataGate's DSH imports through the installation-owned fallback\r\n * created by DSH. The hook neither deletes nor rewrites the profile's package\r\n * tree, and imports belonging to the host or other plugins are untouched.\r\n */\r\nexport function installDshHostResolution(moduleUrl: string): boolean {\r\n const packageDirectory = dirname(dirname(fileURLToPath(moduleUrl)))\r\n const profile = profileDirectory(packageDirectory)\r\n if (!profile) return false\r\n\r\n const globalState = globalThis as typeof globalThis & { [installedHooks]?: Set<string> }\r\n const installed = globalState[installedHooks] ??= new Set<string>()\r\n const key = `${profile}\\u0000${packageDirectory}`\r\n if (installed.has(key)) return true\r\n\r\n const fallbackModules = join(dirname(profile), 'node_modules')\r\n const hostRequire = createRequire(join(fallbackModules, '.stratagate-host-resolution.cjs'))\r\n registerHooks({\r\n resolve(specifier, context, nextResolve) {\r\n const parent = context.parentURL?.startsWith('file:') ? fileURLToPath(context.parentURL) : undefined\r\n if (!hostPackage(specifier) || !parent || !isWithin(parent, packageDirectory)) {\r\n return nextResolve(specifier, context)\r\n }\r\n try {\r\n return { url: pathToFileURL(hostRequire.resolve(specifier)).href, shortCircuit: true }\r\n } catch (cause) {\r\n if (specifier === '@deepseek-ai/dsh-session-format-v0-to-v1'\r\n || specifier === '@deepseek-ai/dsh-session-format-catalog') {\r\n return nextResolve(specifier, context)\r\n }\r\n throw new Error(\r\n `StrataGate cannot resolve host-provided DSH package ${JSON.stringify(specifier)} from ${fallbackModules}. `\r\n + 'Start StrataGate through the DSH profile launcher so the host can prepare its module fallback.',\r\n { cause },\r\n )\r\n }\r\n },\r\n })\r\n installed.add(key)\r\n return true\r\n}\r\n","import { installDshHostResolution } from './dsh-host-resolution.js'\n\n// DSH prepares its installation-owned module fallback before it imports a\n// profile bundle. Install the narrowly-scoped resolver first, then load the\n// implementation so stale profile-local peers cannot win ESM resolution.\ninstallDshHostResolution(import.meta.url)\n\n// This file and src/index.ts are separate tsup entries. The runtime path is\n// intentionally external so the implementation is instantiated only after\n// the resolver above is active.\n// @ts-expect-error dist/plugin.js is emitted from src/index.ts during build.\nconst plugin = await import('./plugin.js') as typeof import('./index.js')\n\nexport const name = plugin.name\nexport const inject = plugin.inject\nexport const STRATAGATE_SETTINGS_NAMESPACE = plugin.STRATAGATE_SETTINGS_NAMESPACE\nexport const Config = plugin.Config\nexport const apply = plugin.apply\nexport type PluginConfig = import('./index.js').PluginConfig\n"],"mappings":";AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,eAAe,qBAAqB;AAC7C,SAAS,SAAS,YAAY,MAAM,gBAAgB;AACpD,SAAS,eAAe,qBAAqB;AAE7C,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,iBAAiB,uBAAO,IAAI,mCAAmC;AAErE,SAAS,SAAS,MAAc,MAAuB;AACrD,QAAM,QAAQ,SAAS,MAAM,IAAI;AACjC,SAAO,UAAU,MAAO,CAAC,MAAM,WAAW,IAAI,KAAK,CAAC,WAAW,KAAK;AACtE;AAEA,SAAS,iBAAiB,OAAmC;AAC3D,MAAI,YAAY;AAChB,aAAS;AACP,UAAM,eAAe,KAAK,WAAW,cAAc;AACnD,QAAI,WAAW,YAAY,GAAG;AAC5B,UAAI;AACF,cAAM,WAAW,KAAK,MAAM,aAAa,cAAc,MAAM,CAAC;AAC9D,YAAI,SAAS,KAAK,WAAW,OAAO,SAAS,IAAI,YAAY,SAAU,QAAO;AAAA,MAChF,QAAQ;AAAA,MAAC;AAAA,IACX;AACA,UAAM,SAAS,QAAQ,SAAS;AAChC,QAAI,WAAW,UAAW,QAAO;AACjC,gBAAY;AAAA,EACd;AACF;AAEA,SAAS,YAAY,WAA4B;AAC/C,SAAO,cAAc,KAAK,CAACA,UAAS,cAAcA,SAAQ,UAAU,WAAW,GAAGA,KAAI,GAAG,CAAC;AAC5F;AAOO,SAAS,yBAAyB,WAA4B;AACnE,QAAM,mBAAmB,QAAQ,QAAQ,cAAc,SAAS,CAAC,CAAC;AAClE,QAAM,UAAU,iBAAiB,gBAAgB;AACjD,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc;AACpB,QAAM,YAAY,YAAY,cAAc,MAAM,oBAAI,IAAY;AAClE,QAAM,MAAM,GAAG,OAAO,KAAS,gBAAgB;AAC/C,MAAI,UAAU,IAAI,GAAG,EAAG,QAAO;AAE/B,QAAM,kBAAkB,KAAK,QAAQ,OAAO,GAAG,cAAc;AAC7D,QAAM,cAAc,cAAc,KAAK,iBAAiB,iCAAiC,CAAC;AAC1F,gBAAc;AAAA,IACZ,QAAQ,WAAW,SAAS,aAAa;AACvC,YAAM,SAAS,QAAQ,WAAW,WAAW,OAAO,IAAI,cAAc,QAAQ,SAAS,IAAI;AAC3F,UAAI,CAAC,YAAY,SAAS,KAAK,CAAC,UAAU,CAAC,SAAS,QAAQ,gBAAgB,GAAG;AAC7E,eAAO,YAAY,WAAW,OAAO;AAAA,MACvC;AACA,UAAI;AACF,eAAO,EAAE,KAAK,cAAc,YAAY,QAAQ,SAAS,CAAC,EAAE,MAAM,cAAc,KAAK;AAAA,MACvF,SAAS,OAAO;AACd,YAAI,cAAc,8CACb,cAAc,2CAA2C;AAC5D,iBAAO,YAAY,WAAW,OAAO;AAAA,QACvC;AACA,cAAM,IAAI;AAAA,UACR,uDAAuD,KAAK,UAAU,SAAS,CAAC,SAAS,eAAe;AAAA,UAExG,EAAE,MAAM;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACD,YAAU,IAAI,GAAG;AACjB,SAAO;AACT;;;ACnFA,yBAAyB,YAAY,GAAG;AAMxC,IAAM,SAAS,MAAM,OAAO,aAAa;AAElC,IAAM,OAAO,OAAO;AACpB,IAAM,SAAS,OAAO;AACtB,IAAM,gCAAgC,OAAO;AAC7C,IAAM,SAAS,OAAO;AACtB,IAAM,QAAQ,OAAO;","names":["name"]}
|
package/dist/plugin.js
CHANGED
|
@@ -9467,6 +9467,11 @@ var DshMetadataStore = class {
|
|
|
9467
9467
|
|
|
9468
9468
|
// src/runtime.ts
|
|
9469
9469
|
import { createHash as createHash3 } from "node:crypto";
|
|
9470
|
+
|
|
9471
|
+
// src/feedback-policy.ts
|
|
9472
|
+
var AGENT_FEEDBACK_ENABLED = false;
|
|
9473
|
+
|
|
9474
|
+
// src/runtime.ts
|
|
9470
9475
|
import { existsSync } from "node:fs";
|
|
9471
9476
|
import { dirname, resolve as resolve2 } from "node:path";
|
|
9472
9477
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
@@ -9818,7 +9823,9 @@ function workspaceDisplayName(cwd) {
|
|
|
9818
9823
|
return canonical2.split(/[\\/]/).at(-1) || "\u5F53\u524D\u5DE5\u4F5C\u533A";
|
|
9819
9824
|
}
|
|
9820
9825
|
function feedbackText(value, maximum) {
|
|
9821
|
-
|
|
9826
|
+
if (typeof value !== "string") return "";
|
|
9827
|
+
const text3 = value.trim().replace(/[\uD800-\uDFFF]/gu, "\uFFFD").slice(0, maximum);
|
|
9828
|
+
return text3.replace(/[\uD800-\uDBFF]$/, "");
|
|
9822
9829
|
}
|
|
9823
9830
|
var FEEDBACK_MARKDOWN_HEADINGS = {
|
|
9824
9831
|
description: "\u95EE\u9898\u63CF\u8FF0",
|
|
@@ -10810,6 +10817,7 @@ var StrataGateRuntime = class {
|
|
|
10810
10817
|
await Promise.all(settled.flatMap((result) => result.status === "fulfilled" ? [result.value.close()] : []));
|
|
10811
10818
|
if (this.profileStorage) await this.profileStorage.close();
|
|
10812
10819
|
this.sessionsById.clear();
|
|
10820
|
+
this.pendingFeedbackSuggestionSessions.clear();
|
|
10813
10821
|
if (flushError !== void 0) throw flushError;
|
|
10814
10822
|
}
|
|
10815
10823
|
namespaceFor(session) {
|
|
@@ -10936,9 +10944,10 @@ var StrataGateRuntime = class {
|
|
|
10936
10944
|
return { items, total: items.length };
|
|
10937
10945
|
}
|
|
10938
10946
|
notePluginError(session, _error) {
|
|
10939
|
-
if (!this.closed) this.pendingFeedbackSuggestionSessions.add(String(session.id));
|
|
10947
|
+
if (AGENT_FEEDBACK_ENABLED && !this.closed) this.pendingFeedbackSuggestionSessions.add(String(session.id));
|
|
10940
10948
|
}
|
|
10941
10949
|
takeFeedbackSuggestion(session, now = Date.now()) {
|
|
10950
|
+
if (!AGENT_FEEDBACK_ENABLED) return "";
|
|
10942
10951
|
const sessionId = String(session.id);
|
|
10943
10952
|
if (!this.pendingFeedbackSuggestionSessions.delete(sessionId)) return "";
|
|
10944
10953
|
const last = this.lastFeedbackPromptAt();
|
|
@@ -12322,7 +12331,7 @@ function registerMemoryTools(ctx, runtime) {
|
|
|
12322
12331
|
return runtime.updatePersistentProfileFromTool(args.field, args.value);
|
|
12323
12332
|
}
|
|
12324
12333
|
}));
|
|
12325
|
-
ctx.tools.register(defineTool({
|
|
12334
|
+
if (AGENT_FEEDBACK_ENABLED) ctx.tools.register(defineTool({
|
|
12326
12335
|
name: "feedback_prepare",
|
|
12327
12336
|
description: 'This tool is provided by the StrataGate plugin. Create or revise a local StrataGate feedback draft when the user directly requests it, or after a proactive suggestion permitted by the StrataGate feedback policy and the user explicitly agrees. A direct user request is already authorization. Use only facts known from the current conversation; leave unknown fields empty and never invent versions, logs, Block counts, or diagnostics. Never submit anything to GitHub. After success, briefly say the draft is local and not submitted, then render feedbackUrl as a Markdown link labeled "\u6253\u5F00\u53CD\u9988\u8349\u7A3F". Then ask exactly once: "\u8981\u4E0D\u8981\u987A\u4FBF\u8BA9\u6211\u5C1D\u8BD5\u4FEE\u590D\u8FD9\u4E2A\u95EE\u9898\uFF0C\u5E76\u63D0\u4EA4\u4E00\u4E2A PR\uFF1F" If the user does not respond or declines, do not ask again. Do not use a popup or other additional UI. Do not print draft fields or an Issue-content table, and do not direct the user through Settings manually.',
|
|
12328
12337
|
parameters: {
|
|
@@ -13117,6 +13126,30 @@ async function topicEvents(runtime, url) {
|
|
|
13117
13126
|
items: page.map(({ id, title, status, createdAt }) => ({ id, title, status, createdAt }))
|
|
13118
13127
|
};
|
|
13119
13128
|
}
|
|
13129
|
+
function liveGraphProjection(snapshot) {
|
|
13130
|
+
const eventIds = new Set([...snapshot.events, ...snapshot.agentEvents].filter(({ status: status2 }) => status2 !== "forgotten" && status2 !== "archived").map(({ id }) => id));
|
|
13131
|
+
const jobs = snapshot.graphProjectionJobs.filter(({ sourceEventIds }) => sourceEventIds.some((id) => eventIds.has(id)));
|
|
13132
|
+
const status = summarizeDerivationJobs(jobs, (job) => job.status === "completed");
|
|
13133
|
+
const projected = new Set(jobs.filter(({ status: status2, projectorVersion }) => status2 === "completed" && projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION).flatMap(({ sourceEventIds }) => sourceEventIds.filter((id) => eventIds.has(id)))).size;
|
|
13134
|
+
const total = eventIds.size;
|
|
13135
|
+
const complete = projected === total && status.processing === 0 && status.terminalFailed === 0 && status.blocked === 0;
|
|
13136
|
+
const state = status.processing > 0 ? "processing" : status.terminalFailed > 0 ? "failed" : complete ? "complete" : "incomplete";
|
|
13137
|
+
return {
|
|
13138
|
+
jobs,
|
|
13139
|
+
status,
|
|
13140
|
+
migration: {
|
|
13141
|
+
projected,
|
|
13142
|
+
total,
|
|
13143
|
+
pending: jobs.filter(({ status: status2 }) => status2 === "pending").length,
|
|
13144
|
+
running: jobs.filter(({ status: status2 }) => status2 === "running").length,
|
|
13145
|
+
failed: status.terminalFailed,
|
|
13146
|
+
retryable: status.retryable,
|
|
13147
|
+
processing: status.processing,
|
|
13148
|
+
state,
|
|
13149
|
+
complete
|
|
13150
|
+
}
|
|
13151
|
+
};
|
|
13152
|
+
}
|
|
13120
13153
|
async function overview(runtime, cachedEntries) {
|
|
13121
13154
|
const entries = cachedEntries ?? await Promise.all((await runtime.adminNamespaces()).map(async (namespace) => ({
|
|
13122
13155
|
namespace,
|
|
@@ -13222,20 +13255,21 @@ async function overview(runtime, cachedEntries) {
|
|
|
13222
13255
|
const topicStatus = summarizeDerivationJobs(topicJobs, (job) => job.status === "completed");
|
|
13223
13256
|
const summaryStatus = summarizeDerivationJobs(snapshot.summaryJobs, (job) => job.status === "succeeded");
|
|
13224
13257
|
const extractionStatus = summarizeDerivationJobs(snapshot.extractionJobs, (job) => job.status === "succeeded" || job.status === "skipped");
|
|
13225
|
-
const
|
|
13258
|
+
const graphWork = liveGraphProjection(snapshot);
|
|
13259
|
+
const graphStatus = graphWork.status;
|
|
13226
13260
|
const failedJobs = summaryStatus.terminalFailed + extractionStatus.terminalFailed + graphStatus.terminalFailed + topicStatus.terminalFailed;
|
|
13227
13261
|
const processingJobs = summaryStatus.processing + extractionStatus.processing + graphStatus.processing + topicStatus.processing;
|
|
13228
13262
|
const failedJobDetails = [
|
|
13229
13263
|
...topicJobs.filter((job) => job.status === "failed").map(describeTopicJob),
|
|
13230
13264
|
...snapshot.summaryJobs.filter(({ status }) => status === "failed").map((job) => describeBlockJob("block-summary", job)),
|
|
13231
13265
|
...snapshot.extractionJobs.filter(({ status }) => status === "failed").map((job) => describeBlockJob("event-extraction", job)),
|
|
13232
|
-
...
|
|
13266
|
+
...graphWork.jobs.filter(({ status }) => status === "failed").map(describeGraphJob)
|
|
13233
13267
|
];
|
|
13234
13268
|
const processingJobDetails = [
|
|
13235
13269
|
...topicJobs.filter((job) => ["processing", "retryable"].includes(derivationJobState(job, job.status === "completed"))).map(describeTopicJob),
|
|
13236
13270
|
...snapshot.summaryJobs.filter((job) => derivationJobState(job, job.status === "succeeded") === "processing" || derivationJobState(job, job.status === "succeeded") === "retryable").map((job) => describeBlockJob("block-summary", job)),
|
|
13237
13271
|
...snapshot.extractionJobs.filter((job) => derivationJobState(job, job.status === "succeeded" || job.status === "skipped") === "processing" || derivationJobState(job, job.status === "succeeded" || job.status === "skipped") === "retryable").map((job) => describeBlockJob("event-extraction", job)),
|
|
13238
|
-
...
|
|
13272
|
+
...graphWork.jobs.filter(graphProjectionIsProcessing).map(describeGraphJob)
|
|
13239
13273
|
];
|
|
13240
13274
|
const timestamps = [
|
|
13241
13275
|
...snapshot.blocks.map(({ createdAt }) => createdAt),
|
|
@@ -13265,23 +13299,7 @@ async function overview(runtime, cachedEntries) {
|
|
|
13265
13299
|
graphProjection: graphStatus,
|
|
13266
13300
|
topicProjection: topicStatus
|
|
13267
13301
|
},
|
|
13268
|
-
graphMigration:
|
|
13269
|
-
const projected = new Set(snapshot.graphProjectionJobs.filter(({ status, projectorVersion }) => status === "completed" && projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION).flatMap(({ sourceEventIds }) => sourceEventIds)).size;
|
|
13270
|
-
const total = snapshot.events.filter(({ status }) => status !== "forgotten" && status !== "archived").length;
|
|
13271
|
-
const complete = projected >= total;
|
|
13272
|
-
const state = complete ? "complete" : graphStatus.processing > 0 ? "processing" : graphStatus.terminalFailed > 0 ? "failed" : "incomplete";
|
|
13273
|
-
return {
|
|
13274
|
-
projected,
|
|
13275
|
-
total,
|
|
13276
|
-
pending: snapshot.graphProjectionJobs.filter(({ status }) => status === "pending").length,
|
|
13277
|
-
running: snapshot.graphProjectionJobs.filter(({ status }) => status === "running").length,
|
|
13278
|
-
failed: graphStatus.terminalFailed,
|
|
13279
|
-
retryable: graphStatus.retryable,
|
|
13280
|
-
processing: graphStatus.processing,
|
|
13281
|
-
state,
|
|
13282
|
-
complete
|
|
13283
|
-
};
|
|
13284
|
-
})(),
|
|
13302
|
+
graphMigration: graphWork.migration,
|
|
13285
13303
|
usageReceipts: snapshot.usageReceipts.length,
|
|
13286
13304
|
memoryUseCount: snapshot.usageReceipts.filter((receipt) => receipt.eventIds.length > 0 || receipt.elementIds.length > 0).length,
|
|
13287
13305
|
failedJobs,
|
|
@@ -13668,23 +13686,7 @@ async function memories(runtime, url) {
|
|
|
13668
13686
|
})),
|
|
13669
13687
|
edges: snapshot.graphEdges,
|
|
13670
13688
|
clusters: clusterKnowledgeGraph(snapshot.graphNodes, snapshot.graphEdges),
|
|
13671
|
-
migration: (
|
|
13672
|
-
const projected = new Set(snapshot.graphProjectionJobs.filter(({ status, projectorVersion }) => status === "completed" && projectorVersion === KNOWLEDGE_GRAPH_PROJECTOR_VERSION).flatMap(({ sourceEventIds }) => sourceEventIds)).size;
|
|
13673
|
-
const graphStatus = summarizeDerivationJobs(snapshot.graphProjectionJobs, (job) => job.status === "completed");
|
|
13674
|
-
const total = snapshot.events.filter(({ status }) => status !== "forgotten" && status !== "archived").length;
|
|
13675
|
-
const complete = projected >= total;
|
|
13676
|
-
return {
|
|
13677
|
-
projected,
|
|
13678
|
-
total,
|
|
13679
|
-
pending: snapshot.graphProjectionJobs.filter(({ status }) => status === "pending").length,
|
|
13680
|
-
running: snapshot.graphProjectionJobs.filter(({ status }) => status === "running").length,
|
|
13681
|
-
failed: graphStatus.terminalFailed,
|
|
13682
|
-
retryable: graphStatus.retryable,
|
|
13683
|
-
processing: graphStatus.processing,
|
|
13684
|
-
state: complete ? "complete" : graphStatus.processing > 0 ? "processing" : graphStatus.terminalFailed > 0 ? "failed" : "incomplete",
|
|
13685
|
-
complete
|
|
13686
|
-
};
|
|
13687
|
-
})()
|
|
13689
|
+
migration: liveGraphProjection(snapshot).migration
|
|
13688
13690
|
};
|
|
13689
13691
|
} else if (kind === "elements") values = snapshot.elements.map(elementSummary);
|
|
13690
13692
|
else if (kind === "blocks") {
|
|
@@ -14615,7 +14617,7 @@ async function apply(ctx, config) {
|
|
|
14615
14617
|
}
|
|
14616
14618
|
});
|
|
14617
14619
|
ctx.systemPrompt.section({ name: "tool:stratagate-memory", order: 113, text: MEMORY_PROTOCOL });
|
|
14618
|
-
ctx.systemPrompt.section({ name: "tool:stratagate-feedback", order: 114, text: FEEDBACK_PROTOCOL });
|
|
14620
|
+
if (AGENT_FEEDBACK_ENABLED) ctx.systemPrompt.section({ name: "tool:stratagate-feedback", order: 114, text: FEEDBACK_PROTOCOL });
|
|
14619
14621
|
ctx.on("system-prompt/assemble", async (_assembly, context, next) => {
|
|
14620
14622
|
const assembled = await next();
|
|
14621
14623
|
const contexts = [...assembled.contexts];
|
|
@@ -14634,24 +14636,24 @@ async function apply(ctx, config) {
|
|
|
14634
14636
|
autoMemory = { name: "stratagate:auto-memory", text: text3 };
|
|
14635
14637
|
} catch (error) {
|
|
14636
14638
|
ctx.logger.warn(`stratagate-memory auto-context failed: ${renderError(error)}`);
|
|
14637
|
-
runtime.notePluginError(session, error);
|
|
14639
|
+
if (AGENT_FEEDBACK_ENABLED) runtime.notePluginError(session, error);
|
|
14638
14640
|
}
|
|
14639
14641
|
try {
|
|
14640
14642
|
const directory = await runtime.buildMemoryDirectory(session);
|
|
14641
14643
|
if (directory) contexts.push({ name: "stratagate:memory-directory", text: directory });
|
|
14642
14644
|
} catch (error) {
|
|
14643
14645
|
ctx.logger.warn(`stratagate-memory directory failed: ${renderError(error)}`);
|
|
14644
|
-
runtime.notePluginError(session, error);
|
|
14646
|
+
if (AGENT_FEEDBACK_ENABLED) runtime.notePluginError(session, error);
|
|
14645
14647
|
}
|
|
14646
14648
|
if (autoMemory) contexts.push(autoMemory);
|
|
14647
|
-
const feedbackSuggestion = runtime.takeFeedbackSuggestion(session);
|
|
14649
|
+
const feedbackSuggestion = AGENT_FEEDBACK_ENABLED ? runtime.takeFeedbackSuggestion(session) : "";
|
|
14648
14650
|
if (feedbackSuggestion) contexts.push({ name: "stratagate:feedback-suggestion", text: feedbackSuggestion });
|
|
14649
14651
|
return { ...assembled, contexts };
|
|
14650
14652
|
});
|
|
14651
14653
|
installRetrievalFinalization(ctx, runtime);
|
|
14652
14654
|
registerMemoryTools(ctx, runtime);
|
|
14653
14655
|
ctx.on("tools/result", (exec, result) => {
|
|
14654
|
-
if (!result.isError || !exec.agent) return;
|
|
14656
|
+
if (!AGENT_FEEDBACK_ENABLED || !result.isError || !exec.agent) return;
|
|
14655
14657
|
if (exec.name === "feedback_prepare" || exec.name.startsWith("memory_")) {
|
|
14656
14658
|
runtime.notePluginError(exec.agent.session, result.error.message);
|
|
14657
14659
|
}
|