@stackmemoryai/stackmemory 1.0.1 → 1.2.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.
Files changed (51) hide show
  1. package/dist/src/cli/claude-sm.js +65 -0
  2. package/dist/src/cli/commands/audit.js +134 -0
  3. package/dist/src/cli/commands/bench.js +252 -0
  4. package/dist/src/cli/commands/dashboard.js +2 -1
  5. package/dist/src/cli/commands/stats.js +118 -0
  6. package/dist/src/cli/index.js +6 -0
  7. package/dist/src/core/config/feature-flags.js +7 -1
  8. package/dist/src/core/context/enhanced-rehydration.js +24 -5
  9. package/dist/src/core/extensions/cerebras-adapter.js +28 -0
  10. package/dist/src/core/extensions/deepinfra-adapter.js +32 -0
  11. package/dist/src/core/extensions/provider-adapter.js +33 -240
  12. package/dist/src/core/models/complexity-scorer.js +154 -0
  13. package/dist/src/core/models/model-router.js +230 -36
  14. package/dist/src/core/models/provider-pricing.js +63 -0
  15. package/dist/src/core/models/sensitive-guard.js +112 -0
  16. package/dist/src/core/monitoring/feedback-loops.js +88 -0
  17. package/dist/src/hooks/schemas.js +12 -1
  18. package/dist/src/integrations/anthropic/batch-client.js +256 -0
  19. package/dist/src/integrations/anthropic/client.js +87 -72
  20. package/dist/src/integrations/claude-code/subagent-client.js +133 -12
  21. package/dist/src/integrations/graphiti/client.js +16 -4
  22. package/dist/src/integrations/mcp/handlers/index.js +25 -1
  23. package/dist/src/integrations/mcp/handlers/provider-handlers.js +227 -0
  24. package/dist/src/integrations/mcp/server.js +316 -1
  25. package/dist/src/integrations/mcp/tool-definitions.js +90 -1
  26. package/dist/src/orchestrators/multimodal/baselines.js +128 -0
  27. package/dist/src/orchestrators/multimodal/constants.js +9 -1
  28. package/dist/src/orchestrators/multimodal/harness.js +86 -6
  29. package/dist/src/orchestrators/multimodal/providers.js +113 -2
  30. package/dist/src/skills/recursive-agent-orchestrator.js +15 -10
  31. package/dist/src/utils/fuzzy-edit.js +162 -0
  32. package/dist/src/utils/hook-installer.js +155 -0
  33. package/package.json +6 -2
  34. package/scripts/gepa/.before-optimize.md +159 -0
  35. package/scripts/gepa/generations/gen-000/baseline.md +159 -124
  36. package/scripts/gepa/generations/gen-001/baseline.md +159 -0
  37. package/scripts/gepa/generations/gen-001/variant-a.md +166 -0
  38. package/scripts/gepa/generations/gen-001/variant-b.md +237 -0
  39. package/scripts/gepa/generations/gen-001/variant-c.md +61 -0
  40. package/scripts/gepa/generations/gen-001/variant-d.md +119 -0
  41. package/scripts/gepa/results/eval-1-baseline.json +41 -0
  42. package/scripts/gepa/results/eval-1-variant-a.json +41 -0
  43. package/scripts/gepa/results/eval-1-variant-b.json +41 -0
  44. package/scripts/gepa/results/eval-1-variant-c.json +41 -0
  45. package/scripts/gepa/results/eval-1-variant-d.json +41 -0
  46. package/scripts/gepa/state.json +41 -2
  47. package/scripts/install-claude-hooks-auto.js +176 -44
  48. package/templates/claude-hooks/auto-checkpoint.js +174 -0
  49. package/templates/claude-hooks/chime-on-stop.sh +22 -0
  50. package/templates/claude-hooks/session-rescue.sh +15 -0
  51. package/templates/claude-hooks/stop-checkpoint.js +120 -0
@@ -32,12 +32,19 @@ class GraphitiClient {
32
32
  const res = await fetch(`${this.endpoint}${path}`, {
33
33
  ...options,
34
34
  signal: controller.signal,
35
- headers: { "Content-Type": "application/json", ...options.headers || {} }
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ ...options.headers || {}
38
+ }
36
39
  });
37
40
  clearTimeout(timeoutId);
38
41
  if (!res.ok) {
39
42
  const msg = await res.text().catch(() => res.statusText);
40
- throw new GraphitiClientError(`Request failed: ${msg}`, "HTTP_ERROR", res.status);
43
+ throw new GraphitiClientError(
44
+ `Request failed: ${msg}`,
45
+ "HTTP_ERROR",
46
+ res.status
47
+ );
41
48
  }
42
49
  return await res.json();
43
50
  } catch (err) {
@@ -53,7 +60,10 @@ class GraphitiClient {
53
60
  }
54
61
  }
55
62
  clearTimeout(timeoutId);
56
- throw new GraphitiClientError(lastError?.message || "Network error", "NETWORK_ERROR");
63
+ throw new GraphitiClientError(
64
+ lastError?.message || "Network error",
65
+ "NETWORK_ERROR"
66
+ );
57
67
  }
58
68
  // Episodes
59
69
  async upsertEpisode(episode) {
@@ -91,7 +101,9 @@ class GraphitiClient {
91
101
  // Health/status
92
102
  async getStatus() {
93
103
  try {
94
- return await this.request(`/status?namespace=${encodeURIComponent(this.namespace)}`);
104
+ return await this.request(
105
+ `/status?namespace=${encodeURIComponent(this.namespace)}`
106
+ );
95
107
  } catch {
96
108
  return { connected: false };
97
109
  }
@@ -15,6 +15,9 @@ import {
15
15
  import {
16
16
  DiscoveryHandlers
17
17
  } from "./discovery-handlers.js";
18
+ import {
19
+ ProviderHandlers
20
+ } from "./provider-handlers.js";
18
21
  import {
19
22
  ContextHandlers as ContextHandlers2
20
23
  } from "./context-handlers.js";
@@ -23,11 +26,13 @@ import {
23
26
  LinearHandlers as LinearHandlers2
24
27
  } from "./linear-handlers.js";
25
28
  import { TraceHandlers as TraceHandlers2 } from "./trace-handlers.js";
29
+ import { ProviderHandlers as ProviderHandlers2 } from "./provider-handlers.js";
26
30
  class MCPHandlerFactory {
27
31
  contextHandlers;
28
32
  taskHandlers;
29
33
  linearHandlers;
30
34
  traceHandlers;
35
+ providerHandlers;
31
36
  constructor(deps) {
32
37
  this.contextHandlers = new ContextHandlers2({
33
38
  frameManager: deps.frameManager
@@ -45,6 +50,7 @@ class MCPHandlerFactory {
45
50
  traceDetector: deps.traceDetector,
46
51
  browserMCP: deps.browserMCP
47
52
  });
53
+ this.providerHandlers = new ProviderHandlers2();
48
54
  }
49
55
  /**
50
56
  * Get handler for a specific tool
@@ -111,6 +117,19 @@ class MCPHandlerFactory {
111
117
  return this.traceHandlers.handleStopBrowserDebug.bind(
112
118
  this.traceHandlers
113
119
  );
120
+ // Provider handlers
121
+ case "delegate_to_model":
122
+ return this.providerHandlers.handleDelegateToModel.bind(
123
+ this.providerHandlers
124
+ );
125
+ case "batch_submit":
126
+ return this.providerHandlers.handleBatchSubmit.bind(
127
+ this.providerHandlers
128
+ );
129
+ case "batch_check":
130
+ return this.providerHandlers.handleBatchCheck.bind(
131
+ this.providerHandlers
132
+ );
114
133
  default:
115
134
  throw new Error(`Unknown tool: ${toolName}`);
116
135
  }
@@ -144,7 +163,11 @@ class MCPHandlerFactory {
144
163
  "start_browser_debug",
145
164
  "take_screenshot",
146
165
  "execute_script",
147
- "stop_browser_debug"
166
+ "stop_browser_debug",
167
+ // Provider tools (conditionally active)
168
+ "delegate_to_model",
169
+ "batch_submit",
170
+ "batch_check"
148
171
  ];
149
172
  }
150
173
  /**
@@ -159,6 +182,7 @@ export {
159
182
  DiscoveryHandlers,
160
183
  LinearHandlers,
161
184
  MCPHandlerFactory,
185
+ ProviderHandlers,
162
186
  TaskHandlers,
163
187
  TraceHandlers
164
188
  };
@@ -0,0 +1,227 @@
1
+ import { fileURLToPath as __fileURLToPath } from 'url';
2
+ import { dirname as __pathDirname } from 'path';
3
+ const __filename = __fileURLToPath(import.meta.url);
4
+ const __dirname = __pathDirname(__filename);
5
+ import { logger } from "../../../core/monitoring/logger.js";
6
+ import { isFeatureEnabled } from "../../../core/config/feature-flags.js";
7
+ import {
8
+ createProvider
9
+ } from "../../../core/extensions/provider-adapter.js";
10
+ import {
11
+ getOptimalProvider
12
+ } from "../../../core/models/model-router.js";
13
+ import { scoreComplexity } from "../../../core/models/complexity-scorer.js";
14
+ import {
15
+ AnthropicBatchClient
16
+ } from "../../anthropic/batch-client.js";
17
+ function errorResponse(err) {
18
+ return {
19
+ content: [{ type: "text", text: JSON.stringify(err, null, 2) }]
20
+ };
21
+ }
22
+ function classifyApiError(error, provider) {
23
+ const msg = error.message || String(error);
24
+ const status = error.status || (msg.match(/(\d{3})/)?.[1] ? parseInt(msg.match(/(\d{3})/)[1]) : void 0);
25
+ if (status === 429) {
26
+ return {
27
+ errorType: "rate_limit",
28
+ message: msg,
29
+ recommendation: `Rate limited by ${provider}. Retry after a delay or switch to a different provider.`,
30
+ provider
31
+ };
32
+ }
33
+ if (status && status >= 500) {
34
+ return {
35
+ errorType: "server_error",
36
+ message: msg,
37
+ recommendation: `${provider} returned a server error. Try a different provider or retry later.`,
38
+ provider
39
+ };
40
+ }
41
+ return {
42
+ errorType: "api_error",
43
+ message: msg,
44
+ recommendation: `API call to ${provider} failed. Check the model name, API key, and base URL.`,
45
+ provider
46
+ };
47
+ }
48
+ class ProviderHandlers {
49
+ batchClient;
50
+ constructor(_deps) {
51
+ }
52
+ getBatchClient() {
53
+ if (!this.batchClient) {
54
+ this.batchClient = new AnthropicBatchClient();
55
+ }
56
+ return this.batchClient;
57
+ }
58
+ /**
59
+ * delegate_to_model — route a prompt to a specific provider+model
60
+ */
61
+ async handleDelegateToModel(args) {
62
+ if (!isFeatureEnabled("multiProvider")) {
63
+ return errorResponse({
64
+ errorType: "feature_disabled",
65
+ message: "Multi-provider routing is disabled.",
66
+ recommendation: "Set STACKMEMORY_MULTI_PROVIDER=true to enable multi-provider routing."
67
+ });
68
+ }
69
+ const taskType = args.taskType || "default";
70
+ const preference = args.provider;
71
+ const complexity = scoreComplexity(args.prompt);
72
+ const optimal = getOptimalProvider(taskType, preference, {
73
+ task: args.prompt
74
+ });
75
+ logger.info("delegate_to_model routing", {
76
+ taskType,
77
+ complexity: complexity.tier,
78
+ score: complexity.score,
79
+ provider: optimal.provider
80
+ });
81
+ const providerModel = args.model || optimal.model;
82
+ const apiKey = process.env[optimal.apiKeyEnv] || "";
83
+ if (!apiKey) {
84
+ return errorResponse({
85
+ errorType: "missing_api_key",
86
+ message: `No API key found for ${optimal.provider} (env: ${optimal.apiKeyEnv})`,
87
+ recommendation: `Set the ${optimal.apiKeyEnv} environment variable or choose a different provider.`,
88
+ provider: optimal.provider
89
+ });
90
+ }
91
+ try {
92
+ const adapter = createProvider(optimal.provider, {
93
+ apiKey,
94
+ baseUrl: optimal.baseUrl
95
+ });
96
+ const messages = [{ role: "user", content: args.prompt }];
97
+ const result = await adapter.complete(messages, {
98
+ model: providerModel,
99
+ maxTokens: args.maxTokens || 4096,
100
+ temperature: args.temperature,
101
+ system: args.system
102
+ });
103
+ const text = result.content.filter((c) => c.type === "text").map((c) => c.text).join("");
104
+ return {
105
+ content: [
106
+ {
107
+ type: "text",
108
+ text: JSON.stringify(
109
+ {
110
+ provider: optimal.provider,
111
+ model: providerModel,
112
+ response: text,
113
+ usage: result.usage
114
+ },
115
+ null,
116
+ 2
117
+ )
118
+ }
119
+ ]
120
+ };
121
+ } catch (error) {
122
+ logger.error("delegate_to_model failed", { error: error.message });
123
+ return errorResponse(classifyApiError(error, optimal.provider));
124
+ }
125
+ }
126
+ /**
127
+ * batch_submit — submit prompts to Anthropic Batch API
128
+ */
129
+ async handleBatchSubmit(args) {
130
+ if (!isFeatureEnabled("multiProvider")) {
131
+ return errorResponse({
132
+ errorType: "feature_disabled",
133
+ message: "Multi-provider routing is disabled.",
134
+ recommendation: "Set STACKMEMORY_MULTI_PROVIDER=true to enable multi-provider routing."
135
+ });
136
+ }
137
+ try {
138
+ const batchClient = this.getBatchClient();
139
+ const requests = args.prompts.map((p) => ({
140
+ custom_id: p.id,
141
+ params: {
142
+ model: p.model || "claude-sonnet-4-5-20250929",
143
+ max_tokens: p.maxTokens || 4096,
144
+ messages: [{ role: "user", content: p.prompt }],
145
+ system: p.system
146
+ }
147
+ }));
148
+ const batchId = await batchClient.submit(requests, args.description);
149
+ return {
150
+ content: [
151
+ {
152
+ type: "text",
153
+ text: JSON.stringify(
154
+ {
155
+ batchId,
156
+ status: "submitted",
157
+ requestCount: requests.length
158
+ },
159
+ null,
160
+ 2
161
+ )
162
+ }
163
+ ]
164
+ };
165
+ } catch (error) {
166
+ return errorResponse({
167
+ errorType: "batch_error",
168
+ message: error.message,
169
+ recommendation: "Check ANTHROPIC_API_KEY and batch request format."
170
+ });
171
+ }
172
+ }
173
+ /**
174
+ * batch_check — poll status / retrieve results
175
+ */
176
+ async handleBatchCheck(args) {
177
+ if (!isFeatureEnabled("multiProvider")) {
178
+ return errorResponse({
179
+ errorType: "feature_disabled",
180
+ message: "Multi-provider routing is disabled.",
181
+ recommendation: "Set STACKMEMORY_MULTI_PROVIDER=true to enable multi-provider routing."
182
+ });
183
+ }
184
+ try {
185
+ const batchClient = this.getBatchClient();
186
+ const job = await batchClient.poll(args.batchId);
187
+ if (args.retrieve && job.processing_status === "ended") {
188
+ const results = await batchClient.retrieve(args.batchId);
189
+ return {
190
+ content: [
191
+ {
192
+ type: "text",
193
+ text: JSON.stringify({ job, results }, null, 2)
194
+ }
195
+ ]
196
+ };
197
+ }
198
+ return {
199
+ content: [
200
+ {
201
+ type: "text",
202
+ text: JSON.stringify(
203
+ {
204
+ batchId: args.batchId,
205
+ status: job.processing_status,
206
+ counts: job.request_counts,
207
+ createdAt: job.created_at,
208
+ endedAt: job.ended_at
209
+ },
210
+ null,
211
+ 2
212
+ )
213
+ }
214
+ ]
215
+ };
216
+ } catch (error) {
217
+ return errorResponse({
218
+ errorType: "batch_error",
219
+ message: error.message,
220
+ recommendation: "Check the batchId is valid and ANTHROPIC_API_KEY is set."
221
+ });
222
+ }
223
+ }
224
+ }
225
+ export {
226
+ ProviderHandlers
227
+ };