@mxf-dev/core 1.0.1 → 2.0.1
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 +18 -0
- package/dist/adapters/FrameworkAdapter.js +1 -1
- package/dist/adapters/FrameworkAdapter.js.map +1 -1
- package/dist/config/ConfigManager.d.ts +9 -8
- package/dist/config/ConfigManager.d.ts.map +1 -1
- package/dist/config/ConfigManager.js +47 -17
- package/dist/config/ConfigManager.js.map +1 -1
- package/dist/config/memory-strata.config.d.ts +25 -0
- package/dist/config/memory-strata.config.d.ts.map +1 -0
- package/dist/config/memory-strata.config.js +107 -0
- package/dist/config/memory-strata.config.js.map +1 -0
- package/dist/constants/ToolNames.d.ts +1 -29
- package/dist/constants/ToolNames.d.ts.map +1 -1
- package/dist/constants/ToolNames.js +4 -17
- package/dist/constants/ToolNames.js.map +1 -1
- package/dist/database/DatabaseAdapterFactory.d.ts +14 -2
- package/dist/database/DatabaseAdapterFactory.d.ts.map +1 -1
- package/dist/database/DatabaseAdapterFactory.js +21 -6
- package/dist/database/DatabaseAdapterFactory.js.map +1 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts +7 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.d.ts.map +1 -1
- package/dist/database/adapters/mongodb/MongoBaseRepository.js +12 -2
- package/dist/database/adapters/mongodb/MongoBaseRepository.js.map +1 -1
- package/dist/events/ClientEventBus.d.ts +16 -77
- package/dist/events/ClientEventBus.d.ts.map +1 -1
- package/dist/events/ClientEventBus.js +38 -311
- package/dist/events/ClientEventBus.js.map +1 -1
- package/dist/events/EventBus.d.ts +1 -1
- package/dist/events/EventBus.d.ts.map +1 -1
- package/dist/events/EventBus.js +5 -4
- package/dist/events/EventBus.js.map +1 -1
- package/dist/events/EventBusBase.d.ts +139 -34
- package/dist/events/EventBusBase.d.ts.map +1 -1
- package/dist/events/EventBusBase.js +366 -88
- package/dist/events/EventBusBase.js.map +1 -1
- package/dist/events/EventNames.d.ts +10 -1
- package/dist/events/EventNames.d.ts.map +1 -1
- package/dist/events/EventNames.js +3 -0
- package/dist/events/EventNames.js.map +1 -1
- package/dist/events/PublicEvents.d.ts +6 -2
- package/dist/events/PublicEvents.d.ts.map +1 -1
- package/dist/events/PublicEvents.js +7 -4
- package/dist/events/PublicEvents.js.map +1 -1
- package/dist/events/ServerEventBus.d.ts +23 -112
- package/dist/events/ServerEventBus.d.ts.map +1 -1
- package/dist/events/ServerEventBus.js +58 -323
- package/dist/events/ServerEventBus.js.map +1 -1
- package/dist/events/event-definitions/LlmBudgetEvents.d.ts +68 -0
- package/dist/events/event-definitions/LlmBudgetEvents.d.ts.map +1 -0
- package/dist/events/event-definitions/LlmBudgetEvents.js +35 -0
- package/dist/events/event-definitions/LlmBudgetEvents.js.map +1 -0
- package/dist/interfaces/IMemoryPersistence.d.ts +41 -0
- package/dist/interfaces/IMemoryPersistence.d.ts.map +1 -0
- package/dist/interfaces/IMemoryPersistence.js +15 -0
- package/dist/interfaces/IMemoryPersistence.js.map +1 -0
- package/dist/middleware/MxpMiddleware.d.ts +8 -1
- package/dist/middleware/MxpMiddleware.d.ts.map +1 -1
- package/dist/middleware/MxpMiddleware.js +42 -20
- package/dist/middleware/MxpMiddleware.js.map +1 -1
- package/dist/models/channelKey.d.ts +1 -0
- package/dist/models/channelKey.d.ts.map +1 -1
- package/dist/models/channelKey.js +5 -0
- package/dist/models/channelKey.js.map +1 -1
- package/dist/models/memoryUtility.d.ts +39 -0
- package/dist/models/memoryUtility.d.ts.map +1 -0
- package/dist/models/memoryUtility.js +39 -0
- package/dist/models/memoryUtility.js.map +1 -0
- package/dist/models/user.d.ts.map +1 -1
- package/dist/models/user.js +23 -1
- package/dist/models/user.js.map +1 -1
- package/dist/mxp/BinaryProtocolLayer.d.ts +24 -8
- package/dist/mxp/BinaryProtocolLayer.d.ts.map +1 -1
- package/dist/mxp/BinaryProtocolLayer.js +90 -103
- package/dist/mxp/BinaryProtocolLayer.js.map +1 -1
- package/dist/mxp/ContextCompressionEngine.d.ts +57 -10
- package/dist/mxp/ContextCompressionEngine.d.ts.map +1 -1
- package/dist/mxp/ContextCompressionEngine.js +170 -128
- package/dist/mxp/ContextCompressionEngine.js.map +1 -1
- package/dist/mxp/MxpTokenOptimizer.d.ts +7 -3
- package/dist/mxp/MxpTokenOptimizer.d.ts.map +1 -1
- package/dist/mxp/MxpTokenOptimizer.js +8 -5
- package/dist/mxp/MxpTokenOptimizer.js.map +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.d.ts +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.d.ts.map +1 -1
- package/dist/prompts/MxfAgentSystemPrompt.js +47 -57
- package/dist/prompts/MxfAgentSystemPrompt.js.map +1 -1
- package/dist/protocols/mcp/ToolError.d.ts +123 -0
- package/dist/protocols/mcp/ToolError.d.ts.map +1 -0
- package/dist/protocols/mcp/ToolError.js +108 -0
- package/dist/protocols/mcp/ToolError.js.map +1 -0
- package/dist/protocols/mcp/defineTool.d.ts +133 -0
- package/dist/protocols/mcp/defineTool.d.ts.map +1 -0
- package/dist/protocols/mcp/defineTool.js +236 -0
- package/dist/protocols/mcp/defineTool.js.map +1 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.d.ts +38 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.d.ts.map +1 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.js +227 -0
- package/dist/protocols/mcp/security/HttpTargetGuard.js.map +1 -0
- package/dist/protocols/mcp/security/McpSecurityGuard.d.ts +9 -1
- package/dist/protocols/mcp/security/McpSecurityGuard.d.ts.map +1 -1
- package/dist/protocols/mcp/security/McpSecurityGuard.js +10 -2
- package/dist/protocols/mcp/security/McpSecurityGuard.js.map +1 -1
- package/dist/protocols/mcp/security/McpToolPolicy.d.ts +81 -0
- package/dist/protocols/mcp/security/McpToolPolicy.d.ts.map +1 -0
- package/dist/protocols/mcp/security/McpToolPolicy.js +202 -0
- package/dist/protocols/mcp/security/McpToolPolicy.js.map +1 -0
- package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts +51 -18
- package/dist/protocols/mcp/services/ExternalMcpServerManager.d.ts.map +1 -1
- package/dist/protocols/mcp/services/ExternalMcpServerManager.js +256 -283
- package/dist/protocols/mcp/services/ExternalMcpServerManager.js.map +1 -1
- package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts +39 -6
- package/dist/protocols/mcp/services/ExternalServerConfigs.d.ts.map +1 -1
- package/dist/protocols/mcp/services/ExternalServerConfigs.js +76 -18
- package/dist/protocols/mcp/services/ExternalServerConfigs.js.map +1 -1
- package/dist/protocols/mcp/tools/AnalyticsTools.js +1 -1
- package/dist/protocols/mcp/tools/AnalyticsTools.js.map +1 -1
- package/dist/protocols/mcp/tools/CodeAnalysisTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/CodeAnalysisTools.js +15 -0
- package/dist/protocols/mcp/tools/CodeAnalysisTools.js.map +1 -1
- package/dist/protocols/mcp/tools/EffectivenessTools.js +3 -3
- package/dist/protocols/mcp/tools/EffectivenessTools.js.map +1 -1
- package/dist/protocols/mcp/tools/GitTools.d.ts +9 -369
- package/dist/protocols/mcp/tools/GitTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/GitTools.js +222 -517
- package/dist/protocols/mcp/tools/GitTools.js.map +1 -1
- package/dist/protocols/mcp/tools/InfrastructureTools.d.ts +56 -24
- package/dist/protocols/mcp/tools/InfrastructureTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/InfrastructureTools.js +117 -26
- package/dist/protocols/mcp/tools/InfrastructureTools.js.map +1 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.d.ts +0 -3
- package/dist/protocols/mcp/tools/MemorySearchTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.js +58 -1
- package/dist/protocols/mcp/tools/MemorySearchTools.js.map +1 -1
- package/dist/protocols/mcp/tools/OrparTools.d.ts +8 -0
- package/dist/protocols/mcp/tools/OrparTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/OrparTools.js +66 -0
- package/dist/protocols/mcp/tools/OrparTools.js.map +1 -1
- package/dist/protocols/mcp/tools/SafetyTools.d.ts +7 -525
- package/dist/protocols/mcp/tools/SafetyTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/SafetyTools.js +349 -514
- package/dist/protocols/mcp/tools/SafetyTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TaskPlanningTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TaskPlanningTools.js +56 -26
- package/dist/protocols/mcp/tools/TaskPlanningTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TestTools.d.ts +15 -376
- package/dist/protocols/mcp/tools/TestTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TestTools.js +241 -363
- package/dist/protocols/mcp/tools/TestTools.js.map +1 -1
- package/dist/protocols/mcp/tools/TypeScriptTools.d.ts +6 -276
- package/dist/protocols/mcp/tools/TypeScriptTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/TypeScriptTools.js +223 -337
- package/dist/protocols/mcp/tools/TypeScriptTools.js.map +1 -1
- package/dist/protocols/mcp/tools/WebTools.d.ts +15 -728
- package/dist/protocols/mcp/tools/WebTools.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/WebTools.js +151 -257
- package/dist/protocols/mcp/tools/WebTools.js.map +1 -1
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts +5 -3
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.d.ts.map +1 -1
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js +31 -6
- package/dist/protocols/mcp/tools/shell/ShellExecuteHandler.js.map +1 -1
- package/dist/schemas/EventPayloadSchema.d.ts +21 -0
- package/dist/schemas/EventPayloadSchema.d.ts.map +1 -1
- package/dist/schemas/EventPayloadSchema.js +14 -0
- package/dist/schemas/EventPayloadSchema.js.map +1 -1
- package/dist/services/BackgroundTaskManager.d.ts.map +1 -1
- package/dist/services/BackgroundTaskManager.js +12 -4
- package/dist/services/BackgroundTaskManager.js.map +1 -1
- package/dist/services/BrowserManager.d.ts +1 -1
- package/dist/services/BrowserManager.d.ts.map +1 -1
- package/dist/services/BrowserManager.js +26 -3
- package/dist/services/BrowserManager.js.map +1 -1
- package/dist/services/MemoryCompressor.d.ts +11 -2
- package/dist/services/MemoryCompressor.d.ts.map +1 -1
- package/dist/services/MemoryCompressor.js +8 -26
- package/dist/services/MemoryCompressor.js.map +1 -1
- package/dist/services/MemoryService.d.ts +16 -3
- package/dist/services/MemoryService.d.ts.map +1 -1
- package/dist/services/MemoryService.js +79 -55
- package/dist/services/MemoryService.js.map +1 -1
- package/dist/services/MxfMLService.d.ts +5 -0
- package/dist/services/MxfMLService.d.ts.map +1 -1
- package/dist/services/MxfMLService.js +32 -6
- package/dist/services/MxfMLService.js.map +1 -1
- package/dist/services/PredictiveAnalyticsService.d.ts +45 -9
- package/dist/services/PredictiveAnalyticsService.d.ts.map +1 -1
- package/dist/services/PredictiveAnalyticsService.js +82 -44
- package/dist/services/PredictiveAnalyticsService.js.map +1 -1
- package/dist/services/QValueManager.d.ts +7 -0
- package/dist/services/QValueManager.d.ts.map +1 -1
- package/dist/services/QValueManager.js +9 -0
- package/dist/services/QValueManager.js.map +1 -1
- package/dist/services/RewardSignalProcessor.d.ts +38 -1
- package/dist/services/RewardSignalProcessor.d.ts.map +1 -1
- package/dist/services/RewardSignalProcessor.js +109 -7
- package/dist/services/RewardSignalProcessor.js.map +1 -1
- package/dist/services/SharedStateService.d.ts +16 -2
- package/dist/services/SharedStateService.d.ts.map +1 -1
- package/dist/services/SharedStateService.js +44 -3
- package/dist/services/SharedStateService.js.map +1 -1
- package/dist/services/TaskEffectivenessService.d.ts +34 -18
- package/dist/services/TaskEffectivenessService.d.ts.map +1 -1
- package/dist/services/TaskEffectivenessService.js +91 -155
- package/dist/services/TaskEffectivenessService.js.map +1 -1
- package/dist/services/WebSearchService.d.ts.map +1 -1
- package/dist/services/WebSearchService.js.map +1 -1
- package/dist/services/dag/TaskDagService.d.ts.map +1 -1
- package/dist/services/dag/TaskDagService.js +2 -0
- package/dist/services/dag/TaskDagService.js.map +1 -1
- package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts +7 -0
- package/dist/services/orpar-memory/OrparMemoryCoordinator.d.ts.map +1 -1
- package/dist/services/orpar-memory/OrparMemoryCoordinator.js +71 -10
- package/dist/services/orpar-memory/OrparMemoryCoordinator.js.map +1 -1
- package/dist/types/MemoryUtilityTypes.d.ts +2 -0
- package/dist/types/MemoryUtilityTypes.d.ts.map +1 -1
- package/dist/types/MemoryUtilityTypes.js.map +1 -1
- package/dist/utils/Logger.d.ts +43 -3
- package/dist/utils/Logger.d.ts.map +1 -1
- package/dist/utils/Logger.js +78 -36
- package/dist/utils/Logger.js.map +1 -1
- package/dist/utils/MxpEncryption.d.ts +19 -6
- package/dist/utils/MxpEncryption.d.ts.map +1 -1
- package/dist/utils/MxpEncryption.js +48 -16
- package/dist/utils/MxpEncryption.js.map +1 -1
- package/package.json +19 -4
- package/src/adapters/FrameworkAdapter.ts +1 -1
- package/src/config/ConfigManager.ts +52 -19
- package/src/config/memory-strata.config.ts +136 -0
- package/src/constants/ToolNames.ts +4 -18
- package/src/database/DatabaseAdapterFactory.ts +23 -6
- package/src/database/adapters/mongodb/MongoBaseRepository.ts +16 -2
- package/src/events/ClientEventBus.ts +68 -403
- package/src/events/EventBus.ts +7 -8
- package/src/events/EventBusBase.ts +479 -116
- package/src/events/EventNames.ts +6 -0
- package/src/events/PublicEvents.ts +7 -4
- package/src/events/ServerEventBus.ts +78 -473
- package/src/events/event-definitions/LlmBudgetEvents.ts +74 -0
- package/src/interfaces/IMemoryPersistence.ts +51 -0
- package/src/middleware/MxpMiddleware.ts +51 -24
- package/src/models/channelKey.ts +18 -4
- package/src/models/memoryUtility.ts +64 -0
- package/src/models/user.ts +36 -4
- package/src/mxp/BinaryProtocolLayer.ts +108 -124
- package/src/mxp/ContextCompressionEngine.ts +219 -161
- package/src/mxp/MxpTokenOptimizer.ts +10 -10
- package/src/prompts/MxfAgentSystemPrompt.ts +45 -55
- package/src/protocols/mcp/ToolError.ts +201 -0
- package/src/protocols/mcp/defineTool.ts +379 -0
- package/src/protocols/mcp/security/HttpTargetGuard.ts +267 -0
- package/src/protocols/mcp/security/McpSecurityGuard.ts +10 -3
- package/src/protocols/mcp/security/McpToolPolicy.ts +221 -0
- package/src/protocols/mcp/services/ExternalMcpServerManager.ts +340 -322
- package/src/protocols/mcp/services/ExternalServerConfigs.ts +82 -19
- package/src/protocols/mcp/tools/AnalyticsTools.ts +1 -1
- package/src/protocols/mcp/tools/CodeAnalysisTools.ts +15 -0
- package/src/protocols/mcp/tools/EffectivenessTools.ts +3 -3
- package/src/protocols/mcp/tools/GitTools.ts +290 -569
- package/src/protocols/mcp/tools/InfrastructureTools.ts +189 -43
- package/src/protocols/mcp/tools/MemorySearchTools.ts +77 -1
- package/src/protocols/mcp/tools/OrparTools.ts +87 -0
- package/src/protocols/mcp/tools/SafetyTools.ts +501 -579
- package/src/protocols/mcp/tools/TaskPlanningTools.ts +81 -39
- package/src/protocols/mcp/tools/TestTools.ts +339 -419
- package/src/protocols/mcp/tools/TypeScriptTools.ts +316 -376
- package/src/protocols/mcp/tools/WebTools.ts +209 -307
- package/src/protocols/mcp/tools/shell/ShellExecuteHandler.ts +53 -14
- package/src/schemas/EventPayloadSchema.ts +37 -0
- package/src/services/BackgroundTaskManager.ts +12 -4
- package/src/services/BrowserManager.ts +41 -1
- package/src/services/MemoryCompressor.ts +20 -32
- package/src/services/MemoryService.ts +96 -58
- package/src/services/MxfMLService.ts +41 -7
- package/src/services/PredictiveAnalyticsService.ts +101 -51
- package/src/services/QValueManager.ts +10 -0
- package/src/services/RewardSignalProcessor.ts +138 -9
- package/src/services/SharedStateService.ts +56 -8
- package/src/services/TaskEffectivenessService.ts +114 -187
- package/src/services/WebSearchService.ts +2 -1
- package/src/services/dag/TaskDagService.ts +2 -0
- package/src/services/orpar-memory/OrparMemoryCoordinator.ts +86 -10
- package/src/types/MemoryUtilityTypes.ts +2 -0
- package/src/utils/Logger.ts +116 -40
- package/src/utils/MxpEncryption.ts +69 -34
- package/dist/mxp/MxpEventForwardingEnhancer.d.ts +0 -134
- package/dist/mxp/MxpEventForwardingEnhancer.d.ts.map +0 -1
- package/dist/mxp/MxpEventForwardingEnhancer.js +0 -361
- package/dist/mxp/MxpEventForwardingEnhancer.js.map +0 -1
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts +0 -56
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.d.ts.map +0 -1
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.js +0 -57
- package/dist/protocols/mcp/services/ToolSchemaEnhancements.js.map +0 -1
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts +0 -270
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.d.ts.map +0 -1
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.js +0 -256
- package/dist/protocols/mcp/tools/ControlLoopLifecycle.js.map +0 -1
- package/dist/protocols/mcp/tools/LspTools.d.ts +0 -495
- package/dist/protocols/mcp/tools/LspTools.d.ts.map +0 -1
- package/dist/protocols/mcp/tools/LspTools.js +0 -469
- package/dist/protocols/mcp/tools/LspTools.js.map +0 -1
- package/src/mxp/MxpEventForwardingEnhancer.ts +0 -471
- package/src/protocols/mcp/services/ToolSchemaEnhancements.ts +0 -92
- package/src/protocols/mcp/tools/ControlLoopLifecycle.ts +0 -302
- package/src/protocols/mcp/tools/LspTools.ts +0 -476
|
@@ -37,6 +37,7 @@ import { promisify } from 'util';
|
|
|
37
37
|
import crypto from 'crypto';
|
|
38
38
|
import { getSecurityGuard, SecurityContext } from '../security/McpSecurityGuard.js';
|
|
39
39
|
import { getConfirmationManager } from '../security/McpConfirmationManager.js';
|
|
40
|
+
import { buildShellChildEnv } from '../security/McpToolPolicy.js';
|
|
40
41
|
import { execute as shellExecuteHandler } from './shell/ShellExecuteHandler.js';
|
|
41
42
|
import { processOutput } from './shell/LargeOutputHandler.js';
|
|
42
43
|
import { BackgroundTaskManager } from '../../../services/BackgroundTaskManager.js';
|
|
@@ -58,68 +59,173 @@ const logger = new Logger('info', 'InfrastructureTools', 'server');
|
|
|
58
59
|
const validator = createStrictValidator('InfrastructureTools');
|
|
59
60
|
const execAsync = promisify(exec);
|
|
60
61
|
|
|
61
|
-
// Initialize security
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// Initialize the security guard singleton. Importing this module is what binds
|
|
63
|
+
// the guard to the project root; ShellExecuteHandler and executeShellCommand
|
|
64
|
+
// below then retrieve it with getSecurityGuard().
|
|
65
|
+
getSecurityGuard(process.cwd());
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
|
-
*
|
|
68
|
+
* Identity of the caller running a shell command.
|
|
69
|
+
*
|
|
70
|
+
* Required — the security guard makes its decision in the context of an agent
|
|
71
|
+
* and a channel, and every shell execution is attributable. There is no default:
|
|
72
|
+
* a missing identity is a wiring bug, not something to paper over with 'system'.
|
|
73
|
+
*/
|
|
74
|
+
export interface ShellCommandContext {
|
|
75
|
+
agentId: AgentId;
|
|
76
|
+
channelId: ChannelId;
|
|
77
|
+
requestId: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Result of running a shell command through {@link executeShellCommand}.
|
|
82
|
+
*/
|
|
83
|
+
export interface ShellCommandResult {
|
|
84
|
+
command: string;
|
|
85
|
+
exitCode: number;
|
|
86
|
+
stdout?: string;
|
|
87
|
+
stderr?: string;
|
|
88
|
+
executionTime: number;
|
|
89
|
+
executedAt: number;
|
|
90
|
+
/** Destructive-pattern warnings raised by the security guard, if any */
|
|
91
|
+
warnings?: string[];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Run a shell command on behalf of an agent.
|
|
96
|
+
*
|
|
97
|
+
* Every tool that shells out — git, tsc, eslint, prettier, jest, mocha, vitest,
|
|
98
|
+
* find, rg, and the rollback/backup tools — goes through here, so this is where
|
|
99
|
+
* the security controls have to live:
|
|
100
|
+
*
|
|
101
|
+
* 1. The command is validated by the McpSecurityGuard, which parses compound
|
|
102
|
+
* expressions and checks each effective command. A blocked command throws.
|
|
103
|
+
* 2. A command the guard flags for confirmation goes to the confirmation
|
|
104
|
+
* manager, and a refusal throws.
|
|
105
|
+
* 3. The child process receives a minimal environment built by the tool policy
|
|
106
|
+
* — not the server's, which holds JWT_SECRET, MONGODB_URI and
|
|
107
|
+
* OPENROUTER_API_KEY.
|
|
108
|
+
* 4. Arguments are shell-escaped before they reach the shell.
|
|
109
|
+
*
|
|
110
|
+
* @param command - The base command (for example 'git')
|
|
111
|
+
* @param args - Arguments, shell-escaped before use
|
|
112
|
+
* @param options - Execution options; `context` identifies the calling agent
|
|
113
|
+
* @throws Error when the guard blocks the command or confirmation is refused
|
|
67
114
|
*/
|
|
68
115
|
export async function executeShellCommand(
|
|
69
116
|
command: string,
|
|
70
|
-
args
|
|
71
|
-
options
|
|
117
|
+
args: string[] | undefined,
|
|
118
|
+
options: {
|
|
119
|
+
/** Who is running this command. Required. */
|
|
120
|
+
context: ShellCommandContext;
|
|
72
121
|
workingDirectory?: string;
|
|
73
122
|
environment?: Record<string, string>;
|
|
74
123
|
timeout?: number;
|
|
75
124
|
captureOutput?: boolean;
|
|
76
125
|
}
|
|
77
|
-
): Promise<{
|
|
78
|
-
command: string;
|
|
79
|
-
exitCode: number;
|
|
80
|
-
stdout?: string;
|
|
81
|
-
stderr?: string;
|
|
82
|
-
executionTime: number;
|
|
83
|
-
executedAt: number;
|
|
84
|
-
}> {
|
|
126
|
+
): Promise<ShellCommandResult> {
|
|
85
127
|
const startTime = Date.now();
|
|
86
|
-
|
|
87
|
-
try {
|
|
88
|
-
// Build the full command string with properly escaped arguments
|
|
89
|
-
// Shell-escape each argument by wrapping in single quotes and escaping any embedded single quotes
|
|
90
|
-
const quotedArgs = args ? args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ') : '';
|
|
91
|
-
const fullCommand = args ? `${command} ${quotedArgs}` : command;
|
|
92
128
|
|
|
93
|
-
|
|
129
|
+
validator.assertIsString(command, 'command');
|
|
130
|
+
|
|
131
|
+
const context = options?.context;
|
|
132
|
+
if (!context || typeof context.agentId !== 'string' || context.agentId.length === 0) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
'executeShellCommand requires context.agentId — shell execution must be attributable to an agent.'
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (typeof context.channelId !== 'string' || context.channelId.length === 0) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
'executeShellCommand requires context.channelId — shell execution must be attributable to a channel.'
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Build the full command string with properly escaped arguments. Each argument
|
|
144
|
+
// is wrapped in single quotes with embedded quotes escaped, so an argument can
|
|
145
|
+
// never break out into a new shell word.
|
|
146
|
+
const quotedArgs = args ? args.map(arg => `'${arg.replace(/'/g, "'\\''")}'`).join(' ') : '';
|
|
147
|
+
const fullCommand = args && args.length > 0 ? `${command} ${quotedArgs}` : command;
|
|
148
|
+
|
|
149
|
+
// ── Security validation ────────────────────────────────────────────────
|
|
150
|
+
// The guard parses compound expressions (`a && b`, `a; b`) and validates each
|
|
151
|
+
// effective command, so `git status; rm -rf /` cannot slip through on the
|
|
152
|
+
// strength of its first word.
|
|
153
|
+
const securityGuard = getSecurityGuard();
|
|
154
|
+
const securityContext: SecurityContext = {
|
|
155
|
+
agentId: context.agentId,
|
|
156
|
+
channelId: context.channelId,
|
|
157
|
+
requestId: context.requestId
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const validation = securityGuard.validateCommand(fullCommand, securityContext);
|
|
161
|
+
|
|
162
|
+
if (!validation.allowed) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`Command blocked by security policy: ${validation.reason ?? 'command is not allowed'} ` +
|
|
165
|
+
`(command: ${command}, risk: ${validation.riskLevel ?? 'unknown'})`
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (validation.warnings && validation.warnings.length > 0) {
|
|
170
|
+
logger.warn(
|
|
171
|
+
`Destructive command warnings for "${fullCommand}": ${validation.warnings.join('; ')}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (validation.requiresConfirmation) {
|
|
176
|
+
const confirmationManager = getConfirmationManager();
|
|
177
|
+
const confirmed = await confirmationManager.requestConfirmation(
|
|
178
|
+
'command',
|
|
179
|
+
'Execute shell command',
|
|
180
|
+
{
|
|
181
|
+
command: fullCommand,
|
|
182
|
+
riskLevel: validation.riskLevel || 'medium',
|
|
183
|
+
reason: validation.reason || 'Command requires confirmation'
|
|
184
|
+
},
|
|
185
|
+
securityContext,
|
|
186
|
+
options?.timeout || 30000
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (!confirmed) {
|
|
190
|
+
throw new Error(`Command execution denied by confirmation policy: ${command}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// ── Execution ──────────────────────────────────────────────────────────
|
|
195
|
+
// Least privilege: the child gets PATH/HOME/locale plus whatever the caller
|
|
196
|
+
// declares, never the server's full environment.
|
|
197
|
+
const childEnv = buildShellChildEnv(options?.environment);
|
|
198
|
+
|
|
199
|
+
try {
|
|
94
200
|
const result = await execAsync(fullCommand, {
|
|
95
201
|
cwd: options?.workingDirectory || process.cwd(),
|
|
96
|
-
env:
|
|
202
|
+
env: childEnv,
|
|
97
203
|
timeout: options?.timeout || 30000,
|
|
98
204
|
maxBuffer: 1024 * 1024 * 10 // 10MB buffer
|
|
99
205
|
});
|
|
100
|
-
|
|
101
|
-
const executionTime = Date.now() - startTime;
|
|
102
|
-
|
|
206
|
+
|
|
103
207
|
return {
|
|
104
208
|
command: fullCommand,
|
|
105
209
|
exitCode: 0,
|
|
106
210
|
stdout: options?.captureOutput !== false ? result.stdout : undefined,
|
|
107
211
|
stderr: options?.captureOutput !== false ? result.stderr : undefined,
|
|
108
|
-
executionTime,
|
|
109
|
-
executedAt: Date.now()
|
|
212
|
+
executionTime: Date.now() - startTime,
|
|
213
|
+
executedAt: Date.now(),
|
|
214
|
+
warnings: validation.warnings
|
|
110
215
|
};
|
|
111
|
-
|
|
216
|
+
|
|
112
217
|
} catch (execError: any) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
//
|
|
218
|
+
// A non-zero exit code is a result, not an exception — `git diff --quiet`
|
|
219
|
+
// and `grep` use exit codes to mean "no changes" / "no matches". The caller
|
|
220
|
+
// inspects exitCode. Genuine policy failures throw above, before we get here.
|
|
116
221
|
return {
|
|
117
|
-
command:
|
|
118
|
-
exitCode: execError.code
|
|
222
|
+
command: fullCommand,
|
|
223
|
+
exitCode: execError.code ?? 1,
|
|
119
224
|
stdout: options?.captureOutput !== false ? execError.stdout || '' : undefined,
|
|
120
225
|
stderr: options?.captureOutput !== false ? execError.stderr || execError.message : undefined,
|
|
121
|
-
executionTime,
|
|
122
|
-
executedAt: Date.now()
|
|
226
|
+
executionTime: Date.now() - startTime,
|
|
227
|
+
executedAt: Date.now(),
|
|
228
|
+
warnings: validation.warnings
|
|
123
229
|
};
|
|
124
230
|
}
|
|
125
231
|
}
|
|
@@ -351,11 +457,6 @@ export const shellExecTool = {
|
|
|
351
457
|
default: true,
|
|
352
458
|
description: 'Whether to capture command output'
|
|
353
459
|
},
|
|
354
|
-
allowedCommands: {
|
|
355
|
-
type: 'array',
|
|
356
|
-
items: { type: 'string' },
|
|
357
|
-
description: 'List of allowed commands (for security)'
|
|
358
|
-
},
|
|
359
460
|
description: {
|
|
360
461
|
type: 'string',
|
|
361
462
|
description: 'Human-readable summary of what this command does (for logging, audit trails, and display)'
|
|
@@ -379,6 +480,7 @@ export const shellExecTool = {
|
|
|
379
480
|
* to BackgroundTaskManager for background execution.
|
|
380
481
|
*
|
|
381
482
|
* Foreground mode provides:
|
|
483
|
+
* - Security guard validation and confirmation
|
|
382
484
|
* - Command semantics (exit code interpretation)
|
|
383
485
|
* - Destructive command warnings
|
|
384
486
|
* - Command classification (read-only, silent, etc.)
|
|
@@ -391,6 +493,10 @@ export const shellExecTool = {
|
|
|
391
493
|
* - Ring-buffer output accumulation
|
|
392
494
|
* - Throttled progress events via EventBus
|
|
393
495
|
* - Query via shell_task_status tool
|
|
496
|
+
*
|
|
497
|
+
* The command allowlist is NOT an input. It comes from MXF_SHELL_ALLOWED_COMMANDS
|
|
498
|
+
* (see McpToolPolicy) — an allowlist passed as a tool argument would be supplied
|
|
499
|
+
* by the same model it is meant to restrict.
|
|
394
500
|
*/
|
|
395
501
|
async handler(input: {
|
|
396
502
|
command: string;
|
|
@@ -399,7 +505,6 @@ export const shellExecTool = {
|
|
|
399
505
|
environment?: Record<string, string>;
|
|
400
506
|
timeout?: number;
|
|
401
507
|
captureOutput?: boolean;
|
|
402
|
-
allowedCommands?: string[];
|
|
403
508
|
description?: string;
|
|
404
509
|
runInBackground?: boolean;
|
|
405
510
|
backgroundTimeout?: number;
|
|
@@ -408,14 +513,55 @@ export const shellExecTool = {
|
|
|
408
513
|
channelId: ChannelId;
|
|
409
514
|
requestId: string;
|
|
410
515
|
}) {
|
|
411
|
-
// Background execution: delegate to BackgroundTaskManager
|
|
516
|
+
// Background execution: delegate to BackgroundTaskManager.
|
|
517
|
+
//
|
|
518
|
+
// The guard runs here, at the tool boundary, because BackgroundTaskManager
|
|
519
|
+
// spawns directly. Without this the background path would be an unguarded
|
|
520
|
+
// way to run exactly the commands the foreground path blocks.
|
|
412
521
|
if (input.runInBackground) {
|
|
522
|
+
const securityGuard = getSecurityGuard();
|
|
523
|
+
const securityContext: SecurityContext = {
|
|
524
|
+
agentId: context.agentId,
|
|
525
|
+
channelId: context.channelId,
|
|
526
|
+
requestId: context.requestId
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
const validation = securityGuard.validateCommand(input.command, securityContext);
|
|
530
|
+
|
|
531
|
+
if (!validation.allowed) {
|
|
532
|
+
throw new Error(
|
|
533
|
+
`Command blocked by security policy: ${validation.reason ?? 'command is not allowed'} ` +
|
|
534
|
+
`(command: ${input.command}, risk: ${validation.riskLevel ?? 'unknown'})`
|
|
535
|
+
);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (validation.requiresConfirmation) {
|
|
539
|
+
const confirmed = await getConfirmationManager().requestConfirmation(
|
|
540
|
+
'command',
|
|
541
|
+
'Execute background shell command',
|
|
542
|
+
{
|
|
543
|
+
command: input.command,
|
|
544
|
+
riskLevel: validation.riskLevel || 'medium',
|
|
545
|
+
reason: validation.reason || 'Command requires confirmation'
|
|
546
|
+
},
|
|
547
|
+
securityContext,
|
|
548
|
+
input.timeout || 30000
|
|
549
|
+
);
|
|
550
|
+
|
|
551
|
+
if (!confirmed) {
|
|
552
|
+
throw new Error(`Background command execution denied by confirmation policy: ${input.command}`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
|
|
413
556
|
const btm = BackgroundTaskManager.getInstance();
|
|
414
557
|
const { taskId } = await btm.startBackground(
|
|
415
558
|
input.command,
|
|
416
559
|
{
|
|
417
560
|
workingDirectory: input.workingDirectory,
|
|
418
|
-
environment
|
|
561
|
+
// Hand the child a minimal environment. BackgroundTaskManager
|
|
562
|
+
// still merges this over process.env internally — see the
|
|
563
|
+
// reported fix for BackgroundTaskManager.ts:190.
|
|
564
|
+
environment: buildShellChildEnv(input.environment),
|
|
419
565
|
timeout: input.backgroundTimeout,
|
|
420
566
|
description: input.description
|
|
421
567
|
},
|
|
@@ -25,6 +25,12 @@
|
|
|
25
25
|
import { McpToolDefinition, McpToolHandlerContext, McpToolHandlerResult, McpToolResultContent } from '../McpServerTypes.js';
|
|
26
26
|
import { Logger } from '../../../utils/Logger.js';
|
|
27
27
|
import { MxfMeilisearchService, SearchParams } from '../../../services/MxfMeilisearchService.js';
|
|
28
|
+
import { MemoryService } from '../../../services/MemoryService.js';
|
|
29
|
+
import { QValueManager } from '../../../services/QValueManager.js';
|
|
30
|
+
import { UtilityScorerService } from '../../../services/UtilityScorerService.js';
|
|
31
|
+
import { RewardSignalProcessor } from '../../../services/RewardSignalProcessor.js';
|
|
32
|
+
import { MemoryCandidate } from '../../../types/MemoryUtilityTypes.js';
|
|
33
|
+
import { getCurrentMemoryPhase } from './OrparTools.js';
|
|
28
34
|
import { paginationInputSchema, checkResultSize, PaginationMetadata } from '../../../utils/ToolPaginationUtils.js';
|
|
29
35
|
|
|
30
36
|
const logger = new Logger('info', 'MemorySearchTools', 'server');
|
|
@@ -32,6 +38,73 @@ const logger = new Logger('info', 'MemorySearchTools', 'server');
|
|
|
32
38
|
/**
|
|
33
39
|
* Search conversation history semantically
|
|
34
40
|
*/
|
|
41
|
+
/**
|
|
42
|
+
* Re-rank search hits by learned utility, and record what was retrieved.
|
|
43
|
+
*
|
|
44
|
+
* This is the join between semantic search and the Memory Utility Learning System.
|
|
45
|
+
* Before this existed, Q-values were computed and stored but no reachable retrieval
|
|
46
|
+
* path consulted them, so learning could not change anything an agent saw — and no
|
|
47
|
+
* production code recorded which memories a task used, so no reward was ever
|
|
48
|
+
* attributed. Both halves of the loop close here.
|
|
49
|
+
*
|
|
50
|
+
* When MULS is disabled this returns the hits untouched, so search behaves exactly as
|
|
51
|
+
* it did before.
|
|
52
|
+
*/
|
|
53
|
+
async function applyUtilityRanking<T extends { id: string; _rankingScore: number }>(
|
|
54
|
+
query: string,
|
|
55
|
+
hits: T[],
|
|
56
|
+
context: McpToolHandlerContext
|
|
57
|
+
): Promise<T[]> {
|
|
58
|
+
const qValueManager = QValueManager.getInstance();
|
|
59
|
+
if (!qValueManager.isEnabled() || hits.length === 0) {
|
|
60
|
+
return hits;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const { agentId, channelId } = context;
|
|
64
|
+
const memoryIds = hits.map(hit => hit.id);
|
|
65
|
+
|
|
66
|
+
// Load Q-values learned in previous runs; without this every memory this process
|
|
67
|
+
// has not seen yet would score at the default and ranking would ignore all learning.
|
|
68
|
+
const memoryService = MemoryService.getInstance();
|
|
69
|
+
await memoryService.hydrateQValues(memoryIds);
|
|
70
|
+
|
|
71
|
+
const candidates: MemoryCandidate[] = hits.map(hit => ({
|
|
72
|
+
memoryId: hit.id,
|
|
73
|
+
similarity: hit._rankingScore,
|
|
74
|
+
qValue: qValueManager.getQValue(hit.id)
|
|
75
|
+
}));
|
|
76
|
+
|
|
77
|
+
// Phase-specific lambda when the agent is inside an ORPAR cycle; otherwise the
|
|
78
|
+
// configured default. We do not guess a phase.
|
|
79
|
+
const phase = agentId && channelId ? getCurrentMemoryPhase(agentId, channelId) : null;
|
|
80
|
+
const scorer = UtilityScorerService.getInstance();
|
|
81
|
+
const scoringResult = phase
|
|
82
|
+
? scorer.scoreForPhase(query, candidates, phase)
|
|
83
|
+
: scorer.scoreMemories(query, candidates);
|
|
84
|
+
|
|
85
|
+
// Record the retrieval so RewardSignalProcessor can attribute the task's outcome to
|
|
86
|
+
// these memories when it completes.
|
|
87
|
+
if (agentId && channelId) {
|
|
88
|
+
RewardSignalProcessor.getInstance().trackAgentMemoriesUsage(
|
|
89
|
+
agentId,
|
|
90
|
+
channelId,
|
|
91
|
+
scoringResult.memories.map(m => m.memoryId),
|
|
92
|
+
phase ?? 'observation',
|
|
93
|
+
'context'
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const hitsById = new Map(hits.map(hit => [hit.id, hit]));
|
|
98
|
+
const ranked: T[] = [];
|
|
99
|
+
for (const scored of scoringResult.memories) {
|
|
100
|
+
const hit = hitsById.get(scored.memoryId);
|
|
101
|
+
if (hit) {
|
|
102
|
+
ranked.push(hit);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return ranked;
|
|
106
|
+
}
|
|
107
|
+
|
|
35
108
|
export const memory_search_conversations = {
|
|
36
109
|
name: 'memory_search_conversations',
|
|
37
110
|
description: 'Search your entire conversation history using semantic search. Find relevant past discussions even if they happened hundreds of messages ago. Use this when you need to recall "that time we talked about X".',
|
|
@@ -159,7 +232,10 @@ export const memory_search_conversations = {
|
|
|
159
232
|
|
|
160
233
|
const result = await meilisearch.searchConversations(searchParams);
|
|
161
234
|
|
|
162
|
-
|
|
235
|
+
// Re-rank by learned utility and record the retrieval for reward attribution.
|
|
236
|
+
const rankedHits = await applyUtilityRanking(input.query, result.hits, context);
|
|
237
|
+
|
|
238
|
+
const formattedResults = rankedHits.map(hit => ({
|
|
163
239
|
content: hit.content,
|
|
164
240
|
role: hit.role,
|
|
165
241
|
agentId: hit.agentId,
|
|
@@ -48,6 +48,9 @@ import { createStrictValidator } from '../../../utils/validation.js';
|
|
|
48
48
|
import { AgentId } from '../../../types/Agent.js';
|
|
49
49
|
import { ChannelId } from '../../../types/ChannelContext.js';
|
|
50
50
|
import { Observation, Reflection } from '../../../types/ControlLoopTypes.js';
|
|
51
|
+
import { OrparPhase as MemoryOrparPhase } from '../../../types/MemoryUtilityTypes.js';
|
|
52
|
+
import { OrparGraphIntegration } from '../../../services/kg/OrparGraphIntegration.js';
|
|
53
|
+
import { EntityExtractionService } from '../../../services/kg/EntityExtractionService.js';
|
|
51
54
|
import {
|
|
52
55
|
normalizeOrparParameters,
|
|
53
56
|
stripUnknownParameters,
|
|
@@ -68,6 +71,75 @@ let agentDisconnectListenerRegistered = false;
|
|
|
68
71
|
*/
|
|
69
72
|
export type OrparPhase = 'observe' | 'reason' | 'plan' | 'act' | 'reflect';
|
|
70
73
|
|
|
74
|
+
/**
|
|
75
|
+
* The ORPAR tools name phases with verbs ('observe'), while the memory-utility system
|
|
76
|
+
* names them with nouns ('observation' — see MemoryUtilityTypes.OrparPhase). They are
|
|
77
|
+
* the same five phases in two vocabularies, which is part of why memory retrieval and
|
|
78
|
+
* phase-weighted learning were never connected. This map is the bridge.
|
|
79
|
+
*/
|
|
80
|
+
const TOOL_PHASE_TO_MEMORY_PHASE: Record<OrparPhase, MemoryOrparPhase> = {
|
|
81
|
+
observe: 'observation',
|
|
82
|
+
reason: 'reasoning',
|
|
83
|
+
plan: 'planning',
|
|
84
|
+
act: 'action',
|
|
85
|
+
reflect: 'reflection'
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The agent's current ORPAR phase, in the vocabulary the memory-utility system uses.
|
|
90
|
+
*
|
|
91
|
+
* Returns null when the agent has no active ORPAR cycle, in which case callers should
|
|
92
|
+
* fall back to phase-independent scoring rather than guessing a phase.
|
|
93
|
+
*/
|
|
94
|
+
export function getCurrentMemoryPhase(agentId: string, channelId: string): MemoryOrparPhase | null {
|
|
95
|
+
const state = agentOrparStates.get(`${agentId}:${channelId}`);
|
|
96
|
+
if (!state?.currentPhase) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return TOOL_PHASE_TO_MEMORY_PHASE[state.currentPhase];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Turn a reflection into knowledge-graph learning.
|
|
104
|
+
*
|
|
105
|
+
* Extracts the entities the agent named in its reflection, records them, and propagates
|
|
106
|
+
* the cycle's outcome as a reward across them — so entities that keep appearing in
|
|
107
|
+
* successful cycles gain utility and entities tied to failures lose it.
|
|
108
|
+
*
|
|
109
|
+
* Returns a summary of what changed. When the knowledge graph is disabled this reports
|
|
110
|
+
* zeroes rather than pretending work happened.
|
|
111
|
+
*/
|
|
112
|
+
async function applyReflectionToGraph(
|
|
113
|
+
agentId: AgentId,
|
|
114
|
+
channelId: ChannelId,
|
|
115
|
+
reflection: string,
|
|
116
|
+
taskSuccess: boolean
|
|
117
|
+
): Promise<{ entitiesCreated: number; relationshipsCreated: number; qValuesUpdated: number }> {
|
|
118
|
+
const graph = OrparGraphIntegration.getInstance();
|
|
119
|
+
if (!graph.isEnabled()) {
|
|
120
|
+
return { entitiesCreated: 0, relationshipsCreated: 0, qValuesUpdated: 0 };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const extraction = await EntityExtractionService.getInstance().extractFromText(
|
|
124
|
+
channelId,
|
|
125
|
+
reflection
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const involvedEntityIds = extraction.entities
|
|
129
|
+
.map(entity => entity.id)
|
|
130
|
+
.filter((id): id is string => Boolean(id));
|
|
131
|
+
|
|
132
|
+
return graph.applyReflectionUpdate(channelId, agentId, {
|
|
133
|
+
// Extraction already persisted the entities and relationships it found, so this
|
|
134
|
+
// update only has to attribute the outcome to them.
|
|
135
|
+
newEntities: [],
|
|
136
|
+
newRelationships: [],
|
|
137
|
+
qValueUpdates: [],
|
|
138
|
+
involvedEntityIds,
|
|
139
|
+
taskSuccess
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
71
143
|
/**
|
|
72
144
|
* Valid phase transitions
|
|
73
145
|
*/
|
|
@@ -898,6 +970,20 @@ IMPORTANT - Parameter format:
|
|
|
898
970
|
{ learnings: input.learnings, phaseData: { reflection: input.reflection, learnings: input.learnings, expectationsMet: input.expectationsMet, adjustments: input.adjustments } }
|
|
899
971
|
);
|
|
900
972
|
|
|
973
|
+
// Feed the reflection back into the knowledge graph.
|
|
974
|
+
//
|
|
975
|
+
// OrparGraphIntegration.applyReflectionUpdate — which creates entities from what the
|
|
976
|
+
// agent learned and propagates the task outcome as a reward across the entities
|
|
977
|
+
// involved — had no caller anywhere, so kg_get_high_utility_entities ranked entities
|
|
978
|
+
// on Q-values that were never once updated. Reflection is the only phase that knows
|
|
979
|
+
// whether expectations were met, so entity learning belongs here.
|
|
980
|
+
const knowledgeGraph = await applyReflectionToGraph(
|
|
981
|
+
agentId,
|
|
982
|
+
channelId,
|
|
983
|
+
input.reflection,
|
|
984
|
+
input.expectationsMet !== false
|
|
985
|
+
);
|
|
986
|
+
|
|
901
987
|
return {
|
|
902
988
|
success: true,
|
|
903
989
|
phase: 'reflect',
|
|
@@ -909,6 +995,7 @@ IMPORTANT - Parameter format:
|
|
|
909
995
|
expectationsMet: input.expectationsMet,
|
|
910
996
|
adjustments: input.adjustments
|
|
911
997
|
},
|
|
998
|
+
knowledgeGraph,
|
|
912
999
|
cycleComplete: true,
|
|
913
1000
|
nextPhase: 'observe',
|
|
914
1001
|
guidance: getPhaseGuidance('reflect', context?.allowedTools || context?._allowedTools),
|