auroq-os 1.0.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/.auroq-core/constitution.md +153 -0
- package/.auroq-core/core/synapse/context/context-builder.js +34 -0
- package/.auroq-core/core/synapse/context/context-tracker.js +198 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/consistency-collector.js +168 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/hook-collector.js +129 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/manifest-collector.js +82 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/output-analyzer.js +134 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/pipeline-collector.js +75 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/quality-collector.js +252 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/relevance-matrix.js +174 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/safe-read-json.js +31 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/session-collector.js +102 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/timing-collector.js +126 -0
- package/.auroq-core/core/synapse/diagnostics/collectors/uap-collector.js +83 -0
- package/.auroq-core/core/synapse/diagnostics/report-formatter.js +484 -0
- package/.auroq-core/core/synapse/diagnostics/synapse-diagnostics.js +95 -0
- package/.auroq-core/core/synapse/domain/domain-loader.js +322 -0
- package/.auroq-core/core/synapse/engine.js +400 -0
- package/.auroq-core/core/synapse/layers/l0-constitution.js +80 -0
- package/.auroq-core/core/synapse/layers/l1-global.js +102 -0
- package/.auroq-core/core/synapse/layers/l2-agent.js +94 -0
- package/.auroq-core/core/synapse/layers/l3-workflow.js +94 -0
- package/.auroq-core/core/synapse/layers/l4-task.js +83 -0
- package/.auroq-core/core/synapse/layers/l5-squad.js +244 -0
- package/.auroq-core/core/synapse/layers/l6-keyword.js +154 -0
- package/.auroq-core/core/synapse/layers/l7-star-command.js +169 -0
- package/.auroq-core/core/synapse/layers/layer-processor.js +82 -0
- package/.auroq-core/core/synapse/memory/memory-bridge.js +220 -0
- package/.auroq-core/core/synapse/memory/synapse-memory-provider.js +201 -0
- package/.auroq-core/core/synapse/output/formatter.js +561 -0
- package/.auroq-core/core/synapse/runtime/hook-runtime.js +98 -0
- package/.auroq-core/core/synapse/scripts/generate-constitution.js +204 -0
- package/.auroq-core/core/synapse/session/session-manager.js +404 -0
- package/.auroq-core/core/synapse/utils/atomic-write.js +79 -0
- package/.auroq-core/core/synapse/utils/paths.js +57 -0
- package/.auroq-core/core/synapse/utils/tokens.js +25 -0
- package/.auroq-core/core-config.yaml +80 -0
- package/.auroq-core/development/sistema-gestao-projetos.md +193 -0
- package/.auroq-core/development/sistema-memoria.md +157 -0
- package/.auroq-core/dna-operacional.md +134 -0
- package/.claude/CLAUDE.md +399 -0
- package/.claude/commands/AuroqOS/agents/forge.md +374 -0
- package/.claude/commands/AuroqOS/agents/ops.md +277 -0
- package/.claude/commands/companion.md +7 -0
- package/.claude/hooks/precompact-session-digest.cjs +46 -0
- package/.claude/hooks/synapse-engine.cjs +99 -0
- package/.claude/rules/agent-authority.md +79 -0
- package/.claude/rules/agent-handoff.md +97 -0
- package/.claude/rules/commit-inteligente.md +86 -0
- package/.claude/rules/dna-operacional.md +53 -0
- package/.claude/rules/evolucao-incremental.md +43 -0
- package/.claude/rules/mcp-usage.md +38 -0
- package/.claude/rules/memoria-inteligente.md +65 -0
- package/.claude/rules/project-tracker.md +49 -0
- package/.claude/rules/tool-response-filtering.md +57 -0
- package/.claude/settings.json +1 -0
- package/.claude/settings.local.json +33 -0
- package/.env.example +22 -0
- package/.gitignore +23 -0
- package/.synapse/constitution +21 -0
- package/.synapse/context +8 -0
- package/.synapse/global +10 -0
- package/.synapse/manifest +35 -0
- package/README.md +67 -0
- package/agents/companion/agents/companion.md +306 -0
- package/agents/companion/data/contexto-dinamico.md +23 -0
- package/agents/companion/data/demandas-backlog.md +19 -0
- package/agents/companion/data/log-decisoes.md +11 -0
- package/agents/companion/data/padroes-observados.md +10 -0
- package/agents/companion/knowledge/companion-foundation.md +49 -0
- package/agents/companion/knowledge/expert-essencial.md +30 -0
- package/agents/companion/knowledge/modus-operandi.md +161 -0
- package/agents/companion/tasks/new-project.md +111 -0
- package/agents/companion/tasks/save-memory.md +73 -0
- package/agents/companion/tasks/start.md +136 -0
- package/agents/companion/tasks/weekly-review.md +82 -0
- package/bin/auroq-os.js +346 -0
- package/business/campanhas/_template/BRIEFING.md +45 -0
- package/business/campanhas/_template/CHECKLIST.md +29 -0
- package/business/campanhas/_template/DIARIO.md +15 -0
- package/business/campanhas/_template/RETROVISOR.md +34 -0
- package/business/cockpit.md +72 -0
- package/business/templates/tracker-template.md +71 -0
- package/docs/knowledge/expert-business/posicionamento.md +27 -0
- package/docs/knowledge/expert-business/publico-alvo.md +39 -0
- package/docs/knowledge/expert-mind/historia.md +27 -0
- package/docs/knowledge/expert-mind/identidade.md +23 -0
- package/docs/knowledge/expert-mind/tom-de-voz.md +30 -0
- package/docs/knowledge/expert-mind/valores.md +32 -0
- package/package.json +26 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L7 Star-Command Layer Processor
|
|
3
|
+
*
|
|
4
|
+
* Detects *command patterns in the user prompt and loads
|
|
5
|
+
* corresponding rules from the .synapse/commands domain file.
|
|
6
|
+
*
|
|
7
|
+
* Command blocks in the domain file are delimited by [*command]
|
|
8
|
+
* headers. Multiple star-commands in a single prompt are supported.
|
|
9
|
+
*
|
|
10
|
+
* @module core/synapse/layers/l7-star-command
|
|
11
|
+
* @version 1.0.0
|
|
12
|
+
* @created Story SYN-5 - Layer Processors L4-L7
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const path = require('path');
|
|
16
|
+
const { loadDomainFile } = require('../domain/domain-loader');
|
|
17
|
+
const LayerProcessor = require('./layer-processor');
|
|
18
|
+
|
|
19
|
+
/** Regex to detect star-commands in prompt */
|
|
20
|
+
const STAR_COMMAND_REGEX = /\*([a-z][\w-]*)/gi;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* L7 Star-Command Processor
|
|
24
|
+
*
|
|
25
|
+
* Detects *command patterns in the prompt, loads the commands
|
|
26
|
+
* domain file, and extracts rules for matching command blocks.
|
|
27
|
+
* Returns null if no star-commands detected.
|
|
28
|
+
*
|
|
29
|
+
* @extends LayerProcessor
|
|
30
|
+
*/
|
|
31
|
+
class L7StarCommandProcessor extends LayerProcessor {
|
|
32
|
+
constructor() {
|
|
33
|
+
super({ name: 'star-command', layer: 7, timeout: 5 });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Detect star-commands and load matching rules.
|
|
38
|
+
*
|
|
39
|
+
* Detection flow:
|
|
40
|
+
* 1. Scan prompt for *command patterns via regex
|
|
41
|
+
* 2. Deduplicate detected commands
|
|
42
|
+
* 3. Load .synapse/commands domain file
|
|
43
|
+
* 4. Parse command blocks delimited by [*command]
|
|
44
|
+
* 5. Collect rules for detected commands
|
|
45
|
+
*
|
|
46
|
+
* @param {object} context
|
|
47
|
+
* @param {string} context.prompt - Current prompt text
|
|
48
|
+
* @param {object} context.session - Session state (SYN-2 schema)
|
|
49
|
+
* @param {object} context.config - Config with synapsePath and manifest
|
|
50
|
+
* @param {object[]} context.previousLayers - Results from previous layers
|
|
51
|
+
* @returns {{ rules: string[], metadata: object } | null}
|
|
52
|
+
*/
|
|
53
|
+
process(context) {
|
|
54
|
+
const { prompt, config } = context;
|
|
55
|
+
const { synapsePath } = config;
|
|
56
|
+
|
|
57
|
+
if (!prompt) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 1. Detect star-commands in prompt
|
|
62
|
+
const commands = this._detectCommands(prompt);
|
|
63
|
+
if (commands.length === 0) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 2. Load commands domain file
|
|
68
|
+
const commandsFilePath = path.join(synapsePath, 'commands');
|
|
69
|
+
const rawRules = loadDomainFile(commandsFilePath);
|
|
70
|
+
|
|
71
|
+
if (!rawRules || rawRules.length === 0) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// 3. Parse command blocks from raw rules
|
|
76
|
+
const commandBlocks = this._parseCommandBlocks(rawRules);
|
|
77
|
+
|
|
78
|
+
// 4. Collect rules for detected commands
|
|
79
|
+
const allRules = [];
|
|
80
|
+
const matchedCommands = [];
|
|
81
|
+
|
|
82
|
+
for (const cmd of commands) {
|
|
83
|
+
const block = commandBlocks[cmd];
|
|
84
|
+
if (block && block.length > 0) {
|
|
85
|
+
allRules.push(...block);
|
|
86
|
+
matchedCommands.push(cmd);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (allRules.length === 0) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
rules: allRules,
|
|
96
|
+
metadata: {
|
|
97
|
+
layer: 7,
|
|
98
|
+
commands: matchedCommands,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Detect star-command patterns in prompt text.
|
|
105
|
+
*
|
|
106
|
+
* @param {string} prompt - User prompt text
|
|
107
|
+
* @returns {string[]} Deduplicated list of command names (lowercase)
|
|
108
|
+
* @private
|
|
109
|
+
*/
|
|
110
|
+
_detectCommands(prompt) {
|
|
111
|
+
const matches = [];
|
|
112
|
+
let match;
|
|
113
|
+
|
|
114
|
+
// Reset regex state
|
|
115
|
+
STAR_COMMAND_REGEX.lastIndex = 0;
|
|
116
|
+
|
|
117
|
+
while ((match = STAR_COMMAND_REGEX.exec(prompt)) !== null) {
|
|
118
|
+
matches.push(match[1].toLowerCase());
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return [...new Set(matches)];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Parse command blocks from domain file rules.
|
|
126
|
+
*
|
|
127
|
+
* Format:
|
|
128
|
+
* [*command] COMMAND:
|
|
129
|
+
* 0. Rule text here
|
|
130
|
+
* 1. Another rule
|
|
131
|
+
*
|
|
132
|
+
* Each [*command] header starts a new block.
|
|
133
|
+
* Rules within a block are the lines following the header.
|
|
134
|
+
*
|
|
135
|
+
* @param {string[]} rules - Raw rules from loadDomainFile
|
|
136
|
+
* @returns {object} Map of command name -> rule strings
|
|
137
|
+
* @private
|
|
138
|
+
*/
|
|
139
|
+
_parseCommandBlocks(rules) {
|
|
140
|
+
const blocks = {};
|
|
141
|
+
let currentCommand = null;
|
|
142
|
+
|
|
143
|
+
for (const rule of rules) {
|
|
144
|
+
// Check if this line is a command header: [*command]
|
|
145
|
+
const headerMatch = rule.match(/^\[\*([a-z][\w-]*)\]/i);
|
|
146
|
+
if (headerMatch) {
|
|
147
|
+
currentCommand = headerMatch[1].toLowerCase();
|
|
148
|
+
if (!blocks[currentCommand]) {
|
|
149
|
+
blocks[currentCommand] = [];
|
|
150
|
+
}
|
|
151
|
+
// If there's content after the header on the same line, include it
|
|
152
|
+
const afterHeader = rule.substring(headerMatch[0].length).trim();
|
|
153
|
+
if (afterHeader && !afterHeader.endsWith(':')) {
|
|
154
|
+
blocks[currentCommand].push(afterHeader);
|
|
155
|
+
}
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Add rule to current command block
|
|
160
|
+
if (currentCommand && rule.trim()) {
|
|
161
|
+
blocks[currentCommand].push(rule.trim());
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return blocks;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = L7StarCommandProcessor;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LayerProcessor — Abstract Base Class
|
|
3
|
+
*
|
|
4
|
+
* Defines the contract for all 8 SYNAPSE layer processors.
|
|
5
|
+
* Each layer implements process() to inject contextual rules
|
|
6
|
+
* into the prompt pipeline. The _safeProcess() wrapper provides
|
|
7
|
+
* timeout monitoring and error recovery (graceful degradation).
|
|
8
|
+
*
|
|
9
|
+
* @module core/synapse/layers/layer-processor
|
|
10
|
+
* @version 1.0.0
|
|
11
|
+
* @created Story SYN-4 - Layer Processors L0-L3
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Abstract base class for SYNAPSE layer processors.
|
|
16
|
+
*
|
|
17
|
+
* Subclasses MUST override process() with their layer-specific logic.
|
|
18
|
+
* Use _safeProcess() as the public entry point — it wraps process()
|
|
19
|
+
* with timeout monitoring and error handling.
|
|
20
|
+
*
|
|
21
|
+
* @abstract
|
|
22
|
+
*/
|
|
23
|
+
class LayerProcessor {
|
|
24
|
+
/**
|
|
25
|
+
* @param {object} options
|
|
26
|
+
* @param {string} options.name - Layer name (e.g., 'constitution', 'global')
|
|
27
|
+
* @param {number} options.layer - Layer number (0-7)
|
|
28
|
+
* @param {number} [options.timeout=15] - Timeout budget in milliseconds
|
|
29
|
+
*/
|
|
30
|
+
constructor({ name, layer, timeout = 15 }) {
|
|
31
|
+
if (new.target === LayerProcessor) {
|
|
32
|
+
throw new Error('LayerProcessor is abstract and cannot be instantiated directly');
|
|
33
|
+
}
|
|
34
|
+
this.name = name;
|
|
35
|
+
this.layer = layer;
|
|
36
|
+
this.timeout = timeout;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Process the layer and return contextual rules.
|
|
41
|
+
*
|
|
42
|
+
* Subclasses MUST override this method.
|
|
43
|
+
*
|
|
44
|
+
* @param {object} context
|
|
45
|
+
* @param {string} context.prompt - Current prompt text
|
|
46
|
+
* @param {object} context.session - Session state (SYN-2 schema)
|
|
47
|
+
* @param {object} context.config - Config with synapsePath and manifest
|
|
48
|
+
* @param {string} context.config.synapsePath - Base path to .synapse/ directory
|
|
49
|
+
* @param {object} context.config.manifest - Parsed manifest from parseManifest()
|
|
50
|
+
* @param {object[]} context.previousLayers - Results from previous layers
|
|
51
|
+
* @returns {{ rules: string[], metadata: object } | null} Rules and metadata, or null to skip
|
|
52
|
+
*/
|
|
53
|
+
process(context) {
|
|
54
|
+
throw new Error(`${this.name}: process() must be implemented by subclass`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Safe wrapper with timeout guard and error recovery.
|
|
59
|
+
*
|
|
60
|
+
* Calls process() and monitors execution time against the timeout budget.
|
|
61
|
+
* On error, logs a warning and returns null (graceful degradation).
|
|
62
|
+
*
|
|
63
|
+
* @param {object} context - Same as process()
|
|
64
|
+
* @returns {{ rules: string[], metadata: object } | null} Result or null on error/timeout
|
|
65
|
+
*/
|
|
66
|
+
_safeProcess(context) {
|
|
67
|
+
const start = Date.now();
|
|
68
|
+
try {
|
|
69
|
+
const result = this.process(context);
|
|
70
|
+
const elapsed = Date.now() - start;
|
|
71
|
+
if (elapsed > this.timeout) {
|
|
72
|
+
console.warn(`[synapse:${this.name}] Warning: Layer exceeded timeout (${elapsed}ms > ${this.timeout}ms)`);
|
|
73
|
+
}
|
|
74
|
+
return result;
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.warn(`[synapse:${this.name}] Error: ${error.message}`);
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = LayerProcessor;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Bridge — MIS consumer for SYNAPSE engine.
|
|
3
|
+
*
|
|
4
|
+
* Connects SynapseEngine to the Memory Intelligence System (MIS)
|
|
5
|
+
* via SynapseMemoryProvider. Implements bracket-aware retrieval with
|
|
6
|
+
* agent-scoped sector filtering and token budget enforcement.
|
|
7
|
+
*
|
|
8
|
+
* Consumer-only: reads from MIS APIs, never modifies memory stores.
|
|
9
|
+
* Graceful no-op when MIS module is not installed.
|
|
10
|
+
*
|
|
11
|
+
* @module core/synapse/memory/memory-bridge
|
|
12
|
+
* @version 2.0.0
|
|
13
|
+
* @created Story SYN-10 - Pro Memory Bridge (Feature-Gated MIS Consumer)
|
|
14
|
+
* @migrated Story INS-4.11 - Removed pro feature gate (AC9)
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const { estimateTokens } = require('../utils/tokens');
|
|
20
|
+
|
|
21
|
+
/** Memory bridge timeout in milliseconds. */
|
|
22
|
+
const BRIDGE_TIMEOUT_MS = 15;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Bracket-to-memory-layer mapping.
|
|
26
|
+
*
|
|
27
|
+
* FRESH → skip (no memory needed)
|
|
28
|
+
* MODERATE → Layer 1 metadata (~50 tokens)
|
|
29
|
+
* DEPLETED → Layer 2 chunks (~200 tokens)
|
|
30
|
+
* CRITICAL → Layer 3 full content (~1000 tokens)
|
|
31
|
+
*/
|
|
32
|
+
const BRACKET_LAYER_MAP = {
|
|
33
|
+
FRESH: { layer: 0, maxTokens: 0 },
|
|
34
|
+
MODERATE: { layer: 1, maxTokens: 50 },
|
|
35
|
+
DEPLETED: { layer: 2, maxTokens: 200 },
|
|
36
|
+
CRITICAL: { layer: 3, maxTokens: 1000 },
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/** Default sector for unknown agents. */
|
|
40
|
+
const DEFAULT_SECTORS = ['semantic'];
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* MemoryBridge — MIS consumer for SYNAPSE engine.
|
|
44
|
+
*
|
|
45
|
+
* Provides bracket-aware memory retrieval with:
|
|
46
|
+
* - Agent-scoped sector filtering
|
|
47
|
+
* - Token budget enforcement
|
|
48
|
+
* - Session-level caching
|
|
49
|
+
* - Timeout protection (<15ms)
|
|
50
|
+
* - Error catch-all with warn-and-proceed
|
|
51
|
+
* - Graceful no-op when MIS module is not installed
|
|
52
|
+
*/
|
|
53
|
+
class MemoryBridge {
|
|
54
|
+
/**
|
|
55
|
+
* @param {object} [options={}]
|
|
56
|
+
* @param {number} [options.timeout=15] - Max execution time in ms
|
|
57
|
+
*/
|
|
58
|
+
constructor(options = {}) {
|
|
59
|
+
this._timeout = options.timeout || BRIDGE_TIMEOUT_MS;
|
|
60
|
+
this._provider = null;
|
|
61
|
+
this._initialized = false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lazy-load the SynapseMemoryProvider (open-source).
|
|
66
|
+
* Gracefully returns null if MIS dependencies are not available.
|
|
67
|
+
*
|
|
68
|
+
* @private
|
|
69
|
+
* @returns {object|null} Provider instance or null
|
|
70
|
+
*/
|
|
71
|
+
_getProvider() {
|
|
72
|
+
if (this._provider) return this._provider;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const { SynapseMemoryProvider } = require('./synapse-memory-provider');
|
|
76
|
+
this._provider = new SynapseMemoryProvider();
|
|
77
|
+
return this._provider;
|
|
78
|
+
} catch {
|
|
79
|
+
// Provider or MIS not available — graceful degradation
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Get memory hints for the current prompt context.
|
|
86
|
+
*
|
|
87
|
+
* Returns an array of memory hint objects suitable for injection
|
|
88
|
+
* into the SYNAPSE pipeline. Gracefully returns [] when:
|
|
89
|
+
* - MIS module is not installed
|
|
90
|
+
* - Bracket is FRESH (no memory needed)
|
|
91
|
+
* - Provider fails or times out
|
|
92
|
+
* - Any error occurs
|
|
93
|
+
*
|
|
94
|
+
* @param {string} agentId - Active agent ID (e.g., 'dev', 'qa')
|
|
95
|
+
* @param {string} bracket - Context bracket (FRESH, MODERATE, DEPLETED, CRITICAL)
|
|
96
|
+
* @param {number} tokenBudget - Max tokens available for memory hints
|
|
97
|
+
* @returns {Promise<Array<{content: string, source: string, relevance: number, tokens: number}>>}
|
|
98
|
+
*/
|
|
99
|
+
async getMemoryHints(agentId, bracket, tokenBudget) {
|
|
100
|
+
try {
|
|
101
|
+
// 1. Bracket check — FRESH needs no memory
|
|
102
|
+
const bracketConfig = BRACKET_LAYER_MAP[bracket];
|
|
103
|
+
if (!bracketConfig || bracketConfig.layer === 0) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 2. Calculate effective token budget
|
|
108
|
+
const effectiveBudget = Math.min(
|
|
109
|
+
bracketConfig.maxTokens,
|
|
110
|
+
tokenBudget > 0 ? tokenBudget : bracketConfig.maxTokens,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (effectiveBudget <= 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// 3. Load provider
|
|
118
|
+
const provider = this._getProvider();
|
|
119
|
+
if (!provider) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 4. Execute with timeout protection
|
|
124
|
+
const hints = await this._executeWithTimeout(
|
|
125
|
+
() => provider.getMemories(agentId, bracket, effectiveBudget),
|
|
126
|
+
this._timeout,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// 5. Enforce token budget on results
|
|
130
|
+
return this._enforceTokenBudget(hints || [], effectiveBudget);
|
|
131
|
+
} catch (error) {
|
|
132
|
+
// Catch-all: warn and proceed with empty results
|
|
133
|
+
console.warn(`[synapse:memory-bridge] Error getting memory hints: ${error.message}`);
|
|
134
|
+
return [];
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Execute a function with timeout protection.
|
|
140
|
+
*
|
|
141
|
+
* @private
|
|
142
|
+
* @param {Function} fn - Async function to execute
|
|
143
|
+
* @param {number} timeoutMs - Timeout in milliseconds
|
|
144
|
+
* @returns {Promise<*>} Result or empty array on timeout
|
|
145
|
+
*/
|
|
146
|
+
async _executeWithTimeout(fn, timeoutMs) {
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
const timer = setTimeout(() => {
|
|
149
|
+
console.warn(`[synapse:memory-bridge] Timeout after ${timeoutMs}ms`);
|
|
150
|
+
resolve([]);
|
|
151
|
+
}, timeoutMs);
|
|
152
|
+
|
|
153
|
+
Promise.resolve(fn())
|
|
154
|
+
.then((result) => {
|
|
155
|
+
clearTimeout(timer);
|
|
156
|
+
resolve(result);
|
|
157
|
+
})
|
|
158
|
+
.catch((error) => {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
console.warn(`[synapse:memory-bridge] Provider error: ${error.message}`);
|
|
161
|
+
resolve([]);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Enforce token budget on hint array.
|
|
168
|
+
* Removes hints from end until within budget.
|
|
169
|
+
*
|
|
170
|
+
* @private
|
|
171
|
+
* @param {Array<{content: string, tokens: number}>} hints
|
|
172
|
+
* @param {number} budget
|
|
173
|
+
* @returns {Array}
|
|
174
|
+
*/
|
|
175
|
+
_enforceTokenBudget(hints, budget) {
|
|
176
|
+
if (!Array.isArray(hints) || hints.length === 0) {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const result = [];
|
|
181
|
+
let tokensUsed = 0;
|
|
182
|
+
|
|
183
|
+
for (const hint of hints) {
|
|
184
|
+
const hintTokens = hint.tokens || estimateTokens(hint.content || '');
|
|
185
|
+
if (tokensUsed + hintTokens > budget) {
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
result.push({ ...hint, tokens: hintTokens });
|
|
189
|
+
tokensUsed += hintTokens;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Clear provider cache. Used for testing and session reset.
|
|
197
|
+
*/
|
|
198
|
+
clearCache() {
|
|
199
|
+
if (this._provider && typeof this._provider.clearCache === 'function') {
|
|
200
|
+
this._provider.clearCache();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Reset internal state. Used for testing.
|
|
206
|
+
*
|
|
207
|
+
* @private
|
|
208
|
+
*/
|
|
209
|
+
_reset() {
|
|
210
|
+
this._provider = null;
|
|
211
|
+
this._initialized = false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
module.exports = {
|
|
216
|
+
MemoryBridge,
|
|
217
|
+
BRACKET_LAYER_MAP,
|
|
218
|
+
BRIDGE_TIMEOUT_MS,
|
|
219
|
+
DEFAULT_SECTORS,
|
|
220
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synapse Memory Provider — MIS retrieval for SYNAPSE engine.
|
|
3
|
+
*
|
|
4
|
+
* Implements the provider interface consumed by MemoryBridge.
|
|
5
|
+
* Open-source: no feature gate required.
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Agent-scoped memory retrieval using AGENT_SECTOR_PREFERENCES
|
|
9
|
+
* - Progressive disclosure layer selection based on bracket
|
|
10
|
+
* - Session-level caching (keyed by agentId-bracket)
|
|
11
|
+
* - Token budget respect
|
|
12
|
+
*
|
|
13
|
+
* @module core/synapse/memory/synapse-memory-provider
|
|
14
|
+
* @version 2.0.0
|
|
15
|
+
* @created Story SYN-10 - Pro Memory Bridge (Feature-Gated MIS Consumer)
|
|
16
|
+
* @migrated Story INS-4.11 - Moved from pro/ to open-source (AC9)
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
'use strict';
|
|
20
|
+
|
|
21
|
+
const { estimateTokens } = require('../utils/tokens');
|
|
22
|
+
|
|
23
|
+
/** Default sectors for unknown agents. */
|
|
24
|
+
const DEFAULT_SECTORS = ['semantic'];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Agent sector preferences for memory retrieval.
|
|
28
|
+
* Defines which cognitive sectors each agent prefers.
|
|
29
|
+
*
|
|
30
|
+
* Moved from pro/memory/memory-loader.js to open-source.
|
|
31
|
+
*/
|
|
32
|
+
const AGENT_SECTOR_PREFERENCES = {
|
|
33
|
+
dev: ['procedural', 'semantic'],
|
|
34
|
+
qa: ['reflective', 'episodic'],
|
|
35
|
+
architect: ['semantic', 'reflective'],
|
|
36
|
+
pm: ['episodic', 'semantic'],
|
|
37
|
+
po: ['episodic', 'semantic'],
|
|
38
|
+
sm: ['procedural', 'episodic'],
|
|
39
|
+
devops: ['procedural', 'episodic'],
|
|
40
|
+
analyst: ['semantic', 'reflective'],
|
|
41
|
+
'data-engineer': ['procedural', 'semantic'],
|
|
42
|
+
'ux-design-expert': ['reflective', 'procedural'],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Bracket → retrieval configuration.
|
|
47
|
+
*/
|
|
48
|
+
const BRACKET_CONFIG = {
|
|
49
|
+
MODERATE: { layer: 1, limit: 3, minRelevance: 0.7 },
|
|
50
|
+
DEPLETED: { layer: 2, limit: 5, minRelevance: 0.5 },
|
|
51
|
+
CRITICAL: { layer: 3, limit: 10, minRelevance: 0.3 },
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* SynapseMemoryProvider — Open-source memory retrieval.
|
|
56
|
+
*
|
|
57
|
+
* Provides memories from MIS for SYNAPSE engine injection.
|
|
58
|
+
* Session-level caching avoids repeated MIS queries for
|
|
59
|
+
* the same agent + bracket combination.
|
|
60
|
+
*
|
|
61
|
+
* Uses lazy-loading for MemoryLoader to gracefully degrade
|
|
62
|
+
* when the MIS module is not installed.
|
|
63
|
+
*/
|
|
64
|
+
class SynapseMemoryProvider {
|
|
65
|
+
/**
|
|
66
|
+
* @param {object} [options={}]
|
|
67
|
+
* @param {string} [options.projectDir] - Project directory for MemoryLoader
|
|
68
|
+
*/
|
|
69
|
+
constructor(options = {}) {
|
|
70
|
+
this._projectDir = options.projectDir || process.cwd();
|
|
71
|
+
this._loader = null;
|
|
72
|
+
/** @type {Map<string, Array>} Session-level cache keyed by `${agentId}-${bracket}` */
|
|
73
|
+
this._cache = new Map();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Lazy-load MemoryLoader.
|
|
78
|
+
* Gracefully returns null if pro/memory module is not available.
|
|
79
|
+
*
|
|
80
|
+
* @private
|
|
81
|
+
* @returns {object|null}
|
|
82
|
+
*/
|
|
83
|
+
_getLoader() {
|
|
84
|
+
if (this._loader) return this._loader;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const { MemoryLoader } = require('../../../../pro/memory/memory-loader');
|
|
88
|
+
this._loader = new MemoryLoader(this._projectDir);
|
|
89
|
+
return this._loader;
|
|
90
|
+
} catch {
|
|
91
|
+
// MIS module not available — graceful degradation
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Get memories for SYNAPSE engine injection.
|
|
98
|
+
*
|
|
99
|
+
* Uses bracket to determine:
|
|
100
|
+
* - Which MIS layer to query (1=metadata, 2=chunks, 3=full)
|
|
101
|
+
* - How many results to return
|
|
102
|
+
* - Minimum relevance threshold
|
|
103
|
+
*
|
|
104
|
+
* Results are cached per session (agentId + bracket).
|
|
105
|
+
*
|
|
106
|
+
* @param {string} agentId - Active agent ID
|
|
107
|
+
* @param {string} bracket - Context bracket (MODERATE, DEPLETED, CRITICAL)
|
|
108
|
+
* @param {number} tokenBudget - Max tokens for memory hints
|
|
109
|
+
* @returns {Promise<Array<{content: string, source: string, relevance: number, tokens: number}>>}
|
|
110
|
+
*/
|
|
111
|
+
async getMemories(agentId, bracket, tokenBudget) {
|
|
112
|
+
// Cache lookup
|
|
113
|
+
const cacheKey = `${agentId}-${bracket}`;
|
|
114
|
+
if (this._cache.has(cacheKey)) {
|
|
115
|
+
return this._cache.get(cacheKey);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Get bracket config
|
|
119
|
+
const config = BRACKET_CONFIG[bracket];
|
|
120
|
+
if (!config) {
|
|
121
|
+
return [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Get loader (lazy-load, graceful if unavailable)
|
|
125
|
+
const loader = this._getLoader();
|
|
126
|
+
if (!loader) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Get agent sectors
|
|
131
|
+
const sectors = AGENT_SECTOR_PREFERENCES[agentId] || DEFAULT_SECTORS;
|
|
132
|
+
|
|
133
|
+
// Query MIS via MemoryLoader
|
|
134
|
+
const memories = await loader.queryMemories(agentId, {
|
|
135
|
+
sectors,
|
|
136
|
+
layer: config.layer,
|
|
137
|
+
limit: config.limit,
|
|
138
|
+
minRelevance: config.minRelevance,
|
|
139
|
+
tokenBudget,
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Transform to hint format
|
|
143
|
+
const hints = this._transformToHints(memories, tokenBudget);
|
|
144
|
+
|
|
145
|
+
// Cache results
|
|
146
|
+
this._cache.set(cacheKey, hints);
|
|
147
|
+
|
|
148
|
+
return hints;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Transform MIS memory results into hint format.
|
|
153
|
+
*
|
|
154
|
+
* @private
|
|
155
|
+
* @param {Array} memories - Raw memories from MemoryLoader
|
|
156
|
+
* @param {number} tokenBudget - Max tokens
|
|
157
|
+
* @returns {Array<{content: string, source: string, relevance: number, tokens: number}>}
|
|
158
|
+
*/
|
|
159
|
+
_transformToHints(memories, tokenBudget) {
|
|
160
|
+
if (!Array.isArray(memories) || memories.length === 0) {
|
|
161
|
+
return [];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const hints = [];
|
|
165
|
+
let tokensUsed = 0;
|
|
166
|
+
|
|
167
|
+
for (const memory of memories) {
|
|
168
|
+
const content = memory.content || memory.summary || memory.title || '';
|
|
169
|
+
const tokens = estimateTokens(content);
|
|
170
|
+
|
|
171
|
+
if (tokensUsed + tokens > tokenBudget) {
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
hints.push({
|
|
176
|
+
content,
|
|
177
|
+
source: memory.source || memory.sector || 'memory',
|
|
178
|
+
relevance: memory.relevance || memory.attention || 0,
|
|
179
|
+
tokens,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
tokensUsed += tokens;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return hints;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Clear the session cache.
|
|
190
|
+
*/
|
|
191
|
+
clearCache() {
|
|
192
|
+
this._cache.clear();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
module.exports = {
|
|
197
|
+
SynapseMemoryProvider,
|
|
198
|
+
AGENT_SECTOR_PREFERENCES,
|
|
199
|
+
BRACKET_CONFIG,
|
|
200
|
+
DEFAULT_SECTORS,
|
|
201
|
+
};
|