@stackmemoryai/stackmemory 1.2.1 → 1.2.4
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/dist/src/cli/codex-sm.js +6 -8
- package/dist/src/cli/commands/config.js +0 -81
- package/dist/src/cli/commands/context-rehydrate.js +133 -47
- package/dist/src/cli/commands/db.js +35 -8
- package/dist/src/cli/commands/handoff.js +1 -1
- package/dist/src/cli/commands/linear.js +9 -0
- package/dist/src/cli/commands/ralph.js +2 -2
- package/dist/src/cli/commands/setup.js +2 -2
- package/dist/src/cli/commands/signup.js +3 -1
- package/dist/src/cli/commands/skills.js +123 -1
- package/dist/src/cli/commands/storage-tier.js +26 -8
- package/dist/src/cli/index.js +1 -57
- package/dist/src/core/config/feature-flags.js +0 -4
- package/dist/src/core/context/dual-stack-manager.js +10 -3
- package/dist/src/core/context/frame-database.js +32 -0
- package/dist/src/core/context/frame-handoff-manager.js +2 -2
- package/dist/src/core/context/{refactored-frame-manager.js → frame-manager.js} +3 -3
- package/dist/src/core/context/index.js +2 -2
- package/dist/src/core/database/sqlite-adapter.js +161 -1
- package/dist/src/core/digest/frame-digest-integration.js +1 -1
- package/dist/src/core/digest/index.js +1 -1
- package/dist/src/core/execution/parallel-executor.js +5 -1
- package/dist/src/core/projects/project-isolation.js +18 -4
- package/dist/src/core/security/index.js +2 -0
- package/dist/src/core/security/input-sanitizer.js +23 -0
- package/dist/src/core/utils/update-checker.js +10 -6
- package/dist/src/daemon/daemon-config.js +2 -1
- package/dist/src/daemon/services/auto-save-service.js +121 -0
- package/dist/src/daemon/services/maintenance-service.js +76 -1
- package/dist/src/features/sweep/prompt-builder.js +2 -2
- package/dist/src/hooks/graphiti-hooks.js +149 -0
- package/dist/src/hooks/session-summary.js +30 -0
- package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +115 -0
- package/dist/src/integrations/greptile/client.js +101 -0
- package/dist/src/integrations/greptile/config.js +14 -0
- package/dist/src/integrations/greptile/index.js +11 -0
- package/dist/src/integrations/greptile/types.js +4 -0
- package/dist/src/integrations/linear/config.js +3 -1
- package/dist/src/integrations/linear/sync.js +18 -5
- package/dist/src/integrations/linear/webhook.js +16 -0
- package/dist/src/integrations/mcp/handlers/code-execution-handlers.js +33 -7
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +397 -0
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +456 -0
- package/dist/src/integrations/mcp/handlers/index.js +55 -1
- package/dist/src/integrations/mcp/handlers/task-handlers.js +55 -12
- package/dist/src/integrations/mcp/handlers/team-handlers.js +211 -0
- package/dist/src/integrations/mcp/handlers/trace-handlers.js +25 -9
- package/dist/src/integrations/mcp/index.js +2 -2
- package/dist/src/integrations/mcp/refactored-server.js +31 -10
- package/dist/src/integrations/mcp/server.js +27 -0
- package/dist/src/integrations/mcp/tool-definitions.js +215 -1
- package/dist/src/integrations/ralph/context/context-budget-manager.js +10 -2
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +54 -22
- package/dist/src/integrations/ralph/learning/pattern-learner.js +59 -24
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +81 -35
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +12 -4
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +32 -9
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +25 -8
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +17 -5
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +73 -22
- package/dist/src/skills/claude-skills.js +46 -103
- package/dist/src/skills/parallel-agent-skill.js +514 -0
- package/dist/src/utils/hook-installer.js +8 -0
- package/package.json +5 -5
- package/scripts/gepa/.before-optimize.md +140 -159
- package/scripts/gepa/config.json +7 -1
- package/scripts/gepa/evals/fixtures/api-endpoint.ts +31 -0
- package/scripts/gepa/evals/fixtures/brittle-integration.ts +38 -0
- package/scripts/gepa/evals/fixtures/fts5-triggers.sql +23 -0
- package/scripts/gepa/evals/fixtures/leaky-service.ts +70 -0
- package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +39 -0
- package/scripts/gepa/evals/fixtures/pr-diff.txt +24 -0
- package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +34 -0
- package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +42 -0
- package/scripts/gepa/evals/stackmemory-tasks.jsonl +8 -0
- package/scripts/gepa/generations/gen-000/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/variant-a.md +156 -146
- package/scripts/gepa/generations/gen-001/variant-b.md +199 -170
- package/scripts/gepa/generations/gen-001/variant-c.md +127 -46
- package/scripts/gepa/generations/gen-001/variant-d.md +160 -107
- package/scripts/gepa/hooks/reflect.js +44 -5
- package/scripts/gepa/optimize.js +281 -39
- package/scripts/gepa/results/eval-1-baseline.json +187 -10
- package/scripts/gepa/results/eval-1-variant-a.json +188 -11
- package/scripts/gepa/results/eval-1-variant-b.json +188 -11
- package/scripts/gepa/results/eval-1-variant-c.json +168 -11
- package/scripts/gepa/results/eval-1-variant-d.json +169 -12
- package/scripts/gepa/state.json +18 -18
- package/scripts/install-claude-hooks-auto.js +8 -0
- package/templates/claude-hooks/cord-trace.js +225 -0
- package/dist/src/core/config/storage-config.js +0 -114
- package/dist/src/core/storage/chromadb-adapter.js +0 -379
- package/dist/src/integrations/claude-code/enhanced-pre-clear-hooks.js +0 -458
- package/dist/src/integrations/ralph/coordination/enhanced-coordination.js +0 -409
- package/dist/src/skills/repo-ingestion-skill.js +0 -631
- package/templates/claude-hooks/chromadb-wrapper +0 -21
- /package/dist/src/core/context/{enhanced-rehydration.js → rehydration.js} +0 -0
- /package/dist/src/core/digest/{enhanced-hybrid-digest.js → hybrid-digest.js} +0 -0
- /package/dist/src/core/session/{enhanced-handoff.js → handoff.js} +0 -0
|
@@ -14,7 +14,9 @@ class MCPToolDefinitions {
|
|
|
14
14
|
...this.getTraceTools(),
|
|
15
15
|
...this.getDiscoveryTools(),
|
|
16
16
|
...this.getEditTools(),
|
|
17
|
-
...this.getGraphitiTools()
|
|
17
|
+
...this.getGraphitiTools(),
|
|
18
|
+
...this.getTeamTools(),
|
|
19
|
+
...this.getCordTools()
|
|
18
20
|
];
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
@@ -755,6 +757,214 @@ class MCPToolDefinitions {
|
|
|
755
757
|
}
|
|
756
758
|
];
|
|
757
759
|
}
|
|
760
|
+
/**
|
|
761
|
+
* Multi-agent team collaboration tools
|
|
762
|
+
*/
|
|
763
|
+
getTeamTools() {
|
|
764
|
+
return [
|
|
765
|
+
{
|
|
766
|
+
name: "team_context_get",
|
|
767
|
+
description: "Get context from other agents working on the same project. Returns recent frames and shared anchors from other sessions.",
|
|
768
|
+
inputSchema: {
|
|
769
|
+
type: "object",
|
|
770
|
+
properties: {
|
|
771
|
+
limit: {
|
|
772
|
+
type: "number",
|
|
773
|
+
default: 10,
|
|
774
|
+
description: "Max frames to return"
|
|
775
|
+
},
|
|
776
|
+
types: {
|
|
777
|
+
type: "array",
|
|
778
|
+
items: { type: "string" },
|
|
779
|
+
description: "Filter by frame types"
|
|
780
|
+
},
|
|
781
|
+
since: {
|
|
782
|
+
type: "number",
|
|
783
|
+
description: "Only frames created after this timestamp (epoch ms)"
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
},
|
|
788
|
+
{
|
|
789
|
+
name: "team_context_share",
|
|
790
|
+
description: "Share a piece of context with other agents working on the same project. Creates a high-priority anchor visible to team_context_get.",
|
|
791
|
+
inputSchema: {
|
|
792
|
+
type: "object",
|
|
793
|
+
properties: {
|
|
794
|
+
content: {
|
|
795
|
+
type: "string",
|
|
796
|
+
description: "The context to share"
|
|
797
|
+
},
|
|
798
|
+
type: {
|
|
799
|
+
type: "string",
|
|
800
|
+
enum: [
|
|
801
|
+
"FACT",
|
|
802
|
+
"DECISION",
|
|
803
|
+
"CONSTRAINT",
|
|
804
|
+
"INTERFACE_CONTRACT",
|
|
805
|
+
"TODO",
|
|
806
|
+
"RISK"
|
|
807
|
+
],
|
|
808
|
+
default: "FACT",
|
|
809
|
+
description: "Type of context"
|
|
810
|
+
},
|
|
811
|
+
priority: {
|
|
812
|
+
type: "number",
|
|
813
|
+
minimum: 1,
|
|
814
|
+
maximum: 10,
|
|
815
|
+
default: 8,
|
|
816
|
+
description: "Priority level (1-10)"
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
required: ["content"]
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
name: "team_search",
|
|
824
|
+
description: "Search across all agents' context in the project. Uses full-text search across all sessions.",
|
|
825
|
+
inputSchema: {
|
|
826
|
+
type: "object",
|
|
827
|
+
properties: {
|
|
828
|
+
query: {
|
|
829
|
+
type: "string",
|
|
830
|
+
description: "Search query"
|
|
831
|
+
},
|
|
832
|
+
limit: {
|
|
833
|
+
type: "number",
|
|
834
|
+
default: 20,
|
|
835
|
+
description: "Maximum results to return"
|
|
836
|
+
},
|
|
837
|
+
include_events: {
|
|
838
|
+
type: "boolean",
|
|
839
|
+
default: false,
|
|
840
|
+
description: "Include events in results"
|
|
841
|
+
}
|
|
842
|
+
},
|
|
843
|
+
required: ["query"]
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
];
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Cord task orchestration tools
|
|
850
|
+
*/
|
|
851
|
+
getCordTools() {
|
|
852
|
+
return [
|
|
853
|
+
{
|
|
854
|
+
name: "cord_spawn",
|
|
855
|
+
description: "Create a subtask with clean context (spawn). Child sees only its prompt and completed blocker results.",
|
|
856
|
+
inputSchema: {
|
|
857
|
+
type: "object",
|
|
858
|
+
properties: {
|
|
859
|
+
goal: {
|
|
860
|
+
type: "string",
|
|
861
|
+
description: "What this task should accomplish"
|
|
862
|
+
},
|
|
863
|
+
prompt: {
|
|
864
|
+
type: "string",
|
|
865
|
+
description: "Detailed instructions for the task"
|
|
866
|
+
},
|
|
867
|
+
blocked_by: {
|
|
868
|
+
type: "array",
|
|
869
|
+
items: { type: "string" },
|
|
870
|
+
description: "Task IDs that must complete before this can start"
|
|
871
|
+
},
|
|
872
|
+
parent_id: {
|
|
873
|
+
type: "string",
|
|
874
|
+
description: "Parent task ID"
|
|
875
|
+
}
|
|
876
|
+
},
|
|
877
|
+
required: ["goal"]
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
name: "cord_fork",
|
|
882
|
+
description: "Create a subtask with full sibling context (fork). Child sees its prompt, blocker results, AND completed sibling results.",
|
|
883
|
+
inputSchema: {
|
|
884
|
+
type: "object",
|
|
885
|
+
properties: {
|
|
886
|
+
goal: {
|
|
887
|
+
type: "string",
|
|
888
|
+
description: "What this task should accomplish"
|
|
889
|
+
},
|
|
890
|
+
prompt: {
|
|
891
|
+
type: "string",
|
|
892
|
+
description: "Detailed instructions for the task"
|
|
893
|
+
},
|
|
894
|
+
blocked_by: {
|
|
895
|
+
type: "array",
|
|
896
|
+
items: { type: "string" },
|
|
897
|
+
description: "Task IDs that must complete before this can start"
|
|
898
|
+
},
|
|
899
|
+
parent_id: {
|
|
900
|
+
type: "string",
|
|
901
|
+
description: "Parent task ID"
|
|
902
|
+
}
|
|
903
|
+
},
|
|
904
|
+
required: ["goal"]
|
|
905
|
+
}
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
name: "cord_complete",
|
|
909
|
+
description: "Mark a cord task as completed with a result. Automatically unblocks dependent tasks.",
|
|
910
|
+
inputSchema: {
|
|
911
|
+
type: "object",
|
|
912
|
+
properties: {
|
|
913
|
+
task_id: {
|
|
914
|
+
type: "string",
|
|
915
|
+
description: "Task ID to complete"
|
|
916
|
+
},
|
|
917
|
+
result: {
|
|
918
|
+
type: "string",
|
|
919
|
+
description: "The result/output of this task"
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
required: ["task_id", "result"]
|
|
923
|
+
}
|
|
924
|
+
},
|
|
925
|
+
{
|
|
926
|
+
name: "cord_ask",
|
|
927
|
+
description: "Create an ask task \u2014 a question that needs an answer before dependent tasks can proceed.",
|
|
928
|
+
inputSchema: {
|
|
929
|
+
type: "object",
|
|
930
|
+
properties: {
|
|
931
|
+
question: {
|
|
932
|
+
type: "string",
|
|
933
|
+
description: "The question to ask"
|
|
934
|
+
},
|
|
935
|
+
options: {
|
|
936
|
+
type: "array",
|
|
937
|
+
items: { type: "string" },
|
|
938
|
+
description: "Optional list of answer choices"
|
|
939
|
+
},
|
|
940
|
+
parent_id: {
|
|
941
|
+
type: "string",
|
|
942
|
+
description: "Parent task ID"
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
required: ["question"]
|
|
946
|
+
}
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
name: "cord_tree",
|
|
950
|
+
description: "View the cord task tree with context scoping. Shows which tasks are active, blocked, or completed.",
|
|
951
|
+
inputSchema: {
|
|
952
|
+
type: "object",
|
|
953
|
+
properties: {
|
|
954
|
+
task_id: {
|
|
955
|
+
type: "string",
|
|
956
|
+
description: "Root task ID to show subtree (omit for full project tree)"
|
|
957
|
+
},
|
|
958
|
+
include_results: {
|
|
959
|
+
type: "boolean",
|
|
960
|
+
default: false,
|
|
961
|
+
description: "Include task results in output"
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
];
|
|
967
|
+
}
|
|
758
968
|
/**
|
|
759
969
|
* Get tool definition by name
|
|
760
970
|
*/
|
|
@@ -780,6 +990,10 @@ class MCPToolDefinitions {
|
|
|
780
990
|
return this.getEditTools();
|
|
781
991
|
case "graphiti":
|
|
782
992
|
return this.getGraphitiTools();
|
|
993
|
+
case "team":
|
|
994
|
+
return this.getTeamTools();
|
|
995
|
+
case "cord":
|
|
996
|
+
return this.getCordTools();
|
|
783
997
|
default:
|
|
784
998
|
return [];
|
|
785
999
|
}
|
|
@@ -115,14 +115,22 @@ class ContextBudgetManager {
|
|
|
115
115
|
const reductionRatio = this.config.maxTokens / currentTokens;
|
|
116
116
|
const phase = this.determinePhase(context.task.currentIteration);
|
|
117
117
|
const adjustedWeights = this.getPhaseAdjustedWeights(phase);
|
|
118
|
-
return this.applyWeightedReduction(
|
|
118
|
+
return this.applyWeightedReduction(
|
|
119
|
+
context,
|
|
120
|
+
reductionRatio,
|
|
121
|
+
adjustedWeights
|
|
122
|
+
);
|
|
119
123
|
}
|
|
120
124
|
/**
|
|
121
125
|
* Priority-based allocation using fixed weights
|
|
122
126
|
*/
|
|
123
127
|
priorityBasedAllocation(context, currentTokens) {
|
|
124
128
|
const reductionRatio = this.config.maxTokens / currentTokens;
|
|
125
|
-
return this.applyWeightedReduction(
|
|
129
|
+
return this.applyWeightedReduction(
|
|
130
|
+
context,
|
|
131
|
+
reductionRatio,
|
|
132
|
+
this.config.priorityWeights
|
|
133
|
+
);
|
|
126
134
|
}
|
|
127
135
|
/**
|
|
128
136
|
* Apply weighted reduction to context
|
|
@@ -46,7 +46,10 @@ class StackMemoryContextLoader {
|
|
|
46
46
|
await sharedContextLayer.initialize();
|
|
47
47
|
const session = await sessionManager.getOrCreateSession({});
|
|
48
48
|
if (session.database) {
|
|
49
|
-
this.frameManager = new FrameManager(
|
|
49
|
+
this.frameManager = new FrameManager(
|
|
50
|
+
session.database,
|
|
51
|
+
session.projectId
|
|
52
|
+
);
|
|
50
53
|
this.contextRetriever = new ContextRetriever(session.database);
|
|
51
54
|
}
|
|
52
55
|
logger.info("Context loader initialized successfully");
|
|
@@ -115,17 +118,25 @@ class StackMemoryContextLoader {
|
|
|
115
118
|
totalTokens += sources[sources.length - 1].tokens;
|
|
116
119
|
}
|
|
117
120
|
const budgetedSources = this.budgetManager.allocateBudget({ sources });
|
|
118
|
-
const synthesizedContext = this.synthesizeContext(
|
|
121
|
+
const synthesizedContext = this.synthesizeContext(
|
|
122
|
+
budgetedSources.sources
|
|
123
|
+
);
|
|
119
124
|
logger.info("Context loaded successfully", {
|
|
120
125
|
totalSources: sources.length,
|
|
121
126
|
totalTokens,
|
|
122
|
-
budgetedTokens: budgetedSources.sources.reduce(
|
|
127
|
+
budgetedTokens: budgetedSources.sources.reduce(
|
|
128
|
+
(sum, s) => sum + s.tokens,
|
|
129
|
+
0
|
|
130
|
+
)
|
|
123
131
|
});
|
|
124
132
|
return {
|
|
125
133
|
context: synthesizedContext,
|
|
126
134
|
sources: budgetedSources.sources,
|
|
127
135
|
metadata: {
|
|
128
|
-
totalTokens: budgetedSources.sources.reduce(
|
|
136
|
+
totalTokens: budgetedSources.sources.reduce(
|
|
137
|
+
(sum, s) => sum + s.tokens,
|
|
138
|
+
0
|
|
139
|
+
),
|
|
129
140
|
sourcesCount: budgetedSources.sources.length,
|
|
130
141
|
patterns: request.usePatterns ? patterns : [],
|
|
131
142
|
similarTasks: request.useSimilarTasks ? similarTasks : []
|
|
@@ -144,16 +155,22 @@ class StackMemoryContextLoader {
|
|
|
144
155
|
return [];
|
|
145
156
|
}
|
|
146
157
|
try {
|
|
147
|
-
const searchResults = await this.contextRetriever.search(
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
158
|
+
const searchResults = await this.contextRetriever.search(
|
|
159
|
+
taskDescription,
|
|
160
|
+
{
|
|
161
|
+
maxResults: 10,
|
|
162
|
+
types: ["task", "subtask"],
|
|
163
|
+
timeFilter: {
|
|
164
|
+
days: this.config.lookbackDays
|
|
165
|
+
}
|
|
152
166
|
}
|
|
153
|
-
|
|
167
|
+
);
|
|
154
168
|
const similarities = [];
|
|
155
169
|
for (const result of searchResults) {
|
|
156
|
-
const similarity = this.calculateTaskSimilarity(
|
|
170
|
+
const similarity = this.calculateTaskSimilarity(
|
|
171
|
+
taskDescription,
|
|
172
|
+
result.content
|
|
173
|
+
);
|
|
157
174
|
if (similarity >= this.config.similarityThreshold) {
|
|
158
175
|
similarities.push({
|
|
159
176
|
frameId: result.frameId,
|
|
@@ -184,7 +201,10 @@ class StackMemoryContextLoader {
|
|
|
184
201
|
if (!context) return [];
|
|
185
202
|
const relevantPatterns = [];
|
|
186
203
|
for (const pattern of context.globalPatterns) {
|
|
187
|
-
const relevance = this.calculatePatternRelevance(
|
|
204
|
+
const relevance = this.calculatePatternRelevance(
|
|
205
|
+
taskDescription,
|
|
206
|
+
pattern.pattern
|
|
207
|
+
);
|
|
188
208
|
if (relevance >= 0.5) {
|
|
189
209
|
relevantPatterns.push({
|
|
190
210
|
pattern: pattern.pattern,
|
|
@@ -197,7 +217,9 @@ class StackMemoryContextLoader {
|
|
|
197
217
|
});
|
|
198
218
|
}
|
|
199
219
|
}
|
|
200
|
-
return relevantPatterns.sort(
|
|
220
|
+
return relevantPatterns.sort(
|
|
221
|
+
(a, b) => b.relevance * Math.log(b.frequency + 1) - a.relevance * Math.log(a.frequency + 1)
|
|
222
|
+
).slice(0, 8);
|
|
201
223
|
} catch (error) {
|
|
202
224
|
logger.error("Failed to extract patterns", error);
|
|
203
225
|
return [];
|
|
@@ -270,12 +292,14 @@ class StackMemoryContextLoader {
|
|
|
270
292
|
const contextParts = [];
|
|
271
293
|
contextParts.push("Similar tasks from history:");
|
|
272
294
|
for (const sim of similarities) {
|
|
273
|
-
contextParts.push(
|
|
295
|
+
contextParts.push(
|
|
296
|
+
`
|
|
274
297
|
Task: ${sim.task}
|
|
275
298
|
Outcome: ${sim.outcome}
|
|
276
299
|
Similarity: ${Math.round(sim.similarity * 100)}%
|
|
277
300
|
${sim.outcome === "success" ? "\u2705 Successfully completed" : "\u274C Had issues"}
|
|
278
|
-
`.trim()
|
|
301
|
+
`.trim()
|
|
302
|
+
);
|
|
279
303
|
}
|
|
280
304
|
return contextParts.join("\n\n");
|
|
281
305
|
}
|
|
@@ -286,13 +310,15 @@ ${sim.outcome === "success" ? "\u2705 Successfully completed" : "\u274C Had issu
|
|
|
286
310
|
const contextParts = [];
|
|
287
311
|
contextParts.push("Relevant patterns from experience:");
|
|
288
312
|
for (const pattern of patterns2) {
|
|
289
|
-
contextParts.push(
|
|
313
|
+
contextParts.push(
|
|
314
|
+
`
|
|
290
315
|
Pattern: ${pattern.pattern}
|
|
291
316
|
Type: ${pattern.type}
|
|
292
317
|
Frequency: ${pattern.frequency} occurrences
|
|
293
318
|
${pattern.resolution ? `Resolution: ${pattern.resolution}` : ""}
|
|
294
319
|
Relevance: ${Math.round(pattern.relevance * 100)}%
|
|
295
|
-
`.trim()
|
|
320
|
+
`.trim()
|
|
321
|
+
);
|
|
296
322
|
}
|
|
297
323
|
return contextParts.join("\n\n");
|
|
298
324
|
}
|
|
@@ -303,11 +329,13 @@ Relevance: ${Math.round(pattern.relevance * 100)}%
|
|
|
303
329
|
const contextParts = [];
|
|
304
330
|
contextParts.push("Recent successful decisions:");
|
|
305
331
|
for (const decision of decisions) {
|
|
306
|
-
contextParts.push(
|
|
332
|
+
contextParts.push(
|
|
333
|
+
`
|
|
307
334
|
Decision: ${decision.decision}
|
|
308
335
|
Reasoning: ${decision.reasoning}
|
|
309
336
|
Date: ${new Date(decision.timestamp).toLocaleDateString()}
|
|
310
|
-
`.trim()
|
|
337
|
+
`.trim()
|
|
338
|
+
);
|
|
311
339
|
}
|
|
312
340
|
return contextParts.join("\n\n");
|
|
313
341
|
}
|
|
@@ -322,11 +350,15 @@ Date: ${new Date(decision.timestamp).toLocaleDateString()}
|
|
|
322
350
|
contextParts.push("Context from StackMemory:");
|
|
323
351
|
const sortedSources = sources.sort((a, b) => b.weight - a.weight);
|
|
324
352
|
for (const source of sortedSources) {
|
|
325
|
-
contextParts.push(
|
|
326
|
-
|
|
353
|
+
contextParts.push(
|
|
354
|
+
`
|
|
355
|
+
--- ${source.type.replace("_", " ").toUpperCase()} ---`
|
|
356
|
+
);
|
|
327
357
|
contextParts.push(source.content);
|
|
328
358
|
}
|
|
329
|
-
contextParts.push(
|
|
359
|
+
contextParts.push(
|
|
360
|
+
"\nUse this context to inform your approach to the current task."
|
|
361
|
+
);
|
|
330
362
|
return contextParts.join("\n");
|
|
331
363
|
}
|
|
332
364
|
/**
|
|
@@ -25,7 +25,10 @@ class PatternLearner {
|
|
|
25
25
|
await sharedContextLayer.initialize();
|
|
26
26
|
const session = await sessionManager.getOrCreateSession({});
|
|
27
27
|
if (session.database) {
|
|
28
|
-
this.frameManager = new FrameManager(
|
|
28
|
+
this.frameManager = new FrameManager(
|
|
29
|
+
session.database,
|
|
30
|
+
session.projectId
|
|
31
|
+
);
|
|
29
32
|
}
|
|
30
33
|
logger.info("Pattern learner initialized successfully");
|
|
31
34
|
} catch (error) {
|
|
@@ -40,7 +43,9 @@ class PatternLearner {
|
|
|
40
43
|
logger.info("Starting pattern learning from completed loops");
|
|
41
44
|
try {
|
|
42
45
|
const completedLoops = await this.getCompletedRalphLoops();
|
|
43
|
-
logger.info(
|
|
46
|
+
logger.info(
|
|
47
|
+
`Found ${completedLoops.length} completed loops for analysis`
|
|
48
|
+
);
|
|
44
49
|
if (completedLoops.length < this.config.minLoopCountForPattern) {
|
|
45
50
|
logger.info("Not enough loops for pattern extraction");
|
|
46
51
|
return [];
|
|
@@ -55,7 +60,9 @@ class PatternLearner {
|
|
|
55
60
|
const taskPatterns = await this.extractTaskPatterns(completedLoops);
|
|
56
61
|
patterns.push(...taskPatterns);
|
|
57
62
|
await this.saveLearnedPatterns(patterns);
|
|
58
|
-
logger.info(
|
|
63
|
+
logger.info(
|
|
64
|
+
`Learned ${patterns.length} patterns from ${completedLoops.length} loops`
|
|
65
|
+
);
|
|
59
66
|
return patterns;
|
|
60
67
|
} catch (error) {
|
|
61
68
|
logger.error("Failed to learn patterns", error);
|
|
@@ -97,7 +104,10 @@ class PatternLearner {
|
|
|
97
104
|
analyses.push(analysis);
|
|
98
105
|
}
|
|
99
106
|
} catch (error) {
|
|
100
|
-
logger.warn(
|
|
107
|
+
logger.warn(
|
|
108
|
+
`Failed to analyze loop ${frame.frame_id}`,
|
|
109
|
+
error
|
|
110
|
+
);
|
|
101
111
|
}
|
|
102
112
|
}
|
|
103
113
|
return analyses;
|
|
@@ -159,15 +169,21 @@ class PatternLearner {
|
|
|
159
169
|
examples: successfulLoops.slice(0, 3).map((l) => l.task),
|
|
160
170
|
metadata: {
|
|
161
171
|
avgIterations,
|
|
162
|
-
minIterations: Math.min(
|
|
163
|
-
|
|
172
|
+
minIterations: Math.min(
|
|
173
|
+
...successfulLoops.map((l) => l.iterationCount)
|
|
174
|
+
),
|
|
175
|
+
maxIterations: Math.max(
|
|
176
|
+
...successfulLoops.map((l) => l.iterationCount)
|
|
177
|
+
)
|
|
164
178
|
}
|
|
165
179
|
});
|
|
166
180
|
const criteriaPatterns = this.extractCriteriaPatterns(successfulLoops);
|
|
167
181
|
patterns.push(...criteriaPatterns);
|
|
168
182
|
const successFactors = this.extractSuccessFactors(successfulLoops);
|
|
169
183
|
patterns.push(...successFactors);
|
|
170
|
-
return patterns.filter(
|
|
184
|
+
return patterns.filter(
|
|
185
|
+
(p) => p.confidence >= this.config.confidenceThreshold
|
|
186
|
+
);
|
|
171
187
|
}
|
|
172
188
|
/**
|
|
173
189
|
* Extract patterns from failed loops to avoid
|
|
@@ -191,7 +207,9 @@ class PatternLearner {
|
|
|
191
207
|
metadata: { failureType: failure.type }
|
|
192
208
|
});
|
|
193
209
|
}
|
|
194
|
-
return patterns.filter(
|
|
210
|
+
return patterns.filter(
|
|
211
|
+
(p) => p.confidence >= this.config.confidenceThreshold
|
|
212
|
+
);
|
|
195
213
|
}
|
|
196
214
|
/**
|
|
197
215
|
* Extract iteration-specific patterns
|
|
@@ -223,7 +241,10 @@ class PatternLearner {
|
|
|
223
241
|
const patterns = [];
|
|
224
242
|
for (const [taskType, taskLoops] of Object.entries(taskGroups)) {
|
|
225
243
|
if (taskLoops.length >= this.config.minLoopCountForPattern) {
|
|
226
|
-
const taskSpecificPatterns = await this.extractSpecializedPatterns(
|
|
244
|
+
const taskSpecificPatterns = await this.extractSpecializedPatterns(
|
|
245
|
+
taskLoops,
|
|
246
|
+
taskType
|
|
247
|
+
);
|
|
227
248
|
patterns.push(...taskSpecificPatterns);
|
|
228
249
|
}
|
|
229
250
|
}
|
|
@@ -266,12 +287,15 @@ class PatternLearner {
|
|
|
266
287
|
*/
|
|
267
288
|
classifyTaskType(task) {
|
|
268
289
|
const taskLower = task.toLowerCase();
|
|
269
|
-
if (taskLower.includes("test") || taskLower.includes("unit"))
|
|
290
|
+
if (taskLower.includes("test") || taskLower.includes("unit"))
|
|
291
|
+
return "testing";
|
|
270
292
|
if (taskLower.includes("fix") || taskLower.includes("bug")) return "bugfix";
|
|
271
293
|
if (taskLower.includes("refactor")) return "refactoring";
|
|
272
|
-
if (taskLower.includes("add") || taskLower.includes("implement"))
|
|
294
|
+
if (taskLower.includes("add") || taskLower.includes("implement"))
|
|
295
|
+
return "feature";
|
|
273
296
|
if (taskLower.includes("document")) return "documentation";
|
|
274
|
-
if (taskLower.includes("optimize") || taskLower.includes("performance"))
|
|
297
|
+
if (taskLower.includes("optimize") || taskLower.includes("performance"))
|
|
298
|
+
return "optimization";
|
|
275
299
|
return "general";
|
|
276
300
|
}
|
|
277
301
|
/**
|
|
@@ -331,7 +355,10 @@ class PatternLearner {
|
|
|
331
355
|
// Additional helper methods for pattern analysis
|
|
332
356
|
analyzeIterations(iterations) {
|
|
333
357
|
return {
|
|
334
|
-
avgDuration: iterations.length > 0 ? iterations.reduce(
|
|
358
|
+
avgDuration: iterations.length > 0 ? iterations.reduce(
|
|
359
|
+
(sum, i) => sum + (i.updated_at - i.created_at),
|
|
360
|
+
0
|
|
361
|
+
) / iterations.length : 0,
|
|
335
362
|
progressPattern: this.extractProgressPattern(iterations),
|
|
336
363
|
commonIssues: this.extractCommonIssues(iterations)
|
|
337
364
|
};
|
|
@@ -347,11 +374,16 @@ class PatternLearner {
|
|
|
347
374
|
return iterations.filter((i) => i.outputs?.errors?.length > 0).flatMap((i) => i.outputs.errors).slice(0, 3);
|
|
348
375
|
}
|
|
349
376
|
extractCriteriaPatterns(loops) {
|
|
350
|
-
const criteriaWords = loops.flatMap(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
377
|
+
const criteriaWords = loops.flatMap(
|
|
378
|
+
(l) => l.criteria.toLowerCase().split(/\s+/)
|
|
379
|
+
);
|
|
380
|
+
const wordCounts = criteriaWords.reduce(
|
|
381
|
+
(acc, word) => {
|
|
382
|
+
acc[word] = (acc[word] || 0) + 1;
|
|
383
|
+
return acc;
|
|
384
|
+
},
|
|
385
|
+
{}
|
|
386
|
+
);
|
|
355
387
|
const commonCriteria = Object.entries(wordCounts).filter(([_, count]) => count >= this.config.minLoopCountForPattern).sort((a, b) => b[1] - a[1]).slice(0, 3);
|
|
356
388
|
return commonCriteria.map(([word, count]) => ({
|
|
357
389
|
id: `criteria-${word}`,
|
|
@@ -374,12 +406,15 @@ class PatternLearner {
|
|
|
374
406
|
return [];
|
|
375
407
|
}
|
|
376
408
|
groupByTaskType(loops) {
|
|
377
|
-
return loops.reduce(
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
409
|
+
return loops.reduce(
|
|
410
|
+
(acc, loop) => {
|
|
411
|
+
const type = loop.taskType;
|
|
412
|
+
if (!acc[type]) acc[type] = [];
|
|
413
|
+
acc[type].push(loop);
|
|
414
|
+
return acc;
|
|
415
|
+
},
|
|
416
|
+
{}
|
|
417
|
+
);
|
|
383
418
|
}
|
|
384
419
|
summarizeSuccessPattern(loops) {
|
|
385
420
|
const avgIterations = loops.reduce((sum, l) => sum + l.iterationCount, 0) / loops.length;
|