@botbotgo/agent-harness 0.0.298 → 0.0.300
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -38
- package/README.zh.md +80 -31
- package/dist/acp.d.ts +3 -0
- package/dist/acp.js +10 -2
- package/dist/api.d.ts +14 -2
- package/dist/api.js +19 -3
- package/dist/cli.d.ts +18 -1
- package/dist/cli.js +1408 -319
- package/dist/client/acp.d.ts +9 -3
- package/dist/client/acp.js +55 -1
- package/dist/client/in-process.d.ts +5 -2
- package/dist/client/in-process.js +4 -6
- package/dist/client/index.d.ts +1 -1
- package/dist/client/types.d.ts +6 -5
- package/dist/config/agents/direct.yaml +7 -17
- package/dist/config/agents/orchestra.yaml +9 -65
- package/dist/config/catalogs/embedding-models.yaml +1 -1
- package/dist/config/catalogs/stores.yaml +1 -1
- package/dist/config/knowledge/knowledge-runtime.yaml +36 -2
- package/dist/config/knowledge/procedural-memory-runtime.yaml +78 -0
- package/dist/config/{catalogs/models.yaml → models.yaml} +2 -2
- package/dist/config/prompts/direct-system.md +16 -0
- package/dist/config/prompts/orchestra-system.md +62 -0
- package/dist/config/prompts/routing-system.md +14 -0
- package/dist/config/runtime/runtime-memory.yaml +39 -5
- package/dist/config/runtime/workspace.yaml +7 -16
- package/dist/contracts/runtime.d.ts +242 -1
- package/dist/contracts/workspace.d.ts +2 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/init-project.js +178 -33
- package/dist/knowledge/contracts.d.ts +5 -0
- package/dist/knowledge/module.d.ts +5 -0
- package/dist/knowledge/module.js +340 -18
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/persistence/file-store.d.ts +5 -1
- package/dist/persistence/file-store.js +16 -0
- package/dist/persistence/sqlite-store.d.ts +4 -1
- package/dist/persistence/sqlite-store.js +88 -14
- package/dist/persistence/types.d.ts +4 -1
- package/dist/procedural/config.d.ts +63 -0
- package/dist/procedural/config.js +125 -0
- package/dist/procedural/index.d.ts +2 -0
- package/dist/procedural/index.js +1 -0
- package/dist/protocol/ag-ui/http.d.ts +3 -0
- package/dist/protocol/ag-ui/http.js +10 -0
- package/dist/request-events.d.ts +63 -0
- package/dist/request-events.js +400 -0
- package/dist/resource/isolation.js +11 -0
- package/dist/resource/resource-impl.d.ts +1 -0
- package/dist/resource/resource-impl.js +103 -12
- package/dist/resources/init-templates/agent-context/deep-research.md +5 -0
- package/dist/resources/init-templates/prompts/research-analyst-basic.md +1 -0
- package/dist/resources/init-templates/prompts/research-analyst-web-search.md +1 -0
- package/dist/resources/init-templates/prompts/research-host-deep-research-basic.md +1 -0
- package/dist/resources/init-templates/prompts/research-host-deep-research-web-search.md +1 -0
- package/dist/resources/init-templates/prompts/research-host-single-agent-basic.md +1 -0
- package/dist/resources/init-templates/prompts/research-host-single-agent-web-search.md +1 -0
- package/dist/resources/prompts/runtime/browser-capability-disclaimer-recovery.md +1 -0
- package/dist/resources/prompts/runtime/default-subagent.md +2 -0
- package/dist/resources/prompts/runtime/durable-memory-context.md +7 -0
- package/dist/resources/prompts/runtime/execution-with-tool-evidence-retry.md +1 -0
- package/dist/resources/prompts/runtime/execution-with-tool-evidence.md +1 -0
- package/dist/resources/prompts/runtime/invalid-tool-selection-recovery.md +1 -0
- package/dist/resources/prompts/runtime/memory-manager.md +31 -0
- package/dist/resources/prompts/runtime/memory-mutation-reconciliation.md +22 -0
- package/dist/resources/prompts/runtime/slash-command-skill.md +6 -0
- package/dist/resources/prompts/runtime/strict-tool-json.md +1 -0
- package/dist/resources/prompts/runtime/workspace-boundary-guidance.md +3 -0
- package/dist/resources/prompts/runtime/workspace-relative-path.md +1 -0
- package/dist/resources/prompts/runtime/write-todos-descriptive-content.md +1 -0
- package/dist/resources/prompts/runtime/write-todos-full-entry.md +1 -0
- package/dist/resources/prompts/runtime/write-todos-non-empty-initial-list.md +1 -0
- package/dist/resources/tools/_runtime_tool_helpers.mjs +152 -0
- package/dist/resources/tools/cancel_request.mjs +21 -0
- package/dist/resources/tools/fetch_url.mjs +23 -0
- package/dist/resources/tools/http_request.mjs +30 -0
- package/dist/resources/tools/inspect_approvals.mjs +27 -0
- package/dist/resources/tools/inspect_artifacts.mjs +21 -0
- package/dist/resources/tools/inspect_events.mjs +21 -0
- package/dist/resources/tools/inspect_requests.mjs +27 -0
- package/dist/resources/tools/inspect_sessions.mjs +21 -0
- package/dist/resources/tools/list_files.mjs +27 -0
- package/dist/resources/tools/read_artifact.mjs +22 -0
- package/dist/resources/tools/request_approval.mjs +27 -0
- package/dist/resources/tools/run_command.mjs +21 -0
- package/dist/resources/tools/schedule_task.mjs +76 -0
- package/dist/resources/tools/search_files.mjs +47 -0
- package/dist/resources/tools/send_message.mjs +23 -0
- package/dist/runtime/adapter/direct-builtin-utility.d.ts +1 -0
- package/dist/runtime/adapter/direct-builtin-utility.js +90 -0
- package/dist/runtime/adapter/flow/execution-context.d.ts +1 -1
- package/dist/runtime/adapter/flow/execution-context.js +1 -1
- package/dist/runtime/adapter/flow/invocation-flow.d.ts +1 -0
- package/dist/runtime/adapter/flow/invocation-flow.js +9 -1
- package/dist/runtime/adapter/flow/invoke-runtime.d.ts +1 -1
- package/dist/runtime/adapter/flow/stream-runtime.d.ts +5 -1
- package/dist/runtime/adapter/flow/stream-runtime.js +556 -35
- package/dist/runtime/adapter/invocation-result.js +3 -2
- package/dist/runtime/adapter/local-tool-invocation.d.ts +1 -1
- package/dist/runtime/adapter/local-tool-invocation.js +28 -4
- package/dist/runtime/adapter/middleware-assembly.js +3 -1
- package/dist/runtime/adapter/model/invocation-request.d.ts +4 -1
- package/dist/runtime/adapter/model/invocation-request.js +138 -16
- package/dist/runtime/adapter/model/message-assembly.js +2 -6
- package/dist/runtime/adapter/model/model-providers.js +103 -5
- package/dist/runtime/adapter/resilience.js +17 -2
- package/dist/runtime/adapter/runtime-adapter-support.d.ts +11 -7
- package/dist/runtime/adapter/runtime-adapter-support.js +39 -5
- package/dist/runtime/adapter/tool/builtin-middleware-tools.d.ts +63 -1
- package/dist/runtime/adapter/tool/builtin-middleware-tools.js +193 -21
- package/dist/runtime/adapter/tool/tool-arguments.d.ts +3 -1
- package/dist/runtime/adapter/tool/tool-arguments.js +52 -17
- package/dist/runtime/adapter/tool-resolution.d.ts +1 -0
- package/dist/runtime/adapter/tool-resolution.js +4 -2
- package/dist/runtime/agent-runtime-adapter.d.ts +27 -0
- package/dist/runtime/agent-runtime-adapter.js +163 -11
- package/dist/runtime/harness/events/event-bus.d.ts +1 -0
- package/dist/runtime/harness/events/event-bus.js +3 -0
- package/dist/runtime/harness/events/event-sink.d.ts +3 -0
- package/dist/runtime/harness/events/event-sink.js +16 -7
- package/dist/runtime/harness/events/streaming.d.ts +18 -1
- package/dist/runtime/harness/events/streaming.js +23 -10
- package/dist/runtime/harness/run/inspection.js +26 -5
- package/dist/runtime/harness/run/stream-run.d.ts +13 -4
- package/dist/runtime/harness/run/stream-run.js +448 -4
- package/dist/runtime/harness/run/surface-semantics.js +7 -34
- package/dist/runtime/harness/system/runtime-memory-manager.d.ts +3 -0
- package/dist/runtime/harness/system/runtime-memory-manager.js +384 -69
- package/dist/runtime/harness/system/runtime-memory-policy.d.ts +20 -1
- package/dist/runtime/harness/system/runtime-memory-policy.js +65 -17
- package/dist/runtime/harness/system/runtime-memory-records.js +100 -0
- package/dist/runtime/harness/system/runtime-memory-sync.js +2 -2
- package/dist/runtime/harness/system/store.d.ts +4 -0
- package/dist/runtime/harness/system/store.js +153 -0
- package/dist/runtime/harness.d.ts +9 -1
- package/dist/runtime/harness.js +141 -7
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.d.ts +8 -3
- package/dist/runtime/maintenance/sqlite-checkpoint-saver.js +152 -53
- package/dist/runtime/parsing/output-parsing.d.ts +10 -2
- package/dist/runtime/parsing/output-parsing.js +223 -16
- package/dist/runtime/parsing/stream-event-parsing.d.ts +7 -0
- package/dist/runtime/parsing/stream-event-parsing.js +51 -1
- package/dist/runtime/scheduling/system-schedule-manager.d.ts +41 -0
- package/dist/runtime/scheduling/system-schedule-manager.js +532 -0
- package/dist/runtime/support/embedding-models.d.ts +1 -1
- package/dist/runtime/support/embedding-models.js +5 -2
- package/dist/runtime/support/runtime-factories.js +1 -1
- package/dist/runtime/support/runtime-layout.d.ts +3 -0
- package/dist/runtime/support/runtime-layout.js +10 -1
- package/dist/runtime/support/runtime-prompts.d.ts +30 -0
- package/dist/runtime/support/runtime-prompts.js +55 -0
- package/dist/runtime/support/vector-stores.d.ts +1 -1
- package/dist/runtime/support/vector-stores.js +5 -2
- package/dist/upstream-events.js +8 -7
- package/dist/utils/bundled-text.d.ts +3 -0
- package/dist/utils/bundled-text.js +25 -0
- package/dist/utils/id.js +3 -2
- package/dist/workspace/agent-binding-compiler.js +53 -13
- package/dist/workspace/object-loader.js +64 -2
- package/dist/workspace/support/workspace-ref-utils.d.ts +2 -1
- package/dist/workspace/support/workspace-ref-utils.js +24 -5
- package/dist/workspace/yaml-object-reader.d.ts +1 -0
- package/dist/workspace/yaml-object-reader.js +95 -17
- package/package.json +11 -5
|
@@ -3,7 +3,8 @@ import { extractMessageText } from "../../../utils/message-content.js";
|
|
|
3
3
|
import { createResolvedModel } from "../../adapter/model/model-providers.js";
|
|
4
4
|
import { FileBackedStore } from "./store.js";
|
|
5
5
|
import { compileModel } from "../../../workspace/resource-compilers.js";
|
|
6
|
-
import { resolveRefId } from "../../../workspace/support/workspace-ref-utils.js";
|
|
6
|
+
import { resolvePromptValue, resolveRefId } from "../../../workspace/support/workspace-ref-utils.js";
|
|
7
|
+
import { renderRuntimeMemoryManagerPrompt, renderRuntimeMemoryMutationReconciliationPrompt } from "../../support/runtime-prompts.js";
|
|
7
8
|
const FORMATION_EVENT_TYPES = new Set([
|
|
8
9
|
"request.state.changed",
|
|
9
10
|
"approval.resolved",
|
|
@@ -52,14 +53,15 @@ export function readRuntimeMemoryFormationConfig(runtimeMemory, workspaceRoot) {
|
|
|
52
53
|
},
|
|
53
54
|
manager: {
|
|
54
55
|
enabled: asBoolean(manager?.enabled) ?? true,
|
|
55
|
-
strategy: asStrategy(manager?.strategy) ?? "
|
|
56
|
+
strategy: asStrategy(manager?.strategy) ?? "model",
|
|
56
57
|
modelRef: asNonEmptyString(manager?.modelRef),
|
|
58
|
+
prompt: resolvePromptValue(manager?.prompt, workspaceRoot),
|
|
57
59
|
maxContextRecords: asPositiveInteger(manager?.maxContextRecords) ?? 12,
|
|
58
60
|
},
|
|
59
61
|
background: {
|
|
60
62
|
enabled: asBoolean(background?.enabled) ?? true,
|
|
61
63
|
maxMessagesPerRequest: asPositiveInteger(background?.maxMessagesPerRequest) ?? asPositiveInteger(ingestion?.maxMessagesPerRequest) ?? 40,
|
|
62
|
-
scopes: normalizeScopeList(asMemoryScopes(background?.scopes) ?? ["
|
|
64
|
+
scopes: normalizeScopeList(asMemoryScopes(background?.scopes) ?? ["user", "project", "workspace"]),
|
|
63
65
|
stateStorePath: asNonEmptyString(background?.stateStorePath) ?? `knowledge/${workspaceBaseName}-memory-formation-state.json`,
|
|
64
66
|
writeOnApprovalResolution: asBoolean(background?.writeOnApprovalResolution) ?? asBoolean(ingestion?.writeOnApprovalResolution) ?? true,
|
|
65
67
|
writeOnRequestCompletion: asBoolean(background?.writeOnRequestCompletion) ?? asBoolean(ingestion?.writeOnRequestCompletion) ?? true,
|
|
@@ -91,29 +93,38 @@ function summarizeApprovals(approvals) {
|
|
|
91
93
|
export function createBackgroundMemoryCandidates(input) {
|
|
92
94
|
const latestUser = excerpt(input.messages.filter((message) => message.role === "user").at(-1));
|
|
93
95
|
const latestAssistant = excerpt(input.messages.filter((message) => message.role === "assistant").at(-1));
|
|
94
|
-
const userContext = latestUser ?? "
|
|
95
|
-
const assistantContext = latestAssistant ?? "
|
|
96
|
+
const userContext = latestUser ?? "(none)";
|
|
97
|
+
const assistantContext = latestAssistant ?? "(none)";
|
|
96
98
|
const approvals = summarizeApprovals(input.approvals);
|
|
97
99
|
const summarySeed = latestUser ?? latestAssistant ?? `Run ${input.requestId}`;
|
|
98
100
|
const baseSummary = summarySeed.length > 120 ? `${summarySeed.slice(0, 117)}...` : summarySeed;
|
|
99
101
|
const sourceRefBase = `runtime://sessions/${input.session.sessionId}/requests/${input.requestId}/background-reflection`;
|
|
100
|
-
return
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
102
|
+
return [{
|
|
103
|
+
kind: "episodic",
|
|
104
|
+
sourceType: "runtime-transcript",
|
|
105
|
+
sourceRef: sourceRefBase,
|
|
106
|
+
summary: baseSummary,
|
|
107
|
+
content: [
|
|
108
|
+
"Transcript evidence for durable knowledge extraction.",
|
|
109
|
+
`Trigger: ${input.trigger}`,
|
|
110
|
+
"",
|
|
111
|
+
"Latest user message:",
|
|
112
|
+
userContext,
|
|
113
|
+
"",
|
|
114
|
+
"Latest assistant response:",
|
|
115
|
+
assistantContext,
|
|
116
|
+
"",
|
|
117
|
+
"Approval snapshot:",
|
|
118
|
+
approvals,
|
|
119
|
+
].join("\n"),
|
|
120
|
+
confidence: 0.72,
|
|
121
|
+
observedAt: input.recordedAt,
|
|
122
|
+
provenance: {
|
|
123
|
+
scopeOptions: input.scopes,
|
|
124
|
+
trigger: input.trigger,
|
|
125
|
+
},
|
|
126
|
+
tags: ["background-extraction", "langmem-aligned", "reusable_summaries", input.trigger],
|
|
127
|
+
}];
|
|
117
128
|
}
|
|
118
129
|
function normalizeKind(value, fallback) {
|
|
119
130
|
if (value === "semantic" || value === "episodic" || value === "procedural") {
|
|
@@ -127,12 +138,41 @@ function normalizeScope(value, fallback) {
|
|
|
127
138
|
}
|
|
128
139
|
return fallback;
|
|
129
140
|
}
|
|
141
|
+
function extractAllowedScopes(candidate) {
|
|
142
|
+
const provenance = typeof candidate.provenance === "object" && candidate.provenance !== null && !Array.isArray(candidate.provenance)
|
|
143
|
+
? candidate.provenance
|
|
144
|
+
: undefined;
|
|
145
|
+
const scopeOptions = provenance?.scopeOptions;
|
|
146
|
+
if (!Array.isArray(scopeOptions)) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
const allowed = scopeOptions
|
|
150
|
+
.filter((item) => item === "session" || item === "agent" || item === "workspace" || item === "user" || item === "project");
|
|
151
|
+
return allowed.length > 0 ? Array.from(new Set(allowed)) : undefined;
|
|
152
|
+
}
|
|
153
|
+
function normalizeScopeWithAllowedSet(value, fallback, allowedScopes) {
|
|
154
|
+
const normalized = normalizeScope(value, fallback);
|
|
155
|
+
if (!allowedScopes || allowedScopes.length === 0) {
|
|
156
|
+
return normalized;
|
|
157
|
+
}
|
|
158
|
+
if (normalized && allowedScopes.includes(normalized)) {
|
|
159
|
+
return normalized;
|
|
160
|
+
}
|
|
161
|
+
if (fallback && allowedScopes.includes(fallback)) {
|
|
162
|
+
return fallback;
|
|
163
|
+
}
|
|
164
|
+
return allowedScopes[0];
|
|
165
|
+
}
|
|
130
166
|
function normalizeTags(value, fallback) {
|
|
167
|
+
const fallbackTags = Array.isArray(fallback)
|
|
168
|
+
? fallback.filter((item) => typeof item === "string" && item.trim().length > 0)
|
|
169
|
+
: [];
|
|
131
170
|
if (!Array.isArray(value)) {
|
|
132
|
-
return fallback;
|
|
171
|
+
return fallbackTags.length > 0 ? fallbackTags : fallback;
|
|
133
172
|
}
|
|
134
173
|
const tags = value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
135
|
-
|
|
174
|
+
const merged = Array.from(new Set([...fallbackTags, ...tags]));
|
|
175
|
+
return merged.length > 0 ? merged : fallback;
|
|
136
176
|
}
|
|
137
177
|
function normalizeConfidence(value, fallback) {
|
|
138
178
|
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
@@ -140,15 +180,256 @@ function normalizeConfidence(value, fallback) {
|
|
|
140
180
|
}
|
|
141
181
|
return Math.min(1, Math.max(0, value));
|
|
142
182
|
}
|
|
183
|
+
function normalizeOperationalRule(value, fallback) {
|
|
184
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
185
|
+
return fallback;
|
|
186
|
+
}
|
|
187
|
+
const typed = value;
|
|
188
|
+
const trigger = typeof typed.trigger === "string" && typed.trigger.trim().length > 0 ? typed.trigger.trim() : undefined;
|
|
189
|
+
const action = typeof typed.action === "string" && typed.action.trim().length > 0 ? typed.action.trim() : undefined;
|
|
190
|
+
const target = typeof typed.target === "string" && typed.target.trim().length > 0 ? typed.target.trim() : undefined;
|
|
191
|
+
const effect = typed.effect === "apply" || typed.effect === "invalidate"
|
|
192
|
+
? typed.effect
|
|
193
|
+
: undefined;
|
|
194
|
+
if (!trigger || !action || !target) {
|
|
195
|
+
return fallback;
|
|
196
|
+
}
|
|
197
|
+
return { trigger, action, target, ...(effect ? { effect } : {}) };
|
|
198
|
+
}
|
|
199
|
+
function normalizeKnowledgeMutation(value, fallback) {
|
|
200
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
201
|
+
return fallback;
|
|
202
|
+
}
|
|
203
|
+
const typed = value;
|
|
204
|
+
const identity = typeof typed.identity === "string" && typed.identity.trim().length > 0 ? typed.identity.trim() : undefined;
|
|
205
|
+
const operation = typed.operation === "create" || typed.operation === "update" || typed.operation === "delete"
|
|
206
|
+
? typed.operation
|
|
207
|
+
: undefined;
|
|
208
|
+
if (!identity) {
|
|
209
|
+
return fallback;
|
|
210
|
+
}
|
|
211
|
+
return { identity, ...(operation ? { operation } : {}) };
|
|
212
|
+
}
|
|
213
|
+
function asCandidateOutputs(parsed, candidate, allowedScopes, recordedAt) {
|
|
214
|
+
const rawMutations = Array.isArray(parsed.mutations) ? parsed.mutations : undefined;
|
|
215
|
+
const outputs = rawMutations && rawMutations.length > 0
|
|
216
|
+
? rawMutations.filter((item) => typeof item === "object" && item !== null && !Array.isArray(item))
|
|
217
|
+
: [parsed];
|
|
218
|
+
return outputs.map((output) => ({
|
|
219
|
+
...candidate,
|
|
220
|
+
content: typeof output.content === "string" && output.content.trim().length > 0 ? output.content.trim() : candidate.content,
|
|
221
|
+
summary: typeof output.summary === "string" && output.summary.trim().length > 0 ? output.summary.trim() : candidate.summary,
|
|
222
|
+
kind: normalizeKind(output.kind, normalizeKind(candidate.kind, undefined)),
|
|
223
|
+
scope: normalizeScopeWithAllowedSet(output.scope, normalizeScope(candidate.scope, undefined), allowedScopes),
|
|
224
|
+
tags: normalizeTags(output.tags, candidate.tags),
|
|
225
|
+
confidence: normalizeConfidence(output.confidence, candidate.confidence),
|
|
226
|
+
knowledgeMutation: normalizeKnowledgeMutation(output.knowledgeMutation, candidate.knowledgeMutation),
|
|
227
|
+
operationalRule: normalizeOperationalRule(output.operationalRule, candidate.operationalRule),
|
|
228
|
+
observedAt: candidate.observedAt ?? recordedAt,
|
|
229
|
+
}));
|
|
230
|
+
}
|
|
143
231
|
function extractText(value) {
|
|
144
232
|
if (typeof value === "string") {
|
|
145
233
|
return value;
|
|
146
234
|
}
|
|
147
|
-
if (typeof value
|
|
235
|
+
if (typeof value !== "object" || value === null) {
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
if ("content" in value && typeof value.content === "string") {
|
|
148
239
|
return String(value.content);
|
|
149
240
|
}
|
|
241
|
+
const kwargs = "kwargs" in value && typeof value.kwargs === "object" && value.kwargs !== null
|
|
242
|
+
? value.kwargs
|
|
243
|
+
: undefined;
|
|
244
|
+
if (typeof kwargs?.content === "string") {
|
|
245
|
+
return kwargs.content;
|
|
246
|
+
}
|
|
150
247
|
return undefined;
|
|
151
248
|
}
|
|
249
|
+
function normalizeCompareText(value) {
|
|
250
|
+
return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
251
|
+
}
|
|
252
|
+
function tokenizeText(value) {
|
|
253
|
+
return new Set(value
|
|
254
|
+
.toLowerCase()
|
|
255
|
+
.split(/[^a-z0-9_]+/i)
|
|
256
|
+
.map((token) => token.trim())
|
|
257
|
+
.filter((token) => token.length > 2));
|
|
258
|
+
}
|
|
259
|
+
function jaccardTextSimilarity(left, right) {
|
|
260
|
+
const leftTokens = tokenizeText(left);
|
|
261
|
+
const rightTokens = tokenizeText(right);
|
|
262
|
+
if (leftTokens.size === 0 || rightTokens.size === 0) {
|
|
263
|
+
return 0;
|
|
264
|
+
}
|
|
265
|
+
let intersection = 0;
|
|
266
|
+
for (const token of leftTokens) {
|
|
267
|
+
if (rightTokens.has(token)) {
|
|
268
|
+
intersection += 1;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
const union = new Set([...leftTokens, ...rightTokens]).size;
|
|
272
|
+
return union === 0 ? 0 : intersection / union;
|
|
273
|
+
}
|
|
274
|
+
function containsDeletionSignal(value) {
|
|
275
|
+
const normalized = normalizeCompareText(value);
|
|
276
|
+
if (!normalized) {
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
return [
|
|
280
|
+
"delete",
|
|
281
|
+
"deleted",
|
|
282
|
+
"remove",
|
|
283
|
+
"removed",
|
|
284
|
+
"revoked",
|
|
285
|
+
"forbidden",
|
|
286
|
+
"not allowed",
|
|
287
|
+
"no longer",
|
|
288
|
+
"unavailable",
|
|
289
|
+
"disabled",
|
|
290
|
+
"deprecated",
|
|
291
|
+
"取消",
|
|
292
|
+
"撤销",
|
|
293
|
+
"删除",
|
|
294
|
+
"已删除",
|
|
295
|
+
"删掉",
|
|
296
|
+
"移除",
|
|
297
|
+
"不再",
|
|
298
|
+
"不可用",
|
|
299
|
+
"不能",
|
|
300
|
+
"无法",
|
|
301
|
+
"禁用",
|
|
302
|
+
"废弃",
|
|
303
|
+
].some((signal) => normalized.includes(signal));
|
|
304
|
+
}
|
|
305
|
+
function containsRuleTarget(candidate, record) {
|
|
306
|
+
const target = record.operationalRule?.target?.trim().toLowerCase();
|
|
307
|
+
if (!target) {
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
const candidateText = `${candidate.summary ?? ""}\n${candidate.content}`.toLowerCase();
|
|
311
|
+
return candidateText.includes(target);
|
|
312
|
+
}
|
|
313
|
+
function extractSalientLiterals(value) {
|
|
314
|
+
const results = new Set();
|
|
315
|
+
const normalized = value.trim();
|
|
316
|
+
if (!normalized) {
|
|
317
|
+
return results;
|
|
318
|
+
}
|
|
319
|
+
for (const match of normalized.matchAll(/[`'"]([^`'"]{1,64})[`'"]/g)) {
|
|
320
|
+
const literal = match[1]?.trim().toLowerCase();
|
|
321
|
+
if (literal && literal.length >= 2) {
|
|
322
|
+
results.add(literal);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
for (const match of normalized.matchAll(/\b[a-z][a-z0-9._/-]{1,63}\b/gi)) {
|
|
326
|
+
const token = match[0]?.trim().toLowerCase();
|
|
327
|
+
if (token && !["system", "startup", "command", "memory", "instruction", "user", "deleted"].includes(token)) {
|
|
328
|
+
results.add(token);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return results;
|
|
332
|
+
}
|
|
333
|
+
function sharesSalientLiteral(candidate, record) {
|
|
334
|
+
const candidateLiterals = extractSalientLiterals(`${candidate.summary ?? ""}\n${candidate.content}`);
|
|
335
|
+
const recordLiterals = extractSalientLiterals(`${record.summary}\n${record.content}`);
|
|
336
|
+
if (candidateLiterals.size === 0 || recordLiterals.size === 0) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
for (const literal of candidateLiterals) {
|
|
340
|
+
if (recordLiterals.has(literal)) {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
return false;
|
|
345
|
+
}
|
|
346
|
+
function selectMutationFallbackMatch(candidate, existingRecords) {
|
|
347
|
+
const candidateScope = normalizeScope(candidate.scope, undefined);
|
|
348
|
+
return existingRecords
|
|
349
|
+
.filter((record) => record.status === "active" && !!record.knowledgeIdentity && record.knowledgeOperation !== "delete")
|
|
350
|
+
.map((record) => {
|
|
351
|
+
let score = 0;
|
|
352
|
+
if (candidateScope && record.scope === candidateScope) {
|
|
353
|
+
score += 2;
|
|
354
|
+
}
|
|
355
|
+
if (containsRuleTarget(candidate, record)) {
|
|
356
|
+
score += 10;
|
|
357
|
+
}
|
|
358
|
+
if (sharesSalientLiteral(candidate, record)) {
|
|
359
|
+
score += 6;
|
|
360
|
+
}
|
|
361
|
+
if (record.operationalRule) {
|
|
362
|
+
score += 2;
|
|
363
|
+
}
|
|
364
|
+
return { record, score };
|
|
365
|
+
})
|
|
366
|
+
.filter((item) => item.score > 0)
|
|
367
|
+
.sort((left, right) => right.score - left.score || right.record.lastConfirmedAt.localeCompare(left.record.lastConfirmedAt))
|
|
368
|
+
.map((item) => item.record)
|
|
369
|
+
.at(0);
|
|
370
|
+
}
|
|
371
|
+
function applyDeterministicMutationFallback(candidate, existingRecords) {
|
|
372
|
+
const currentMutation = candidate.knowledgeMutation;
|
|
373
|
+
if (currentMutation && currentMutation.operation !== "create") {
|
|
374
|
+
return candidate;
|
|
375
|
+
}
|
|
376
|
+
if (!containsDeletionSignal(`${candidate.summary ?? ""}\n${candidate.content}`)) {
|
|
377
|
+
return candidate;
|
|
378
|
+
}
|
|
379
|
+
const matchingRule = selectMutationFallbackMatch(candidate, existingRecords);
|
|
380
|
+
if (!matchingRule?.knowledgeIdentity) {
|
|
381
|
+
return candidate;
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
...candidate,
|
|
385
|
+
scope: matchingRule.scope,
|
|
386
|
+
knowledgeMutation: {
|
|
387
|
+
identity: matchingRule.knowledgeIdentity,
|
|
388
|
+
operation: "delete",
|
|
389
|
+
},
|
|
390
|
+
...(matchingRule.operationalRule
|
|
391
|
+
? {
|
|
392
|
+
operationalRule: {
|
|
393
|
+
...matchingRule.operationalRule,
|
|
394
|
+
effect: "invalidate",
|
|
395
|
+
},
|
|
396
|
+
}
|
|
397
|
+
: {}),
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
function selectRelatedContextRecords(candidate, existingRecords, maxRecords) {
|
|
401
|
+
const candidateScope = normalizeScope(candidate.scope, undefined);
|
|
402
|
+
const candidateSummary = normalizeCompareText(candidate.summary?.trim() || candidate.content);
|
|
403
|
+
const candidateContent = normalizeCompareText(candidate.content);
|
|
404
|
+
const candidateSourceRef = typeof candidate.sourceRef === "string" ? candidate.sourceRef.trim() : "";
|
|
405
|
+
return existingRecords
|
|
406
|
+
.filter((record) => record.status === "active")
|
|
407
|
+
.map((record) => {
|
|
408
|
+
let score = 0;
|
|
409
|
+
if (candidateScope && record.scope === candidateScope) {
|
|
410
|
+
score += 4;
|
|
411
|
+
}
|
|
412
|
+
if (candidateSourceRef && record.sourceRefs.includes(candidateSourceRef)) {
|
|
413
|
+
score += 12;
|
|
414
|
+
}
|
|
415
|
+
if (normalizeCompareText(record.summary) === candidateSummary) {
|
|
416
|
+
score += 10;
|
|
417
|
+
}
|
|
418
|
+
if (normalizeCompareText(record.content) === candidateContent) {
|
|
419
|
+
score += 9;
|
|
420
|
+
}
|
|
421
|
+
score += jaccardTextSimilarity(record.summary, candidate.summary ?? candidate.content) * 4;
|
|
422
|
+
score += jaccardTextSimilarity(record.content, candidate.content) * 3;
|
|
423
|
+
if (score > 0 && record.lastConfirmedAt) {
|
|
424
|
+
score += Math.max(0, 1 - ((Date.now() - Date.parse(record.lastConfirmedAt)) / (1000 * 60 * 60 * 24 * 365)));
|
|
425
|
+
}
|
|
426
|
+
return { record, score };
|
|
427
|
+
})
|
|
428
|
+
.filter((item) => item.score > 0)
|
|
429
|
+
.sort((left, right) => right.score - left.score || right.record.lastConfirmedAt.localeCompare(left.record.lastConfirmedAt))
|
|
430
|
+
.slice(0, maxRecords)
|
|
431
|
+
.map((item) => item.record);
|
|
432
|
+
}
|
|
152
433
|
function tryParseJsonObject(text) {
|
|
153
434
|
try {
|
|
154
435
|
const parsed = JSON.parse(text);
|
|
@@ -168,49 +449,83 @@ function tryParseJsonObject(text) {
|
|
|
168
449
|
}
|
|
169
450
|
}
|
|
170
451
|
}
|
|
171
|
-
function
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
""
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
452
|
+
async function reconcileKnowledgeMutation(input) {
|
|
453
|
+
const eligibleExisting = input.existingRecords.filter((record) => typeof record.knowledgeIdentity === "string" && record.knowledgeIdentity.trim().length > 0);
|
|
454
|
+
if (eligibleExisting.length === 0) {
|
|
455
|
+
return input.candidate;
|
|
456
|
+
}
|
|
457
|
+
const currentMutation = input.candidate.knowledgeMutation;
|
|
458
|
+
if (!currentMutation || currentMutation.operation !== "create") {
|
|
459
|
+
return input.candidate;
|
|
460
|
+
}
|
|
461
|
+
try {
|
|
462
|
+
const response = await input.invoker.invoke(renderRuntimeMemoryMutationReconciliationPrompt({
|
|
463
|
+
candidate: input.candidate,
|
|
464
|
+
existingRecords: eligibleExisting,
|
|
465
|
+
}), {});
|
|
466
|
+
const parsed = tryParseJsonObject(extractText(response) ?? "");
|
|
467
|
+
if (!parsed || parsed.reuseExistingIdentity !== true) {
|
|
468
|
+
return input.candidate;
|
|
469
|
+
}
|
|
470
|
+
const identity = typeof parsed.identity === "string" ? parsed.identity.trim() : "";
|
|
471
|
+
const matched = eligibleExisting.find((record) => record.knowledgeIdentity === identity);
|
|
472
|
+
if (!matched) {
|
|
473
|
+
return input.candidate;
|
|
474
|
+
}
|
|
475
|
+
const operation = parsed.operation === "update" || parsed.operation === "delete"
|
|
476
|
+
? parsed.operation
|
|
477
|
+
: currentMutation.operation;
|
|
478
|
+
const reconciledScope = normalizeScopeWithAllowedSet(parsed.scope, matched.scope, extractAllowedScopes(input.candidate));
|
|
479
|
+
return {
|
|
480
|
+
...input.candidate,
|
|
481
|
+
knowledgeMutation: {
|
|
482
|
+
identity,
|
|
483
|
+
operation,
|
|
484
|
+
},
|
|
485
|
+
scope: reconciledScope ?? input.candidate.scope ?? matched.scope,
|
|
486
|
+
operationalRule: operation === "delete" && matched.operationalRule
|
|
487
|
+
? {
|
|
488
|
+
...matched.operationalRule,
|
|
489
|
+
effect: "invalidate",
|
|
490
|
+
}
|
|
491
|
+
: input.candidate.operationalRule,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
catch {
|
|
495
|
+
return input.candidate;
|
|
496
|
+
}
|
|
198
497
|
}
|
|
199
498
|
export async function runModelMemoryManager(input) {
|
|
200
|
-
|
|
499
|
+
let resolvedModel;
|
|
500
|
+
try {
|
|
501
|
+
resolvedModel = await createResolvedModel(input.model, input.modelResolver);
|
|
502
|
+
}
|
|
503
|
+
catch {
|
|
504
|
+
return input.candidates;
|
|
505
|
+
}
|
|
201
506
|
const invoker = resolvedModel;
|
|
202
507
|
if (typeof invoker.invoke !== "function") {
|
|
203
508
|
return input.candidates;
|
|
204
509
|
}
|
|
510
|
+
const callableInvoker = invoker;
|
|
205
511
|
const transformed = [];
|
|
206
512
|
for (const candidate of input.candidates) {
|
|
207
|
-
const
|
|
513
|
+
const allowedScopes = extractAllowedScopes(candidate);
|
|
514
|
+
const prompt = renderRuntimeMemoryManagerPrompt({
|
|
208
515
|
candidate,
|
|
209
516
|
sessionId: input.sessionId,
|
|
210
517
|
requestId: input.requestId,
|
|
211
|
-
existingRecords: input.existingRecords,
|
|
518
|
+
existingRecords: selectRelatedContextRecords(candidate, input.existingRecords, input.maxContextRecords ?? input.existingRecords.length),
|
|
519
|
+
template: input.promptTemplate,
|
|
212
520
|
});
|
|
213
|
-
|
|
521
|
+
let response;
|
|
522
|
+
try {
|
|
523
|
+
response = await callableInvoker.invoke(prompt, {});
|
|
524
|
+
}
|
|
525
|
+
catch {
|
|
526
|
+
transformed.push(candidate);
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
214
529
|
const parsed = tryParseJsonObject(extractText(response) ?? "");
|
|
215
530
|
if (!parsed) {
|
|
216
531
|
transformed.push(candidate);
|
|
@@ -219,16 +534,15 @@ export async function runModelMemoryManager(input) {
|
|
|
219
534
|
if (parsed.store === false) {
|
|
220
535
|
continue;
|
|
221
536
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
537
|
+
const refinedCandidates = asCandidateOutputs(parsed, candidate, allowedScopes, input.recordedAt);
|
|
538
|
+
for (const refinedCandidate of refinedCandidates) {
|
|
539
|
+
const reconciledCandidate = await reconcileKnowledgeMutation({
|
|
540
|
+
invoker: callableInvoker,
|
|
541
|
+
candidate: refinedCandidate,
|
|
542
|
+
existingRecords: selectRelatedContextRecords(refinedCandidate, input.existingRecords, input.maxContextRecords ?? input.existingRecords.length),
|
|
543
|
+
});
|
|
544
|
+
transformed.push(applyDeterministicMutationFallback(reconciledCandidate, input.existingRecords));
|
|
545
|
+
}
|
|
232
546
|
}
|
|
233
547
|
return transformed;
|
|
234
548
|
}
|
|
@@ -239,9 +553,8 @@ export function createRuntimeMemoryManager(input) {
|
|
|
239
553
|
return candidates;
|
|
240
554
|
}
|
|
241
555
|
const contextRecords = existingRecords
|
|
242
|
-
.filter((record) => record.status === "active")
|
|
243
|
-
|
|
244
|
-
if (input.config.manager.strategy !== "model") {
|
|
556
|
+
.filter((record) => record.status === "active");
|
|
557
|
+
if (input.config.manager.strategy === "rules") {
|
|
245
558
|
return candidates;
|
|
246
559
|
}
|
|
247
560
|
if (!binding.langchainAgentParams?.model) {
|
|
@@ -263,6 +576,8 @@ export function createRuntimeMemoryManager(input) {
|
|
|
263
576
|
requestId,
|
|
264
577
|
recordedAt,
|
|
265
578
|
existingRecords: contextRecords,
|
|
579
|
+
maxContextRecords: input.config.manager.maxContextRecords,
|
|
580
|
+
promptTemplate: input.config.manager.prompt,
|
|
266
581
|
modelResolver: input.modelResolver,
|
|
267
582
|
});
|
|
268
583
|
},
|
|
@@ -4,6 +4,11 @@ export type ResolvedRuntimeMemoryPolicyConfig = {
|
|
|
4
4
|
defaultTopK: number;
|
|
5
5
|
maxPromptMemories: number;
|
|
6
6
|
};
|
|
7
|
+
writePolicy: {
|
|
8
|
+
mode: "all" | "selective" | "disabled";
|
|
9
|
+
allow: string[];
|
|
10
|
+
deny: string[];
|
|
11
|
+
};
|
|
7
12
|
namespaces: {
|
|
8
13
|
session: string;
|
|
9
14
|
workspace: string;
|
|
@@ -21,4 +26,18 @@ export declare function normalizeLangMemMemoryKind(kind: string | undefined): "s
|
|
|
21
26
|
export declare function readRuntimeMemoryPolicyConfig(runtimeMemory: Record<string, unknown> | undefined, workspaceRoot: string): ResolvedRuntimeMemoryPolicyConfig | undefined;
|
|
22
27
|
export declare function readRuntimeMemoryMaintenanceConfig(runtimeMemory: Record<string, unknown> | undefined): ResolvedRuntimeMemoryMaintenanceConfig | undefined;
|
|
23
28
|
export declare function resolveMemoryNamespace(template: string, values: Record<string, string | undefined>): string[];
|
|
24
|
-
export declare function
|
|
29
|
+
export declare function hasExplicitResourceReference(text: string): boolean;
|
|
30
|
+
export declare function extractExplicitResourceReferences(text: string): string[];
|
|
31
|
+
export declare function shouldRecallDurableMemory(text: string): boolean;
|
|
32
|
+
export declare function collectMemoryCandidateLabels(candidate: {
|
|
33
|
+
kind?: string;
|
|
34
|
+
scope?: string;
|
|
35
|
+
sourceType?: string;
|
|
36
|
+
tags?: string[];
|
|
37
|
+
}): string[];
|
|
38
|
+
export declare function shouldStoreMemoryCandidate(policy: ResolvedRuntimeMemoryPolicyConfig | null | undefined, candidate: {
|
|
39
|
+
kind?: string;
|
|
40
|
+
scope?: string;
|
|
41
|
+
sourceType?: string;
|
|
42
|
+
tags?: string[];
|
|
43
|
+
}): boolean;
|