@devflow-tools/mcp-server 0.17.7 → 0.18.0
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/LICENSE +21 -0
- package/README.md +2 -2
- package/dist/command-registry.json +5 -5
- package/dist/domain-tool-registry.d.ts +3 -0
- package/dist/domain-tool-registry.d.ts.map +1 -0
- package/dist/domain-tool-registry.js +24 -0
- package/dist/domain-tool-registry.js.map +1 -0
- package/dist/enforcer/constitutional.js +1 -1
- package/dist/enforcer/constitutional.js.map +1 -1
- package/dist/enforcer/index.d.ts +2 -2
- package/dist/enforcer/index.d.ts.map +1 -1
- package/dist/enforcer/index.js +140 -49
- package/dist/enforcer/index.js.map +1 -1
- package/dist/enforcer/rule-engine.d.ts +1 -1
- package/dist/enforcer/rule-engine.d.ts.map +1 -1
- package/dist/enforcer/rule-engine.js +1 -1
- package/dist/enforcer/rule-engine.js.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/resources.d.ts +1 -1
- package/dist/resources.d.ts.map +1 -1
- package/dist/retrieval-composition.d.ts +73 -0
- package/dist/retrieval-composition.d.ts.map +1 -0
- package/dist/retrieval-composition.js +611 -0
- package/dist/retrieval-composition.js.map +1 -0
- package/dist/runtime-composition.d.ts +42 -0
- package/dist/runtime-composition.d.ts.map +1 -0
- package/dist/runtime-composition.js +93 -0
- package/dist/runtime-composition.js.map +1 -0
- package/dist/sampling-evidence-reranker.d.ts +4 -0
- package/dist/sampling-evidence-reranker.d.ts.map +1 -0
- package/dist/sampling-evidence-reranker.js +82 -0
- package/dist/sampling-evidence-reranker.js.map +1 -0
- package/dist/semantic-sampling-resolver.d.ts +7 -6
- package/dist/semantic-sampling-resolver.d.ts.map +1 -1
- package/dist/semantic-sampling-resolver.js +191 -71
- package/dist/semantic-sampling-resolver.js.map +1 -1
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +15 -6
- package/dist/server.js.map +1 -1
- package/dist/task-evidence-service.d.ts +24 -0
- package/dist/task-evidence-service.d.ts.map +1 -0
- package/dist/task-evidence-service.js +202 -0
- package/dist/task-evidence-service.js.map +1 -0
- package/dist/tool-contracts.d.ts +26 -7
- package/dist/tool-contracts.d.ts.map +1 -1
- package/dist/tool-contracts.js +27 -6
- package/dist/tool-contracts.js.map +1 -1
- package/dist/tool-profile.d.ts +1 -0
- package/dist/tool-profile.d.ts.map +1 -1
- package/dist/tool-profile.js +13 -2
- package/dist/tool-profile.js.map +1 -1
- package/dist/tools.d.ts +11 -2
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +295 -335
- package/dist/tools.js.map +1 -1
- package/package.json +34 -11
package/dist/tools.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { loadSemanticExecutionContext, retrieveProjectEvidence, } from './retrieval-composition.js';
|
|
2
|
+
import { projectTaskKnowledgeResult, projectTaskMemoryResult, queryAuthoritativeTaskEvidence, } from './task-evidence-service.js';
|
|
3
|
+
import { resolveTaskSemanticContext, } from '@devflow-tools/semantic-engine';
|
|
3
4
|
import { resolveCapabilityRollout } from "@devflow-tools/sdk/capability-rollout";
|
|
4
5
|
import { canonicalizeProjectRoot, wrapHandlerRequireRoot } from "./plugin-guards.js";
|
|
5
6
|
import { getReportResourceUri, readToolReport } from "./report-store.js";
|
|
6
7
|
import { normalizeTurnId, openGlobalDevFlowDatabase, } from "@devflow-tools/database";
|
|
7
|
-
import { createHash } from "node:crypto";
|
|
8
8
|
import { isAbsolute, normalize, relative } from "node:path";
|
|
9
9
|
import { normalizeMemoryCandidates, OBSERVATION_TYPE_SCHEMA, rejectedToolResult, TOOL_RESULT_OUTPUT_SCHEMA, } from "./tool-contracts.js";
|
|
10
|
-
import { emitSemanticControlLog } from '@devflow-tools/telemetry';
|
|
10
|
+
import { emitSemanticControlLog, SemanticRuntimeEventProjector } from '@devflow-tools/telemetry';
|
|
11
|
+
import { ActivationSnapshotStore, TaskEventStore, TaskKernel } from '@devflow-tools/task-runtime';
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
11
13
|
export const GUARDED_CORE_TOOL_NAMES = new Set([
|
|
12
14
|
"get_project_context",
|
|
13
15
|
"search_symbol",
|
|
@@ -57,6 +59,7 @@ export function getCoreTools(knowledgeScopes = []) {
|
|
|
57
59
|
type: "object",
|
|
58
60
|
properties: {
|
|
59
61
|
query: { type: "string", description: "自然语言查询" },
|
|
62
|
+
budgetTokens: { type: "number", description: "Maximum response tokens", default: 2000, minimum: 1 },
|
|
60
63
|
mode: { type: "string", enum: ["fast", "deep"], default: "fast" },
|
|
61
64
|
expandedTerms: { type: "string", description: "Agent 预翻译的英文关键词(空格分隔),用于提升中文查询的搜索效果" },
|
|
62
65
|
retrievalSessionId: { type: "string", description: "首轮上下文返回的检索会话 ID;仅用于最多三轮的定向补检" },
|
|
@@ -133,9 +136,6 @@ export function getCoreTools(knowledgeScopes = []) {
|
|
|
133
136
|
status: { type: "string", enum: ["done", "failed", "skipped", "waiting_user"] },
|
|
134
137
|
output: { type: "string", description: "Bounded step result summary" },
|
|
135
138
|
duration: { type: "number", minimum: 0, description: "Step duration in milliseconds" },
|
|
136
|
-
contextReceipt: { type: "string", description: "Context receipt used for the host action" },
|
|
137
|
-
executionId: { type: "string", description: "Host execution identity" },
|
|
138
|
-
toolUseIds: { type: "array", items: { type: "string" }, maxItems: 100 },
|
|
139
139
|
changedFiles: { type: "array", items: { type: "string" }, maxItems: 100 },
|
|
140
140
|
verification: {
|
|
141
141
|
type: "object",
|
|
@@ -179,7 +179,7 @@ export function getCoreTools(knowledgeScopes = []) {
|
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
name: "get_memory",
|
|
182
|
-
description: "
|
|
182
|
+
description: "投影当前 canonical task authoritative receipt 中的 Memory 证据",
|
|
183
183
|
inputSchema: {
|
|
184
184
|
type: "object",
|
|
185
185
|
properties: {
|
|
@@ -261,6 +261,16 @@ export function getCoreTools(knowledgeScopes = []) {
|
|
|
261
261
|
items: { type: "string", minLength: 1 },
|
|
262
262
|
description: "Exact, verbatim substrings copied from the canonical user prompt that support this candidate. Required when refining an already committed explicit-memory turn.",
|
|
263
263
|
},
|
|
264
|
+
operation: {
|
|
265
|
+
type: "string",
|
|
266
|
+
enum: ["add", "reinforce", "supersede", "link", "hold", "retire", "none"],
|
|
267
|
+
description: "Requested lifecycle operation. supersede/retire require referencedFactIds and exact evidenceSpans; omit when uncertain.",
|
|
268
|
+
},
|
|
269
|
+
referencedFactIds: {
|
|
270
|
+
type: "array",
|
|
271
|
+
items: { type: "string", minLength: 1 },
|
|
272
|
+
description: "Exact existing fact IDs affected by reinforce/link/supersede/retire. Entity or alias matches are not fact identity.",
|
|
273
|
+
},
|
|
264
274
|
},
|
|
265
275
|
},
|
|
266
276
|
},
|
|
@@ -351,7 +361,7 @@ export function getCoreTools(knowledgeScopes = []) {
|
|
|
351
361
|
},
|
|
352
362
|
{
|
|
353
363
|
name: "get_knowledge",
|
|
354
|
-
description: "
|
|
364
|
+
description: "投影当前 canonical task authoritative receipt 中的 Knowledge 证据",
|
|
355
365
|
inputSchema: {
|
|
356
366
|
type: "object",
|
|
357
367
|
properties: {
|
|
@@ -582,14 +592,9 @@ function resolveBoundContextTask(input) {
|
|
|
582
592
|
|| record.turnId !== input.turnId || record.requestId !== input.requestId) {
|
|
583
593
|
throw new Error('TASK_IDENTITY_MISMATCH:intent artifact does not belong to this MCP request');
|
|
584
594
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
turnId: record.turnId,
|
|
589
|
-
sourceIntentHash: record.artifactHash,
|
|
590
|
-
});
|
|
591
|
-
if (!planRecord)
|
|
592
|
-
throw new Error(`QUERY_PLAN_NOT_FOUND:${record.artifactHash}`);
|
|
595
|
+
if (!record.executionId) {
|
|
596
|
+
throw new Error('TASK_IDENTITY_INCOMPLETE:intent artifact execution identity is missing');
|
|
597
|
+
}
|
|
593
598
|
const identity = {
|
|
594
599
|
projectRoot: record.projectRoot,
|
|
595
600
|
projectId: record.projectId,
|
|
@@ -597,7 +602,7 @@ function resolveBoundContextTask(input) {
|
|
|
597
602
|
sessionId: record.sessionId,
|
|
598
603
|
turnId: record.turnId,
|
|
599
604
|
requestId: record.requestId,
|
|
600
|
-
|
|
605
|
+
executionId: record.executionId,
|
|
601
606
|
};
|
|
602
607
|
const artifact = {
|
|
603
608
|
identity,
|
|
@@ -619,75 +624,80 @@ function resolveBoundContextTask(input) {
|
|
|
619
624
|
artifactHash: record.artifactHash,
|
|
620
625
|
createdAt: record.createdAt,
|
|
621
626
|
};
|
|
622
|
-
const queryPlan = {
|
|
623
|
-
identity,
|
|
624
|
-
sourceIntentHash: planRecord.sourceIntentHash,
|
|
625
|
-
planHash: planRecord.planHash,
|
|
626
|
-
code: planRecord.code,
|
|
627
|
-
memory: planRecord.memory,
|
|
628
|
-
knowledge: planRecord.knowledge,
|
|
629
|
-
generatedBy: planRecord.generatedBy,
|
|
630
|
-
...(planRecord.degradation ? { degradation: planRecord.degradation } : {}),
|
|
631
|
-
createdAt: planRecord.createdAt,
|
|
632
|
-
};
|
|
633
627
|
const query = stripArtifactCommand(artifact.normalizedPrompt, artifact.command);
|
|
634
628
|
const expandedTerms = [input.agentQuery, input.expandedTerms]
|
|
635
629
|
.filter((value) => typeof value === 'string' && value.trim().length > 0)
|
|
636
630
|
.join(' ')
|
|
637
631
|
.slice(0, 4_000) || undefined;
|
|
638
|
-
return { query, expandedTerms, requestId: record.requestId, turnId: record.turnId, intentArtifact: artifact
|
|
632
|
+
return { query, expandedTerms, requestId: record.requestId, turnId: record.turnId, intentArtifact: artifact };
|
|
639
633
|
}
|
|
640
634
|
finally {
|
|
641
635
|
database.close();
|
|
642
636
|
}
|
|
643
637
|
}
|
|
644
638
|
export async function resolveBoundContextTaskWithSemantics(input, engines, dependencies) {
|
|
645
|
-
const
|
|
646
|
-
const artifact =
|
|
639
|
+
const bound = resolveBoundContextTask(input);
|
|
640
|
+
const artifact = bound.intentArtifact;
|
|
647
641
|
if (!artifact)
|
|
648
|
-
return
|
|
649
|
-
const semanticMode = resolveSemanticResolutionMode(input.projectRoot);
|
|
650
|
-
if (semanticMode === 'off' || !engines.semanticRouter)
|
|
651
|
-
return legacy;
|
|
642
|
+
return bound;
|
|
652
643
|
const database = openGlobalDevFlowDatabase(undefined, { busyTimeoutMs: 250 });
|
|
653
644
|
try {
|
|
654
|
-
const
|
|
655
|
-
if (
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
const
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
return
|
|
645
|
+
const currentContext = database.getSemanticExecutionContext(artifact.identity.projectRoot, artifact.identity.sessionId, artifact.identity.turnId, artifact.version);
|
|
646
|
+
if (currentContext) {
|
|
647
|
+
const snapshot = database.getTaskAggregateSnapshot(artifact.identity.projectRoot, artifact.identity.sessionId, artifact.identity.turnId, artifact.version);
|
|
648
|
+
const definition = database.getTaskDefinitionV2(currentContext.taskDefinitionHash);
|
|
649
|
+
const activation = database.getRuntimeActivation(artifact.identity.projectRoot, artifact.identity.sessionId, artifact.identity.turnId, artifact.version);
|
|
650
|
+
if (snapshot && definition && activation
|
|
651
|
+
&& snapshot.semanticFactsHash === currentContext.facts.factsHash
|
|
652
|
+
&& snapshot.semanticContextHash === currentContext.contextHash
|
|
653
|
+
&& snapshot.channelPlanHash === currentContext.plan.planHash
|
|
654
|
+
&& snapshot.taskDefinitionHash === definition.definitionHash
|
|
655
|
+
&& snapshot.activationSnapshotHash === activation.snapshotHash
|
|
656
|
+
&& definition.semanticContextHash === currentContext.contextHash) {
|
|
657
|
+
return { ...bound, queryPlan: currentContext.plan };
|
|
667
658
|
}
|
|
668
|
-
return legacy;
|
|
669
|
-
}
|
|
670
|
-
let provisional;
|
|
671
|
-
try {
|
|
672
|
-
assertTaskSemanticFrameV2(latest.frame, artifact.normalizedPrompt);
|
|
673
|
-
provisional = latest.frame;
|
|
674
|
-
}
|
|
675
|
-
catch {
|
|
676
|
-
return legacy;
|
|
677
659
|
}
|
|
678
|
-
const
|
|
679
|
-
|
|
680
|
-
|
|
660
|
+
const activation = new ActivationSnapshotStore(database).get(artifact.identity, artifact.version);
|
|
661
|
+
if (!activation)
|
|
662
|
+
throw new Error(`RUNTIME_ACTIVATION_MISSING:${artifact.artifactHash}`);
|
|
663
|
+
const revision = artifact.version;
|
|
664
|
+
const resolvedContext = await resolveTaskSemanticContext({
|
|
665
|
+
normalizedPrompt: artifact.normalizedPrompt,
|
|
666
|
+
sourceHash: artifact.sourceHash,
|
|
667
|
+
identity: artifact.identity,
|
|
668
|
+
revision,
|
|
669
|
+
activation,
|
|
670
|
+
...(engines.semanticRouter ? { router: engines.semanticRouter } : {}),
|
|
671
|
+
...(dependencies.semanticSampling ? {
|
|
672
|
+
hostSampling: { sample: dependencies.semanticSampling },
|
|
673
|
+
} : {}),
|
|
674
|
+
...(dependencies.retrievalQuerySampling ? {
|
|
675
|
+
retrievalQuerySampling: { sample: dependencies.retrievalQuerySampling },
|
|
676
|
+
} : {}),
|
|
677
|
+
...(artifact.command ? { command: artifact.command } : {}),
|
|
681
678
|
targetAnchors: artifact.targetAnchors,
|
|
679
|
+
policy: {
|
|
680
|
+
policyHash: `policy:${activation.rolloutPolicyVersion}`,
|
|
681
|
+
activeSkill: artifact.activeSkill,
|
|
682
|
+
budgets: {
|
|
683
|
+
hookDeadlineMs: 3_000,
|
|
684
|
+
contextTokens: 8_000,
|
|
685
|
+
responseReserveTokens: 2_000,
|
|
686
|
+
perChannelMs: { code: 1_500, memory: 800, knowledge: 1_500 },
|
|
687
|
+
},
|
|
688
|
+
sourceEvidenceIds: artifact.sourceEventIds,
|
|
689
|
+
},
|
|
682
690
|
});
|
|
683
|
-
const
|
|
691
|
+
const finalResolution = resolvedContext.resolution;
|
|
692
|
+
const facts = finalResolution.facts;
|
|
693
|
+
const route = finalResolution.route;
|
|
684
694
|
emitSemanticControlLog({
|
|
685
695
|
event: 'semantic.route.scored',
|
|
686
696
|
identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
|
|
687
697
|
level: route.status === 'unavailable' ? 'warn' : 'info',
|
|
688
698
|
timestamp: Date.now(),
|
|
689
699
|
data: {
|
|
690
|
-
mode:
|
|
700
|
+
mode: activation.semantic,
|
|
691
701
|
status: route.status,
|
|
692
702
|
modelId: route.modelId,
|
|
693
703
|
modelRevision: route.modelRevision,
|
|
@@ -703,228 +713,95 @@ export async function resolveBoundContextTaskWithSemantics(input, engines, depen
|
|
|
703
713
|
identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
|
|
704
714
|
level: 'debug', timestamp: Date.now(),
|
|
705
715
|
data: {
|
|
706
|
-
mode:
|
|
707
|
-
thresholdVersion: route.thresholdVersion,
|
|
716
|
+
mode: activation.semantic, modelId: route.modelId, modelRevision: route.modelRevision,
|
|
717
|
+
thresholdVersion: route.thresholdVersion,
|
|
708
718
|
status: route.status, latencyMs: route.latencyMs,
|
|
709
719
|
},
|
|
710
720
|
});
|
|
711
|
-
|
|
712
|
-
if ((route.status === 'escalation_required' || hasCompositionalStructure(structural))
|
|
713
|
-
&& dependencies.semanticSampling) {
|
|
721
|
+
if (finalResolution.sampling.attempted) {
|
|
714
722
|
emitSemanticControlLog({
|
|
715
723
|
event: 'semantic.resolution.escalated', identity: artifact.identity, level: 'info', timestamp: Date.now(),
|
|
716
|
-
data: { mode:
|
|
717
|
-
|
|
718
|
-
sampled = await dependencies.semanticSampling({
|
|
719
|
-
normalizedPrompt: structural.normalizedPrompt,
|
|
720
|
-
sourceHash: artifact.sourceHash,
|
|
721
|
-
structural,
|
|
722
|
-
route,
|
|
723
|
-
provisionalFrame: provisional,
|
|
724
|
-
timeoutMs: 3_000,
|
|
724
|
+
data: { mode: activation.semantic, factsHash: facts.factsHash, reason: route.reason,
|
|
725
|
+
providerReceiptId: finalResolution.sampling.receiptId },
|
|
725
726
|
});
|
|
726
727
|
}
|
|
727
|
-
const
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
728
|
+
const semanticPlan = resolvedContext.context.plan;
|
|
729
|
+
const kernel = new TaskKernel(new TaskEventStore(database), new SemanticRuntimeEventProjector());
|
|
730
|
+
kernel.dispatch({
|
|
731
|
+
definition: resolvedContext.definition,
|
|
732
|
+
kind: 'activation_bound',
|
|
733
|
+
payload: { activationSnapshotHash: activation.snapshotHash },
|
|
734
|
+
idempotencyKey: `activation:${artifact.artifactHash}:${revision}`,
|
|
735
|
+
producer: 'mcp-semantic-adapter',
|
|
733
736
|
});
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
targetAnchors: finalResolution.frame.targetAnchors,
|
|
744
|
-
policyConstraints: finalResolution.frame.constraints,
|
|
745
|
-
classificationEvidence: finalResolution.frame.evidence.flatMap((evidence) => {
|
|
746
|
-
const field = evidence.field === 'negation' || evidence.field === 'condition'
|
|
747
|
-
? 'constraint'
|
|
748
|
-
: evidence.field;
|
|
749
|
-
if (field !== 'intent' && field !== 'action' && field !== 'entity'
|
|
750
|
-
&& field !== 'target' && field !== 'constraint')
|
|
751
|
-
return [];
|
|
752
|
-
const source = evidence.source === 'structural'
|
|
753
|
-
|| evidence.source === 'lexical_feature'
|
|
754
|
-
? 'deterministic_parser'
|
|
755
|
-
: evidence.source === 'host_sampling'
|
|
756
|
-
? 'host_semantic'
|
|
757
|
-
: evidence.source;
|
|
758
|
-
return [{
|
|
759
|
-
source,
|
|
760
|
-
field,
|
|
761
|
-
value: evidence.value,
|
|
762
|
-
reason: `semantic_frame:${finalResolution.frame.frameHash}`,
|
|
763
|
-
confidence: evidence.confidence,
|
|
764
|
-
}];
|
|
765
|
-
}),
|
|
766
|
-
createdAt: finalResolution.frame.createdAt,
|
|
767
|
-
};
|
|
768
|
-
const { artifactHash: _oldHash, ...unhashedArtifact } = revisedBody;
|
|
769
|
-
const revisedArtifact = {
|
|
770
|
-
...unhashedArtifact,
|
|
771
|
-
artifactHash: hashCanonical(unhashedArtifact),
|
|
772
|
-
};
|
|
773
|
-
const taskPlan = buildRetrievalTaskPlan({
|
|
774
|
-
query: legacy.query,
|
|
775
|
-
parsedIntent: parseIntent(legacy.query),
|
|
776
|
-
targetAnchors: revisedArtifact.targetAnchors,
|
|
777
|
-
activeSkill: revisedArtifact.activeSkill,
|
|
778
|
-
command: revisedArtifact.command,
|
|
779
|
-
authoritativeArtifact: revisedArtifact,
|
|
780
|
-
semanticFrame: finalResolution.frame,
|
|
737
|
+
kernel.dispatch({
|
|
738
|
+
definition: resolvedContext.definition,
|
|
739
|
+
kind: 'semantic_resolved',
|
|
740
|
+
payload: {
|
|
741
|
+
semanticFactsHash: facts.factsHash,
|
|
742
|
+
semanticContextHash: resolvedContext.context.contextHash,
|
|
743
|
+
},
|
|
744
|
+
idempotencyKey: `semantic:${artifact.artifactHash}:${revision}:${facts.factsHash}`,
|
|
745
|
+
producer: 'mcp-semantic-adapter',
|
|
781
746
|
});
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
747
|
+
kernel.dispatch({
|
|
748
|
+
definition: resolvedContext.definition,
|
|
749
|
+
kind: 'plan_compiled',
|
|
750
|
+
payload: { channelPlanHash: semanticPlan.planHash },
|
|
751
|
+
idempotencyKey: `plan:${artifact.artifactHash}:${revision}:${semanticPlan.planHash}`,
|
|
752
|
+
producer: 'mcp-semantic-adapter',
|
|
787
753
|
});
|
|
788
|
-
database.
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
sourceHash: artifact.sourceHash,
|
|
794
|
-
artifactHash: revisedArtifact.artifactHash,
|
|
795
|
-
artifactRevision: 2,
|
|
796
|
-
supersedesFrameHash: provisional.frameHash,
|
|
797
|
-
state: finalResolution.frame.state,
|
|
798
|
-
generatedBy: finalResolution.frame.resolver.generatedBy,
|
|
799
|
-
modelId: finalResolution.frame.resolver.modelId,
|
|
800
|
-
modelRevision: finalResolution.frame.resolver.modelRevision,
|
|
801
|
-
routeCatalogVersion: finalResolution.frame.resolver.routeCatalogVersion,
|
|
802
|
-
thresholdVersion: finalResolution.frame.resolver.thresholdVersion,
|
|
803
|
-
route: finalResolution.route,
|
|
804
|
-
sampling: finalResolution.sampling,
|
|
805
|
-
conflicts: finalResolution.conflicts,
|
|
806
|
-
frame: finalResolution.frame,
|
|
807
|
-
durationMs: Math.round(finalResolution.route.latencyMs + (finalResolution.sampling.latencyMs ?? 0)),
|
|
808
|
-
createdAt: finalResolution.frame.createdAt,
|
|
754
|
+
database.putCanonicalSemanticTask({
|
|
755
|
+
revision,
|
|
756
|
+
activation,
|
|
757
|
+
context: resolvedContext.context,
|
|
758
|
+
definition: resolvedContext.definition,
|
|
809
759
|
});
|
|
810
|
-
logSemanticResolution(artifact,
|
|
811
|
-
return
|
|
812
|
-
? legacy
|
|
813
|
-
: { ...legacy, intentArtifact: revisedArtifact, queryPlan: revisedPlan };
|
|
760
|
+
logSemanticResolution(artifact, resolvedContext.context.mode, finalResolution);
|
|
761
|
+
return { ...bound, queryPlan: semanticPlan };
|
|
814
762
|
}
|
|
815
763
|
finally {
|
|
816
764
|
database.close();
|
|
817
765
|
}
|
|
818
766
|
}
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
attempted: true,
|
|
837
|
-
status: sampled.status,
|
|
838
|
-
...(sampled.model ? { model: sampled.model } : {}),
|
|
839
|
-
latencyMs: sampled.latencyMs,
|
|
840
|
-
...(sampled.responseHash ? { responseHash: sampled.responseHash } : {}),
|
|
841
|
-
},
|
|
842
|
-
};
|
|
767
|
+
const semanticInitializationLocks = new Map();
|
|
768
|
+
async function ensureBoundContextTaskWithSemantics(input, engines, dependencies) {
|
|
769
|
+
if (!input.intentArtifactHash)
|
|
770
|
+
return resolveBoundContextTaskWithSemantics(input, engines, dependencies);
|
|
771
|
+
const key = `${input.projectRoot}\0${input.intentArtifactHash}`;
|
|
772
|
+
const pending = semanticInitializationLocks.get(key);
|
|
773
|
+
if (pending)
|
|
774
|
+
return pending;
|
|
775
|
+
const current = resolveBoundContextTaskWithSemantics(input, engines, dependencies);
|
|
776
|
+
semanticInitializationLocks.set(key, current);
|
|
777
|
+
try {
|
|
778
|
+
return await current;
|
|
779
|
+
}
|
|
780
|
+
finally {
|
|
781
|
+
if (semanticInitializationLocks.get(key) === current)
|
|
782
|
+
semanticInitializationLocks.delete(key);
|
|
783
|
+
}
|
|
843
784
|
}
|
|
844
|
-
function logSemanticResolution(artifact, mode, resolution
|
|
845
|
-
const event = resolution.
|
|
846
|
-
? 'semantic.resolution.completed'
|
|
847
|
-
: 'semantic.resolution.abstained';
|
|
785
|
+
function logSemanticResolution(artifact, mode, resolution) {
|
|
786
|
+
const event = resolution.facts.conflicts.length === 0
|
|
787
|
+
? 'semantic.resolution.completed' : 'semantic.resolution.abstained';
|
|
848
788
|
emitSemanticControlLog({
|
|
849
789
|
event, identity: { ...artifact.identity, intentArtifactHash: artifact.artifactHash },
|
|
850
|
-
level: resolution.
|
|
790
|
+
level: resolution.facts.conflicts.length === 0 ? 'info' : 'warn', timestamp: Date.now(),
|
|
851
791
|
data: {
|
|
852
|
-
mode,
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
792
|
+
mode, factsHash: resolution.facts.factsHash,
|
|
793
|
+
mutation: resolution.actionAuthority.mutation,
|
|
794
|
+
intents: resolution.facts.intents,
|
|
795
|
+
actions: resolution.facts.actions,
|
|
796
|
+
samplingStatus: resolution.sampling.status,
|
|
797
|
+
conflictCount: resolution.facts.conflicts.length,
|
|
856
798
|
},
|
|
857
799
|
});
|
|
858
|
-
if (resolution.conflicts.length > 0)
|
|
800
|
+
if (resolution.facts.conflicts.length > 0)
|
|
859
801
|
emitSemanticControlLog({
|
|
860
802
|
event: 'semantic.authority.conflicted', identity: artifact.identity, level: 'warn', timestamp: Date.now(),
|
|
861
|
-
data: {
|
|
803
|
+
data: { factsHash: resolution.facts.factsHash, conflicts: resolution.facts.conflicts },
|
|
862
804
|
});
|
|
863
|
-
if (projection.intent !== artifact.intent || projection.action !== artifact.action)
|
|
864
|
-
emitSemanticControlLog({
|
|
865
|
-
event: 'semantic.regex.shadow_mismatch', identity: artifact.identity, level: 'info', timestamp: Date.now(),
|
|
866
|
-
data: { mode, frameHash: resolution.frame.frameHash, legacyIntent: artifact.intent,
|
|
867
|
-
legacyAction: artifact.action, semanticIntent: projection.intent, semanticAction: projection.action },
|
|
868
|
-
});
|
|
869
|
-
}
|
|
870
|
-
function toTaskIntentRecord(artifact) {
|
|
871
|
-
return {
|
|
872
|
-
...artifact.identity, version: artifact.version, supersedesHash: artifact.supersedesHash,
|
|
873
|
-
rawPrompt: artifact.rawPrompt, normalizedPrompt: artifact.normalizedPrompt,
|
|
874
|
-
command: artifact.command, slashArgs: artifact.slashArgs, activeSkill: artifact.activeSkill,
|
|
875
|
-
intent: artifact.intent, action: artifact.action, entities: artifact.entities,
|
|
876
|
-
targetAnchors: artifact.targetAnchors, policyConstraints: artifact.policyConstraints,
|
|
877
|
-
classificationEvidence: artifact.classificationEvidence.map(item => ({ ...item })),
|
|
878
|
-
sourceEventIds: artifact.sourceEventIds, sourceHash: artifact.sourceHash,
|
|
879
|
-
artifactHash: artifact.artifactHash, createdAt: artifact.createdAt,
|
|
880
|
-
};
|
|
881
|
-
}
|
|
882
|
-
function toChannelQueryPlanRecord(plan) {
|
|
883
|
-
return {
|
|
884
|
-
...plan.identity, sourceIntentHash: plan.sourceIntentHash, planHash: plan.planHash,
|
|
885
|
-
code: plan.code.map(item => ({ ...item })), memory: plan.memory.map(item => ({ ...item })),
|
|
886
|
-
knowledge: plan.knowledge.map(item => ({ ...item })), generatedBy: plan.generatedBy,
|
|
887
|
-
...(plan.degradation ? { degradation: { ...plan.degradation } } : {}), createdAt: plan.createdAt,
|
|
888
|
-
};
|
|
889
|
-
}
|
|
890
|
-
function toSdkIntentArtifact(record) {
|
|
891
|
-
return {
|
|
892
|
-
identity: { projectRoot: record.projectRoot, projectId: record.projectId, hostId: record.hostId,
|
|
893
|
-
sessionId: record.sessionId, turnId: record.turnId, requestId: record.requestId,
|
|
894
|
-
...(record.executionId ? { executionId: record.executionId } : {}) },
|
|
895
|
-
version: record.version, ...(record.supersedesHash ? { supersedesHash: record.supersedesHash } : {}),
|
|
896
|
-
rawPrompt: record.rawPrompt, normalizedPrompt: record.normalizedPrompt,
|
|
897
|
-
...(record.command ? { command: record.command } : {}), slashArgs: record.slashArgs,
|
|
898
|
-
...(record.activeSkill ? { activeSkill: record.activeSkill } : {}), intent: record.intent,
|
|
899
|
-
action: record.action, entities: record.entities, targetAnchors: record.targetAnchors,
|
|
900
|
-
policyConstraints: record.policyConstraints, classificationEvidence: record.classificationEvidence,
|
|
901
|
-
sourceEventIds: record.sourceEventIds, sourceHash: record.sourceHash,
|
|
902
|
-
artifactHash: record.artifactHash, createdAt: record.createdAt,
|
|
903
|
-
};
|
|
904
|
-
}
|
|
905
|
-
function toSdkChannelQueryPlan(record) {
|
|
906
|
-
return { identity: { projectRoot: record.projectRoot, projectId: record.projectId, hostId: record.hostId,
|
|
907
|
-
sessionId: record.sessionId, turnId: record.turnId, requestId: record.requestId,
|
|
908
|
-
...(record.executionId ? { executionId: record.executionId } : {}) },
|
|
909
|
-
sourceIntentHash: record.sourceIntentHash, planHash: record.planHash, code: record.code,
|
|
910
|
-
memory: record.memory, knowledge: record.knowledge, generatedBy: record.generatedBy,
|
|
911
|
-
...(record.degradation ? { degradation: record.degradation } : {}), createdAt: record.createdAt };
|
|
912
|
-
}
|
|
913
|
-
function hashCanonical(value) {
|
|
914
|
-
return createHash('sha256').update(stableCanonicalJson(value)).digest('hex');
|
|
915
|
-
}
|
|
916
|
-
function stableCanonicalJson(value) {
|
|
917
|
-
if (value === null || typeof value === 'string' || typeof value === 'boolean')
|
|
918
|
-
return JSON.stringify(value);
|
|
919
|
-
if (typeof value === 'number')
|
|
920
|
-
return Number.isFinite(value) ? JSON.stringify(value) : 'null';
|
|
921
|
-
if (Array.isArray(value))
|
|
922
|
-
return `[${value.map(stableCanonicalJson).join(',')}]`;
|
|
923
|
-
if (!value || typeof value !== 'object')
|
|
924
|
-
return JSON.stringify(String(value));
|
|
925
|
-
const record = value;
|
|
926
|
-
return `{${Object.keys(record).sort().filter(key => record[key] !== undefined)
|
|
927
|
-
.map(key => `${JSON.stringify(key)}:${stableCanonicalJson(record[key])}`).join(',')}}`;
|
|
928
805
|
}
|
|
929
806
|
function stripArtifactCommand(prompt, command) {
|
|
930
807
|
if (!command)
|
|
@@ -935,9 +812,41 @@ function stripArtifactCommand(prompt, command) {
|
|
|
935
812
|
export function createToolHandlers(engines, boundProjectRoot, dependencies = {}) {
|
|
936
813
|
const hasBoundProjectRoot = typeof boundProjectRoot === 'string' && boundProjectRoot.trim().length > 0;
|
|
937
814
|
const canonicalProjectRoot = canonicalizeProjectRoot(String(boundProjectRoot ?? process.cwd()));
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
815
|
+
const taskEvidence = dependencies.taskEvidence ?? {
|
|
816
|
+
load: loadSemanticExecutionContext,
|
|
817
|
+
query: queryAuthoritativeTaskEvidence,
|
|
818
|
+
};
|
|
819
|
+
async function authoritativeEvidence(projection, runtime) {
|
|
820
|
+
const sessionId = typeof runtime.sessionId === 'string' ? runtime.sessionId : undefined;
|
|
821
|
+
const turnId = typeof runtime.turnId === 'string' ? runtime.turnId : undefined;
|
|
822
|
+
if (!sessionId || !turnId) {
|
|
823
|
+
return {
|
|
824
|
+
status: 'unavailable',
|
|
825
|
+
authority: 'authoritative_task',
|
|
826
|
+
reasonCode: 'task_identity_required',
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
const loaded = taskEvidence.load({ projectRoot: canonicalProjectRoot, sessionId, turnId });
|
|
830
|
+
if (!loaded) {
|
|
831
|
+
return {
|
|
832
|
+
status: 'unavailable',
|
|
833
|
+
authority: 'authoritative_task',
|
|
834
|
+
reasonCode: 'task_evidence_unavailable',
|
|
835
|
+
};
|
|
836
|
+
}
|
|
837
|
+
const result = await taskEvidence.query({
|
|
838
|
+
engines,
|
|
839
|
+
request: {
|
|
840
|
+
schemaVersion: 'authoritative-task-evidence-request.v1',
|
|
841
|
+
identity: loaded.context.identity,
|
|
842
|
+
taskRevision: loaded.definition.revision,
|
|
843
|
+
semanticContextHash: loaded.context.contextHash,
|
|
844
|
+
requestedProjection: projection,
|
|
845
|
+
},
|
|
846
|
+
...(dependencies.evidenceReranker ? { reranker: dependencies.evidenceReranker } : {}),
|
|
847
|
+
});
|
|
848
|
+
return result;
|
|
849
|
+
}
|
|
941
850
|
function getFreshnessMs() {
|
|
942
851
|
try {
|
|
943
852
|
const stats = engines.codegraph.getStats();
|
|
@@ -948,8 +857,8 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
948
857
|
}
|
|
949
858
|
}
|
|
950
859
|
const handlers = {
|
|
951
|
-
get_project_context: async ({ query, mode, expandedTerms, retrievalSessionId, baselineReceipt, missingContext, _devflow_session_id, _devflow_execution_id, _devflow_request_id, _devflow_turn_id, _devflow_intent_artifact_hash, _devflow_active_skill, activeSkill }) => {
|
|
952
|
-
const boundTask = await
|
|
860
|
+
get_project_context: async ({ query, budgetTokens, mode, expandedTerms, retrievalSessionId, baselineReceipt, missingContext, _devflow_session_id, _devflow_execution_id, _devflow_request_id, _devflow_turn_id, _devflow_intent_artifact_hash, _devflow_active_skill, activeSkill }) => {
|
|
861
|
+
const boundTask = await ensureBoundContextTaskWithSemantics({
|
|
953
862
|
projectRoot: canonicalProjectRoot,
|
|
954
863
|
sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : undefined,
|
|
955
864
|
requestId: typeof _devflow_request_id === 'string' ? _devflow_request_id : undefined,
|
|
@@ -958,26 +867,28 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
958
867
|
agentQuery: query,
|
|
959
868
|
expandedTerms: typeof expandedTerms === 'string' ? expandedTerms : undefined,
|
|
960
869
|
}, engines, dependencies);
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
baselineReceipt: typeof baselineReceipt === 'string' ? baselineReceipt : undefined,
|
|
967
|
-
missingContext: Array.isArray(missingContext) ? missingContext : undefined,
|
|
968
|
-
sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : process.env.DEVFLOW_SESSION_ID ?? undefined,
|
|
969
|
-
executionId: typeof _devflow_execution_id === 'string' ? _devflow_execution_id : undefined,
|
|
970
|
-
requestId: boundTask.requestId,
|
|
870
|
+
const sessionId = typeof _devflow_session_id === 'string'
|
|
871
|
+
? _devflow_session_id : process.env.DEVFLOW_SESSION_ID ?? undefined;
|
|
872
|
+
const semantic = loadSemanticExecutionContext({
|
|
873
|
+
projectRoot: canonicalProjectRoot,
|
|
874
|
+
sessionId,
|
|
971
875
|
turnId: boundTask.turnId,
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
:
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
876
|
+
});
|
|
877
|
+
if (semantic) {
|
|
878
|
+
return retrieveProjectEvidence({
|
|
879
|
+
engines,
|
|
880
|
+
context: semantic.context,
|
|
881
|
+
definition: semantic.definition,
|
|
882
|
+
...(typeof budgetTokens === 'number' ? { tokenBudget: budgetTokens } : {}),
|
|
883
|
+
query: boundTask.query,
|
|
884
|
+
...(dependencies.evidenceReranker ? { reranker: dependencies.evidenceReranker } : {}),
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return {
|
|
888
|
+
status: 'unavailable',
|
|
889
|
+
authority: 'authoritative_task',
|
|
890
|
+
reasonCode: 'semantic_execution_context_unavailable',
|
|
891
|
+
};
|
|
981
892
|
},
|
|
982
893
|
search_symbol: async ({ symbol }) => {
|
|
983
894
|
const result = await engines.indexer.findSymbol(symbol);
|
|
@@ -1018,7 +929,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1018
929
|
_accuracy: {
|
|
1019
930
|
data_freshness_ms: getFreshnessMs(),
|
|
1020
931
|
source_layer: "codegraph",
|
|
1021
|
-
|
|
932
|
+
execution_status: "unavailable",
|
|
1022
933
|
},
|
|
1023
934
|
seeds: [t],
|
|
1024
935
|
depth: d,
|
|
@@ -1038,7 +949,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1038
949
|
_accuracy: {
|
|
1039
950
|
data_freshness_ms: getFreshnessMs(),
|
|
1040
951
|
source_layer: "codegraph",
|
|
1041
|
-
|
|
952
|
+
execution_status: result.edges.length === 0 && result.nodes.length > 0 ? "unavailable" : "executed",
|
|
1042
953
|
},
|
|
1043
954
|
};
|
|
1044
955
|
},
|
|
@@ -1126,7 +1037,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1126
1037
|
},
|
|
1127
1038
|
};
|
|
1128
1039
|
},
|
|
1129
|
-
devflow_report_step: async ({ runId, stepId, status, output, duration,
|
|
1040
|
+
devflow_report_step: async ({ runId, stepId, status, output, duration, changedFiles, verification, _devflow_session_id, _devflow_execution_id, _devflow_tool_use_id, }) => {
|
|
1130
1041
|
const canonicalRunId = String(runId ?? '').trim();
|
|
1131
1042
|
const canonicalStepId = String(stepId ?? '').trim();
|
|
1132
1043
|
if (!canonicalRunId || !canonicalStepId) {
|
|
@@ -1185,29 +1096,30 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1185
1096
|
if (!hostRun || !hostStep) {
|
|
1186
1097
|
return rejectedToolResult('WORKFLOW_ENGINE_MAPPING_MISSING', 'The workflow engine run mapping is unavailable.', false);
|
|
1187
1098
|
}
|
|
1188
|
-
const canonicalExecutionId = typeof executionId === 'string'
|
|
1189
|
-
? executionId.trim()
|
|
1190
|
-
: typeof _devflow_execution_id === 'string' ? _devflow_execution_id.trim() : '';
|
|
1191
|
-
const canonicalReceipt = typeof contextReceipt === 'string' ? contextReceipt.trim() : '';
|
|
1192
1099
|
const sessionId = typeof _devflow_session_id === 'string' ? _devflow_session_id.trim() : '';
|
|
1193
|
-
const
|
|
1194
|
-
?
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1100
|
+
const canonicalExecutionId = typeof _devflow_execution_id === 'string'
|
|
1101
|
+
? _devflow_execution_id.trim() : '';
|
|
1102
|
+
const canonicalToolUseId = typeof _devflow_tool_use_id === 'string'
|
|
1103
|
+
? _devflow_tool_use_id.trim() : '';
|
|
1104
|
+
if (!sessionId || !canonicalExecutionId || !canonicalToolUseId) {
|
|
1105
|
+
return rejectedToolResult('WORKFLOW_IDENTITY_MISSING', 'Canonical session, execution, and tool-use identity are required.', false);
|
|
1106
|
+
}
|
|
1107
|
+
if (sessionId !== action.sessionId || canonicalExecutionId !== action.executionId) {
|
|
1108
|
+
return rejectedToolResult('WORKFLOW_ACTION_IDENTITY_MISMATCH', 'The canonical report identity does not match the host action.', false);
|
|
1198
1109
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1110
|
+
const activeReceipt = database.getActiveContextReceipt(canonicalProjectRoot, sessionId, canonicalExecutionId);
|
|
1111
|
+
if (!activeReceipt || activeReceipt.contextHash !== action.contextReceipt) {
|
|
1112
|
+
return rejectedToolResult('STALE_CONTEXT_RECEIPT', 'The host action is not bound to the active context receipt.', true);
|
|
1201
1113
|
}
|
|
1202
1114
|
const files = sanitizeChangedFiles(canonicalProjectRoot, changedFiles);
|
|
1203
|
-
const tools =
|
|
1115
|
+
const tools = [canonicalToolUseId];
|
|
1204
1116
|
const verificationRecord = verification && typeof verification === 'object' && !Array.isArray(verification)
|
|
1205
1117
|
? verification
|
|
1206
1118
|
: undefined;
|
|
1207
1119
|
const report = {
|
|
1208
1120
|
status: requestedStatus,
|
|
1209
1121
|
summary: typeof output === 'string' ? output.trim().slice(0, 4000) : '',
|
|
1210
|
-
contextReceipt:
|
|
1122
|
+
contextReceipt: activeReceipt.contextHash,
|
|
1211
1123
|
executionId: canonicalExecutionId,
|
|
1212
1124
|
toolUseIds: tools.sort(),
|
|
1213
1125
|
changedFiles: files.sort(),
|
|
@@ -1223,6 +1135,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1223
1135
|
};
|
|
1224
1136
|
const evidenceHash = workflowEvidenceHash(report);
|
|
1225
1137
|
let terminal;
|
|
1138
|
+
let retrievalProof;
|
|
1226
1139
|
if (requestedStatus === 'failed') {
|
|
1227
1140
|
terminal = database.failHostAction({
|
|
1228
1141
|
actionId: action.actionId,
|
|
@@ -1283,6 +1196,17 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1283
1196
|
report,
|
|
1284
1197
|
evidenceHash,
|
|
1285
1198
|
});
|
|
1199
|
+
if (actionKind === 'verify') {
|
|
1200
|
+
retrievalProof = database.verifyReceiptBoundRetrieval({
|
|
1201
|
+
projectRoot: canonicalProjectRoot,
|
|
1202
|
+
sessionId,
|
|
1203
|
+
executionId: canonicalExecutionId,
|
|
1204
|
+
contextReceipt: activeReceipt.contextHash,
|
|
1205
|
+
toolUseId: canonicalToolUseId,
|
|
1206
|
+
verificationReceipt: evidenceHash,
|
|
1207
|
+
verifiedAt: finishedAt,
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1286
1210
|
}
|
|
1287
1211
|
let telemetryDegraded = false;
|
|
1288
1212
|
try {
|
|
@@ -1295,7 +1219,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1295
1219
|
return {
|
|
1296
1220
|
ok: true,
|
|
1297
1221
|
acknowledged: true,
|
|
1298
|
-
status:
|
|
1222
|
+
status: 'accepted',
|
|
1299
1223
|
runId: canonicalRunId,
|
|
1300
1224
|
stepId: canonicalStepId,
|
|
1301
1225
|
receipt: {
|
|
@@ -1303,8 +1227,11 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1303
1227
|
evidenceHash,
|
|
1304
1228
|
stepState: terminal.state,
|
|
1305
1229
|
runState: resumed.metadata?.canonicalStatus,
|
|
1230
|
+
...(retrievalProof ? { retrievalProof } : {}),
|
|
1306
1231
|
},
|
|
1307
|
-
...(telemetryDegraded ? {
|
|
1232
|
+
...(telemetryDegraded ? { warnings: [{
|
|
1233
|
+
code: 'TELEMETRY_WRITE_FAILED', message: 'Host action was accepted but telemetry persistence failed.',
|
|
1234
|
+
}] } : {}),
|
|
1308
1235
|
};
|
|
1309
1236
|
}
|
|
1310
1237
|
catch (error) {
|
|
@@ -1329,15 +1256,29 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1329
1256
|
steps: run.steps.map(step => ({ ...step, stepId: step.stepId ?? step.name })),
|
|
1330
1257
|
};
|
|
1331
1258
|
},
|
|
1332
|
-
get_memory: async ({ query, purpose, budgetTokens, scopes, _devflow_session_id, _devflow_execution_id, _devflow_request_id }) =>
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1259
|
+
get_memory: async ({ query, purpose, budgetTokens, scopes, _devflow_session_id, _devflow_execution_id, _devflow_request_id, _devflow_turn_id, _devflow_intent_artifact_hash }) => {
|
|
1260
|
+
await ensureBoundContextTaskWithSemantics({
|
|
1261
|
+
projectRoot: canonicalProjectRoot,
|
|
1262
|
+
sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : undefined,
|
|
1263
|
+
requestId: typeof _devflow_request_id === 'string' ? _devflow_request_id : undefined,
|
|
1264
|
+
turnId: typeof _devflow_turn_id === 'string' ? _devflow_turn_id : undefined,
|
|
1265
|
+
intentArtifactHash: typeof _devflow_intent_artifact_hash === 'string' ? _devflow_intent_artifact_hash : undefined,
|
|
1266
|
+
agentQuery: typeof query === 'string' ? query : '',
|
|
1267
|
+
}, engines, dependencies);
|
|
1268
|
+
const authoritative = await authoritativeEvidence('memory', {
|
|
1269
|
+
sessionId: _devflow_session_id,
|
|
1270
|
+
executionId: _devflow_execution_id,
|
|
1271
|
+
requestId: _devflow_request_id,
|
|
1272
|
+
turnId: _devflow_turn_id,
|
|
1273
|
+
});
|
|
1274
|
+
if (authoritative.status === 'unavailable')
|
|
1275
|
+
return authoritative;
|
|
1276
|
+
const [project, user] = await Promise.all([
|
|
1277
|
+
engines.memory.getProjectContext(),
|
|
1278
|
+
engines.memory.getUserPreferences(),
|
|
1279
|
+
]);
|
|
1280
|
+
return projectTaskMemoryResult(authoritative.receipt, { project, user });
|
|
1281
|
+
},
|
|
1341
1282
|
memory_request_distill: async ({ sessionId, batchId, page, pageSize }) => {
|
|
1342
1283
|
const memory = engines.memory;
|
|
1343
1284
|
const requestedPage = typeof page === "number" && Number.isFinite(page) ? page : 0;
|
|
@@ -1402,7 +1343,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1402
1343
|
const memory = engines.memory;
|
|
1403
1344
|
if (pending.status === 'pending' && recovery?.operation === 'commit_explicit' && recovery.explicitContent?.trim()) {
|
|
1404
1345
|
await ensureMemoryTurnEvent(memory, pending, recovery);
|
|
1405
|
-
const saved = await memory.saveExplicitMemoryIntent(recovery.explicitContent.trim(), sessionId, pending.eventId);
|
|
1346
|
+
const saved = await memory.saveExplicitMemoryIntent(recovery.explicitContent.trim(), { actorId: 'actor:mcp-host', sessionId }, pending.eventId);
|
|
1406
1347
|
const recoveredMemoryIds = [...new Set([saved.id, ...(saved.relatedMemoryIds ?? [])])];
|
|
1407
1348
|
const receipt = commitMemoryReceipt(database, pending, recoveredMemoryIds, 'explicit_intent', 'explicit_user_request_mcp_recovery');
|
|
1408
1349
|
if (memory.finalizeTurnDecision && receipt.receiptId) {
|
|
@@ -1467,13 +1408,13 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1467
1408
|
if (explicitRefinement) {
|
|
1468
1409
|
return {
|
|
1469
1410
|
...replayMemoryDecision(pending),
|
|
1470
|
-
status: '
|
|
1411
|
+
status: 'accepted',
|
|
1471
1412
|
replayed: false,
|
|
1472
1413
|
refined: false,
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1414
|
+
warnings: [{
|
|
1415
|
+
code: 'INVALID_HOST_REFINEMENT_CANDIDATES',
|
|
1416
|
+
message: 'The explicit memory remains committed; host refinement candidates were rejected.',
|
|
1417
|
+
}],
|
|
1477
1418
|
rejectedCandidates: validation.rejected,
|
|
1478
1419
|
};
|
|
1479
1420
|
}
|
|
@@ -1500,18 +1441,20 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1500
1441
|
sourceEventIds: candidate.sourceEventIds,
|
|
1501
1442
|
evidenceSpans: candidate.evidenceSpans,
|
|
1502
1443
|
disposition: candidate.disposition,
|
|
1444
|
+
operation: candidate.operation,
|
|
1445
|
+
referencedFactIds: candidate.referencedFactIds,
|
|
1503
1446
|
}));
|
|
1504
1447
|
await ensureMemoryTurnEvent(memory, pending, recovery);
|
|
1505
1448
|
if (explicitRefinement) {
|
|
1506
1449
|
if (!memory.refineExplicitTurnObservations) {
|
|
1507
1450
|
return {
|
|
1508
1451
|
...replayMemoryDecision(pending),
|
|
1509
|
-
status: '
|
|
1452
|
+
status: 'accepted',
|
|
1510
1453
|
replayed: false,
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1454
|
+
warnings: [{
|
|
1455
|
+
code: 'EXPLICIT_REFINEMENT_UNAVAILABLE',
|
|
1456
|
+
message: 'The explicit memory remains committed; host refinement is unavailable.',
|
|
1457
|
+
}],
|
|
1515
1458
|
};
|
|
1516
1459
|
}
|
|
1517
1460
|
try {
|
|
@@ -1570,7 +1513,7 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1570
1513
|
refinedMemoryIds,
|
|
1571
1514
|
retiredMemoryIds: refined.retiredMemoryIds,
|
|
1572
1515
|
operations: refined.operations,
|
|
1573
|
-
|
|
1516
|
+
explicitReceiptPreserved: true,
|
|
1574
1517
|
},
|
|
1575
1518
|
};
|
|
1576
1519
|
}
|
|
@@ -1583,22 +1526,22 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1583
1526
|
metadata: {
|
|
1584
1527
|
projectRoot: String(projectRoot), sessionId, turnId: pending.turnId,
|
|
1585
1528
|
receiptId: pending.receiptId, reason,
|
|
1586
|
-
|
|
1529
|
+
warningCode: 'EXPLICIT_REFINEMENT_FAILED',
|
|
1587
1530
|
},
|
|
1588
1531
|
});
|
|
1589
1532
|
emitSemanticControlLog({
|
|
1590
|
-
event: 'memory.write.
|
|
1533
|
+
event: 'memory.write.completed',
|
|
1591
1534
|
identity: { projectRoot: String(projectRoot), sessionId, turnId: pending.turnId },
|
|
1592
1535
|
level: 'warn',
|
|
1593
1536
|
timestamp: Date.now(),
|
|
1594
|
-
data: { stage: 'explicit_host_refinement', reason,
|
|
1537
|
+
data: { stage: 'explicit_host_refinement', reason, warningCode: 'EXPLICIT_REFINEMENT_FAILED' },
|
|
1595
1538
|
});
|
|
1596
1539
|
return {
|
|
1597
1540
|
...replayMemoryDecision(pending),
|
|
1598
|
-
status: '
|
|
1541
|
+
status: 'accepted',
|
|
1599
1542
|
replayed: false,
|
|
1600
1543
|
refined: false,
|
|
1601
|
-
|
|
1544
|
+
warnings: [{ code: 'EXPLICIT_REFINEMENT_FAILED', message: reason }],
|
|
1602
1545
|
};
|
|
1603
1546
|
}
|
|
1604
1547
|
}
|
|
@@ -1806,10 +1749,13 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1806
1749
|
}
|
|
1807
1750
|
catch (error) {
|
|
1808
1751
|
emitSemanticControlLog({
|
|
1809
|
-
event: 'memory.write.
|
|
1752
|
+
event: 'memory.write.completed',
|
|
1810
1753
|
identity: { projectRoot: canonicalProjectRoot, sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : undefined },
|
|
1811
1754
|
level: 'warn', timestamp: Date.now(),
|
|
1812
|
-
data: {
|
|
1755
|
+
data: {
|
|
1756
|
+
stage: 'distill_vector_enqueue', batchId, reason: error.message,
|
|
1757
|
+
warningCode: 'VECTOR_BACKFILL_ENQUEUE_FAILED',
|
|
1758
|
+
},
|
|
1813
1759
|
});
|
|
1814
1760
|
}
|
|
1815
1761
|
finally {
|
|
@@ -1832,11 +1778,25 @@ export function createToolHandlers(engines, boundProjectRoot, dependencies = {})
|
|
|
1832
1778
|
},
|
|
1833
1779
|
};
|
|
1834
1780
|
},
|
|
1835
|
-
get_knowledge: async ({ query, scope, budgetTokens }) =>
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1781
|
+
get_knowledge: async ({ query, scope, budgetTokens, _devflow_session_id, _devflow_execution_id, _devflow_request_id, _devflow_turn_id, _devflow_intent_artifact_hash }) => {
|
|
1782
|
+
await ensureBoundContextTaskWithSemantics({
|
|
1783
|
+
projectRoot: canonicalProjectRoot,
|
|
1784
|
+
sessionId: typeof _devflow_session_id === 'string' ? _devflow_session_id : undefined,
|
|
1785
|
+
requestId: typeof _devflow_request_id === 'string' ? _devflow_request_id : undefined,
|
|
1786
|
+
turnId: typeof _devflow_turn_id === 'string' ? _devflow_turn_id : undefined,
|
|
1787
|
+
intentArtifactHash: typeof _devflow_intent_artifact_hash === 'string' ? _devflow_intent_artifact_hash : undefined,
|
|
1788
|
+
agentQuery: typeof query === 'string' ? query : '',
|
|
1789
|
+
}, engines, dependencies);
|
|
1790
|
+
const authoritative = await authoritativeEvidence('knowledge', {
|
|
1791
|
+
sessionId: _devflow_session_id,
|
|
1792
|
+
executionId: _devflow_execution_id,
|
|
1793
|
+
requestId: _devflow_request_id,
|
|
1794
|
+
turnId: _devflow_turn_id,
|
|
1795
|
+
});
|
|
1796
|
+
if (authoritative.status === 'unavailable')
|
|
1797
|
+
return authoritative;
|
|
1798
|
+
return projectTaskKnowledgeResult(authoritative.receipt);
|
|
1799
|
+
},
|
|
1840
1800
|
devflow_report_event: async (args) => {
|
|
1841
1801
|
const truncate = (s, max) => {
|
|
1842
1802
|
if (!s || s.length <= max)
|