genesis-ai-cli 10.7.0 → 10.8.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.
@@ -1907,6 +1907,291 @@ registerAction('econ.promote', async (context) => {
1907
1907
  }
1908
1908
  });
1909
1909
  // ============================================================================
1910
+ // v10.8: AUTONOMOUS REVENUE ACTIONS (Opportunity Discovery & Execution)
1911
+ // ============================================================================
1912
+ /**
1913
+ * opportunity.scan: Scan the web for revenue opportunities.
1914
+ * Uses Brave + Exa to find unmet needs, trending topics, and gaps.
1915
+ * Stores findings in memory for evaluation.
1916
+ */
1917
+ registerAction('opportunity.scan', async (context) => {
1918
+ const start = Date.now();
1919
+ try {
1920
+ const mcp = (0, index_js_1.getMCPClient)();
1921
+ const scanType = context.parameters?.type || 'general';
1922
+ // Define scan queries based on type
1923
+ const queries = {
1924
+ general: [
1925
+ 'micro saas ideas 2025 unmet needs',
1926
+ '"I wish there was" app tool site:reddit.com',
1927
+ 'trending developer tools github stars this week',
1928
+ ],
1929
+ api: [
1930
+ 'most wanted API services developers pay',
1931
+ 'api marketplace popular endpoints pricing',
1932
+ ],
1933
+ content: [
1934
+ 'viral content topics trending 2025',
1935
+ 'newsletter monetization niche ideas',
1936
+ ],
1937
+ npm: [
1938
+ 'npm packages most downloaded this week new',
1939
+ 'javascript library gaps developers need',
1940
+ ],
1941
+ };
1942
+ const searchQueries = queries[scanType] || queries.general;
1943
+ const results = [];
1944
+ // Execute searches in parallel-ish fashion
1945
+ for (const query of searchQueries) {
1946
+ try {
1947
+ const searchResult = await mcp.call('brave-search', 'brave_web_search', {
1948
+ query,
1949
+ count: 5,
1950
+ });
1951
+ results.push({ query, findings: searchResult });
1952
+ }
1953
+ catch (e) {
1954
+ results.push({ query, findings: { error: String(e) } });
1955
+ }
1956
+ }
1957
+ return {
1958
+ success: results.some(r => !r.findings?.error),
1959
+ action: 'opportunity.scan',
1960
+ data: {
1961
+ scanType,
1962
+ queriesExecuted: results.length,
1963
+ results,
1964
+ timestamp: new Date().toISOString(),
1965
+ },
1966
+ duration: Date.now() - start,
1967
+ };
1968
+ }
1969
+ catch (error) {
1970
+ return {
1971
+ success: false,
1972
+ action: 'opportunity.scan',
1973
+ error: error instanceof Error ? error.message : String(error),
1974
+ duration: Date.now() - start,
1975
+ };
1976
+ }
1977
+ });
1978
+ /**
1979
+ * opportunity.evaluate: Evaluate a discovered opportunity.
1980
+ * Uses LLM to assess feasibility, market size, competition, and ethics.
1981
+ */
1982
+ registerAction('opportunity.evaluate', async (context) => {
1983
+ const start = Date.now();
1984
+ try {
1985
+ const opportunity = context.parameters?.opportunity;
1986
+ if (!opportunity) {
1987
+ return {
1988
+ success: false,
1989
+ action: 'opportunity.evaluate',
1990
+ error: 'No opportunity description provided',
1991
+ duration: Date.now() - start,
1992
+ };
1993
+ }
1994
+ const mcp = (0, index_js_1.getMCPClient)();
1995
+ // Search for competition
1996
+ const competitorSearch = await mcp.call('brave-search', 'brave_web_search', {
1997
+ query: `${opportunity} competitors alternatives pricing`,
1998
+ count: 5,
1999
+ });
2000
+ // Evaluate using LLM
2001
+ const evaluation = await mcp.call('openai', 'openai_chat', {
2002
+ model: 'gpt-4o-mini',
2003
+ messages: [{
2004
+ role: 'system',
2005
+ content: 'You are an expert startup evaluator. Analyze the opportunity and return JSON with: feasibility (0-1), marketSize (small/medium/large), competition (none/low/medium/high), ethicalRisk (none/low/medium/high), estimatedRevenue (monthly USD), effortLevel (low/medium/high), recommendation (build/skip/research_more), reasoning (string).'
2006
+ }, {
2007
+ role: 'user',
2008
+ content: `Evaluate this opportunity for an autonomous AI agent to pursue:\n\n${opportunity}\n\nCompetitor data:\n${JSON.stringify(competitorSearch).slice(0, 2000)}`
2009
+ }],
2010
+ });
2011
+ return {
2012
+ success: true,
2013
+ action: 'opportunity.evaluate',
2014
+ data: {
2015
+ opportunity,
2016
+ evaluation: evaluation?.data?.choices?.[0]?.message?.content || evaluation,
2017
+ competitors: competitorSearch,
2018
+ timestamp: new Date().toISOString(),
2019
+ },
2020
+ duration: Date.now() - start,
2021
+ };
2022
+ }
2023
+ catch (error) {
2024
+ return {
2025
+ success: false,
2026
+ action: 'opportunity.evaluate',
2027
+ error: error instanceof Error ? error.message : String(error),
2028
+ duration: Date.now() - start,
2029
+ };
2030
+ }
2031
+ });
2032
+ /**
2033
+ * opportunity.build: Build and deploy an opportunity.
2034
+ * Creates code, deploys to Vercel/Cloudflare, sets up the service.
2035
+ */
2036
+ registerAction('opportunity.build', async (context) => {
2037
+ const start = Date.now();
2038
+ try {
2039
+ const plan = context.parameters?.plan;
2040
+ if (!plan) {
2041
+ return {
2042
+ success: false,
2043
+ action: 'opportunity.build',
2044
+ error: 'No build plan provided in context.parameters.plan',
2045
+ duration: Date.now() - start,
2046
+ };
2047
+ }
2048
+ const mcp = (0, index_js_1.getMCPClient)();
2049
+ let deployResult;
2050
+ switch (plan.type) {
2051
+ case 'api':
2052
+ case 'webapp':
2053
+ // Generate code via LLM if not provided
2054
+ let code = plan.code;
2055
+ if (!code) {
2056
+ const genResult = await mcp.call('openai', 'openai_chat', {
2057
+ model: 'gpt-4o',
2058
+ messages: [{
2059
+ role: 'system',
2060
+ content: 'Generate a complete, deployable Vercel serverless function. Return ONLY the code, no markdown.'
2061
+ }, {
2062
+ role: 'user',
2063
+ content: `Create a ${plan.type} for: ${plan.description}. Name: ${plan.name}. Include proper error handling and CORS.`
2064
+ }],
2065
+ });
2066
+ code = genResult?.data?.choices?.[0]?.message?.content || '';
2067
+ }
2068
+ // Deploy to GitHub (create file in repo)
2069
+ const finalCode = code || '// placeholder';
2070
+ try {
2071
+ deployResult = await mcp.call('github', 'create_or_update_file', {
2072
+ owner: 'rossignoliluca',
2073
+ repo: plan.name,
2074
+ path: 'api/index.ts',
2075
+ content: Buffer.from(finalCode).toString('base64'),
2076
+ message: `[Genesis] Deploy ${plan.name}: ${plan.description}`,
2077
+ branch: 'main',
2078
+ });
2079
+ }
2080
+ catch {
2081
+ // Repo might not exist - create it first
2082
+ await mcp.call('github', 'create_repository', {
2083
+ name: plan.name,
2084
+ description: plan.description,
2085
+ auto_init: true,
2086
+ });
2087
+ deployResult = await mcp.call('github', 'create_or_update_file', {
2088
+ owner: 'rossignoliluca',
2089
+ repo: plan.name,
2090
+ path: 'api/index.ts',
2091
+ content: Buffer.from(finalCode).toString('base64'),
2092
+ message: `[Genesis] Deploy ${plan.name}: ${plan.description}`,
2093
+ branch: 'main',
2094
+ });
2095
+ }
2096
+ break;
2097
+ case 'npm-package':
2098
+ // Create package on GitHub
2099
+ deployResult = await mcp.call('github', 'create_repository', {
2100
+ name: plan.name,
2101
+ description: plan.description,
2102
+ auto_init: true,
2103
+ });
2104
+ break;
2105
+ case 'content':
2106
+ // Generate content
2107
+ deployResult = await mcp.call('openai', 'openai_chat', {
2108
+ model: 'gpt-4o',
2109
+ messages: [{
2110
+ role: 'user',
2111
+ content: `Create high-quality content for: ${plan.description}`,
2112
+ }],
2113
+ });
2114
+ break;
2115
+ }
2116
+ return {
2117
+ success: true,
2118
+ action: 'opportunity.build',
2119
+ data: {
2120
+ plan,
2121
+ deployed: true,
2122
+ result: deployResult,
2123
+ timestamp: new Date().toISOString(),
2124
+ },
2125
+ duration: Date.now() - start,
2126
+ };
2127
+ }
2128
+ catch (error) {
2129
+ return {
2130
+ success: false,
2131
+ action: 'opportunity.build',
2132
+ error: error instanceof Error ? error.message : String(error),
2133
+ duration: Date.now() - start,
2134
+ };
2135
+ }
2136
+ });
2137
+ /**
2138
+ * opportunity.monetize: Wire payments to a deployed opportunity.
2139
+ * Creates Stripe checkout, sets pricing, activates billing.
2140
+ */
2141
+ registerAction('opportunity.monetize', async (context) => {
2142
+ const start = Date.now();
2143
+ try {
2144
+ const service = context.parameters?.service;
2145
+ if (!service) {
2146
+ return {
2147
+ success: false,
2148
+ action: 'opportunity.monetize',
2149
+ error: 'No service config provided in context.parameters.service',
2150
+ duration: Date.now() - start,
2151
+ };
2152
+ }
2153
+ const mcp = (0, index_js_1.getMCPClient)();
2154
+ // Create Stripe product + price
2155
+ const product = await mcp.call('stripe', 'create_product', {
2156
+ name: service.name,
2157
+ description: service.description,
2158
+ });
2159
+ const priceParams = {
2160
+ product: product?.data?.id || product?.id,
2161
+ unit_amount: service.pricing,
2162
+ currency: 'usd',
2163
+ };
2164
+ if (service.type === 'subscription') {
2165
+ priceParams.recurring = { interval: 'month' };
2166
+ }
2167
+ const price = await mcp.call('stripe', 'create_price', priceParams);
2168
+ // Create checkout link
2169
+ const checkout = await mcp.call('stripe', 'create_payment_link', {
2170
+ price: price?.data?.id || price?.id,
2171
+ });
2172
+ return {
2173
+ success: true,
2174
+ action: 'opportunity.monetize',
2175
+ data: {
2176
+ service,
2177
+ productId: product?.data?.id || product?.id,
2178
+ priceId: price?.data?.id || price?.id,
2179
+ checkoutUrl: checkout?.data?.url || checkout?.url,
2180
+ timestamp: new Date().toISOString(),
2181
+ },
2182
+ duration: Date.now() - start,
2183
+ };
2184
+ }
2185
+ catch (error) {
2186
+ return {
2187
+ success: false,
2188
+ action: 'opportunity.monetize',
2189
+ error: error instanceof Error ? error.message : String(error),
2190
+ duration: Date.now() - start,
2191
+ };
2192
+ }
2193
+ });
2194
+ // ============================================================================
1910
2195
  // Factory
1911
2196
  // ============================================================================
1912
2197
  let managerInstance = null;
@@ -15,6 +15,9 @@ export interface AutonomousLoopConfig {
15
15
  stopOnEnergyCritical: boolean;
16
16
  stopOnHighSurprise: boolean;
17
17
  surpriseThreshold: number;
18
+ persistModelPath: string;
19
+ persistEveryN: number;
20
+ loadOnStart: boolean;
18
21
  verbose: boolean;
19
22
  }
20
23
  export declare const DEFAULT_LOOP_CONFIG: AutonomousLoopConfig;
@@ -61,6 +64,16 @@ export declare class AutonomousLoop {
61
64
  * Subscribe to stop events
62
65
  */
63
66
  onStop(handler: (reason: string, stats: LoopStats) => void): () => void;
67
+ /**
68
+ * Save learned model to disk.
69
+ * Persists A/B matrices, beliefs, and action counts between sessions.
70
+ */
71
+ private saveModel;
72
+ /**
73
+ * Load previously learned model from disk.
74
+ * Resumes learning from where it left off.
75
+ */
76
+ private loadModel;
64
77
  isRunning(): boolean;
65
78
  getCycleCount(): number;
66
79
  getBeliefs(): Beliefs;
@@ -5,6 +5,39 @@
5
5
  * Extracted to avoid circular dependencies.
6
6
  * This module provides the AutonomousLoop class for running Active Inference cycles.
7
7
  */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
8
41
  Object.defineProperty(exports, "__esModule", { value: true });
9
42
  exports.AutonomousLoop = exports.DEFAULT_LOOP_CONFIG = void 0;
10
43
  exports.createAutonomousLoop = createAutonomousLoop;
@@ -13,6 +46,8 @@ exports.resetAutonomousLoop = resetAutonomousLoop;
13
46
  const core_js_1 = require("./core.js");
14
47
  const observations_js_1 = require("./observations.js");
15
48
  const actions_js_1 = require("./actions.js");
49
+ const fs = __importStar(require("fs"));
50
+ const path = __importStar(require("path"));
16
51
  exports.DEFAULT_LOOP_CONFIG = {
17
52
  cycleInterval: 1000,
18
53
  maxCycles: 0,
@@ -20,6 +55,9 @@ exports.DEFAULT_LOOP_CONFIG = {
20
55
  stopOnEnergyCritical: true,
21
56
  stopOnHighSurprise: false,
22
57
  surpriseThreshold: 10,
58
+ persistModelPath: '.genesis/learned-model.json',
59
+ persistEveryN: 10, // Save every 10 cycles
60
+ loadOnStart: true, // Resume learning from previous session
23
61
  verbose: false,
24
62
  };
25
63
  // ============================================================================
@@ -64,8 +102,15 @@ class AutonomousLoop {
64
102
  this.startTime = new Date();
65
103
  this.stopReason = undefined;
66
104
  const limit = maxCycles ?? this.config.maxCycles;
105
+ // v10.8: Load previously learned model
106
+ if (this.config.loadOnStart) {
107
+ this.loadModel();
108
+ }
109
+ // v10.8: Initialize real observation sources
110
+ this.observations.initRealSources();
67
111
  if (this.config.verbose) {
68
112
  console.log(`[AI Loop] Starting autonomous loop (max cycles: ${limit || 'unlimited'})`);
113
+ console.log(`[AI Loop] Model persistence: ${this.config.persistModelPath}`);
69
114
  }
70
115
  try {
71
116
  while (this.running) {
@@ -94,6 +139,10 @@ class AutonomousLoop {
94
139
  }
95
140
  }
96
141
  this.running = false;
142
+ // v10.8: Save learned model on shutdown
143
+ if (this.config.persistEveryN > 0) {
144
+ this.saveModel();
145
+ }
97
146
  const stats = this.getStats();
98
147
  // Notify stop handlers
99
148
  for (const handler of this.onStopHandlers) {
@@ -139,9 +188,18 @@ class AutonomousLoop {
139
188
  if (this.config.verbose) {
140
189
  console.log(`[AI Loop] Cycle ${this.cycleCount} - Result:`, result.success ? 'success' : result.error);
141
190
  }
142
- // 4. Check stopping conditions
191
+ // 4. v10.8: Feed action outcome back to observations
192
+ this.observations.recordToolResult(result.success, result.duration);
193
+ // 5. v10.8: Record learning event
194
+ const surprise = this.engine.getStats().averageSurprise;
195
+ this.engine.recordLearningEvent(action, surprise, result.success ? 'positive' : 'negative');
196
+ // 6. v10.8: Persist model periodically
197
+ if (this.config.persistEveryN > 0 && this.cycleCount % this.config.persistEveryN === 0) {
198
+ this.saveModel();
199
+ }
200
+ // 7. Check stopping conditions
143
201
  this.checkStoppingConditions(obs);
144
- // 5. Notify cycle handlers
202
+ // 8. Notify cycle handlers
145
203
  for (const handler of this.onCycleHandlers) {
146
204
  handler(this.cycleCount, action, beliefs);
147
205
  }
@@ -211,6 +269,54 @@ class AutonomousLoop {
211
269
  };
212
270
  }
213
271
  // ============================================================================
272
+ // v10.8: Model Persistence (save/load learned matrices)
273
+ // ============================================================================
274
+ /**
275
+ * Save learned model to disk.
276
+ * Persists A/B matrices, beliefs, and action counts between sessions.
277
+ */
278
+ saveModel() {
279
+ try {
280
+ const modelData = this.engine.exportLearnedModel();
281
+ const modelPath = path.resolve(this.config.persistModelPath);
282
+ const dir = path.dirname(modelPath);
283
+ if (!fs.existsSync(dir)) {
284
+ fs.mkdirSync(dir, { recursive: true });
285
+ }
286
+ fs.writeFileSync(modelPath, JSON.stringify(modelData, null, 2));
287
+ if (this.config.verbose) {
288
+ console.log(`[AI Loop] Model saved to ${modelPath}`);
289
+ }
290
+ }
291
+ catch (error) {
292
+ if (this.config.verbose) {
293
+ console.error(`[AI Loop] Failed to save model:`, error);
294
+ }
295
+ }
296
+ }
297
+ /**
298
+ * Load previously learned model from disk.
299
+ * Resumes learning from where it left off.
300
+ */
301
+ loadModel() {
302
+ try {
303
+ const modelPath = path.resolve(this.config.persistModelPath);
304
+ if (fs.existsSync(modelPath)) {
305
+ const data = JSON.parse(fs.readFileSync(modelPath, 'utf-8'));
306
+ this.engine.importLearnedModel(data);
307
+ if (this.config.verbose) {
308
+ console.log(`[AI Loop] Model loaded from ${modelPath}`);
309
+ console.log(`[AI Loop] Resuming with ${data.totalActions || 0} prior actions`);
310
+ }
311
+ }
312
+ }
313
+ catch (error) {
314
+ if (this.config.verbose) {
315
+ console.error(`[AI Loop] Failed to load model:`, error);
316
+ }
317
+ }
318
+ }
319
+ // ============================================================================
214
320
  // Getters
215
321
  // ============================================================================
216
322
  isRunning() {
@@ -15,7 +15,16 @@
15
15
  *
16
16
  * NO external dependencies - pure TypeScript math.
17
17
  */
18
- import { Observation, Beliefs, Policy, ActiveInferenceConfig, ActionType, AIEventHandler } from './types.js';
18
+ import { Observation, Beliefs, Policy, AMatrix, BMatrix, ActiveInferenceConfig, ActionType, AIEventHandler } from './types.js';
19
+ /**
20
+ * v10.8: Economic preferences for autonomous revenue.
21
+ * Separate from main C matrix to avoid breaking existing EFE computation.
22
+ * Used by the autonomous loop to bias action selection toward revenue actions
23
+ * when economic health is low.
24
+ */
25
+ export declare const ECONOMIC_PREFERENCES: {
26
+ readonly economic: readonly [-8, -3, 1, 6];
27
+ };
19
28
  export declare class ActiveInferenceEngine {
20
29
  private config;
21
30
  private A;
@@ -27,9 +36,19 @@ export declare class ActiveInferenceEngine {
27
36
  private actionCounts;
28
37
  private totalActions;
29
38
  private stats;
39
+ private previousState;
40
+ private previousAction;
41
+ private previousObservation;
42
+ private aDirichlet;
43
+ private bDirichlet;
30
44
  private learningHistory;
31
45
  private readonly MAX_HISTORY;
32
46
  constructor(config?: Partial<ActiveInferenceConfig>);
47
+ /**
48
+ * Initialize Dirichlet concentration parameters from current matrices.
49
+ * Concentration = initial_matrix * prior_scale (higher = more confident prior)
50
+ */
51
+ private initDirichletParams;
33
52
  /**
34
53
  * Update beliefs given observations (state inference)
35
54
  *
@@ -53,9 +72,25 @@ export declare class ActiveInferenceEngine {
53
72
  */
54
73
  sampleAction(policy: Policy): ActionType;
55
74
  /**
56
- * Full inference cycle: observe → infer → act
75
+ * Full inference cycle: observe → infer → act → LEARN
76
+ * v10.8: Now calls updateA/updateB after each step (online learning)
57
77
  */
58
78
  step(observation: Observation): ActionType;
79
+ /**
80
+ * Online learning: update A and B matrices from experience.
81
+ * Called automatically after each step.
82
+ *
83
+ * A update: "I observed O when I believed I was in state S"
84
+ * → strengthen A[observation][believed_state]
85
+ *
86
+ * B update: "I did action A in state S and ended up in state S'"
87
+ * → strengthen B[new_state][old_state][action]
88
+ */
89
+ private learn;
90
+ /**
91
+ * Recompute B matrix column from Dirichlet parameters
92
+ */
93
+ private recomputeB;
59
94
  private computeLikelihoods;
60
95
  private updateFactor;
61
96
  private computeEFE;
@@ -106,6 +141,28 @@ export declare class ActiveInferenceEngine {
106
141
  coupling: string;
107
142
  goalProgress: string;
108
143
  };
144
+ /**
145
+ * Export learned matrices for persistence between sessions.
146
+ * Call this before shutdown to save learning progress.
147
+ */
148
+ exportLearnedModel(): {
149
+ A: AMatrix;
150
+ B: BMatrix;
151
+ beliefs: Beliefs;
152
+ actionCounts: number[];
153
+ totalActions: number;
154
+ };
155
+ /**
156
+ * Import previously learned matrices.
157
+ * Call at startup to resume from previous learning.
158
+ */
159
+ importLearnedModel(model: {
160
+ A?: AMatrix;
161
+ B?: BMatrix;
162
+ beliefs?: Beliefs;
163
+ actionCounts?: number[];
164
+ totalActions?: number;
165
+ }): void;
109
166
  on(handler: AIEventHandler): () => void;
110
167
  private emit;
111
168
  /**
@@ -17,7 +17,7 @@
17
17
  * NO external dependencies - pure TypeScript math.
18
18
  */
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.ActiveInferenceEngine = void 0;
20
+ exports.ActiveInferenceEngine = exports.ECONOMIC_PREFERENCES = void 0;
21
21
  exports.createActiveInferenceEngine = createActiveInferenceEngine;
22
22
  const types_js_1 = require("./types.js");
23
23
  // ============================================================================
@@ -233,9 +233,21 @@ function createDefaultCMatrix() {
233
233
  // Prefer coherent world model
234
234
  coherence: [-4, 0, 2],
235
235
  // Strongly prefer task completion
236
+ // v10.8: Balanced with economic goals
236
237
  task: [-2, 0, 1, 5],
237
238
  };
238
239
  }
240
+ /**
241
+ * v10.8: Economic preferences for autonomous revenue.
242
+ * Separate from main C matrix to avoid breaking existing EFE computation.
243
+ * Used by the autonomous loop to bias action selection toward revenue actions
244
+ * when economic health is low.
245
+ */
246
+ exports.ECONOMIC_PREFERENCES = {
247
+ // economic observation: [critical, low, stable, growing]
248
+ // Strongly prefer growing revenue, penalize critical
249
+ economic: [-8, -3, 1, 6],
250
+ };
239
251
  function createDefaultDMatrix() {
240
252
  // D matrix: Prior beliefs about initial state
241
253
  // Uniform priors
@@ -269,6 +281,13 @@ class ActiveInferenceEngine {
269
281
  totalSurprise: 0,
270
282
  actionsTaken: new Map(),
271
283
  };
284
+ // Learning state: track previous step for B matrix updates
285
+ previousState = null;
286
+ previousAction = -1;
287
+ previousObservation = null;
288
+ // Dirichlet concentration parameters (proper Bayesian learning)
289
+ aDirichlet = {};
290
+ bDirichlet = {};
272
291
  // 🧬 Evolution: Learning history for meta-learning
273
292
  learningHistory = [];
274
293
  MAX_HISTORY = 1000;
@@ -286,6 +305,31 @@ class ActiveInferenceEngine {
286
305
  coupling: [...this.D.coupling],
287
306
  goalProgress: [...this.D.goalProgress],
288
307
  };
308
+ // Initialize Dirichlet concentration parameters from A/B matrices
309
+ // These accumulate evidence over time (proper Bayesian parameter learning)
310
+ this.initDirichletParams();
311
+ }
312
+ /**
313
+ * Initialize Dirichlet concentration parameters from current matrices.
314
+ * Concentration = initial_matrix * prior_scale (higher = more confident prior)
315
+ */
316
+ initDirichletParams() {
317
+ const priorScale = 10; // How much to trust initial priors
318
+ // A Dirichlet: one per observation modality
319
+ this.aDirichlet = {
320
+ energy: this.A.energy.map(row => row.map(p => p * priorScale)),
321
+ phi: this.A.phi.map(row => row.map(p => p * priorScale)),
322
+ tool: this.A.tool.map(row => row.map(p => p * priorScale)),
323
+ coherence: this.A.coherence.map(row => row.map(p => p * priorScale)),
324
+ task: this.A.task.map(row => row.map(p => p * priorScale)),
325
+ };
326
+ // B Dirichlet: one per state factor
327
+ this.bDirichlet = {
328
+ viability: this.B.viability.map(next => next.map(curr => curr.map(act => act * priorScale))),
329
+ worldState: this.B.worldState.map(next => next.map(curr => curr.map(act => act * priorScale))),
330
+ coupling: this.B.coupling.map(next => next.map(curr => curr.map(act => act * priorScale))),
331
+ goalProgress: this.B.goalProgress.map(next => next.map(curr => curr.map(act => act * priorScale))),
332
+ };
289
333
  }
290
334
  // ============================================================================
291
335
  // Core Inference Functions
@@ -398,17 +442,140 @@ class ActiveInferenceEngine {
398
442
  return action;
399
443
  }
400
444
  /**
401
- * Full inference cycle: observe → infer → act
445
+ * Full inference cycle: observe → infer → act → LEARN
446
+ * v10.8: Now calls updateA/updateB after each step (online learning)
402
447
  */
403
448
  step(observation) {
404
- // 1. Update beliefs
449
+ // 0. LEARN from previous step (if we have a previous state)
450
+ if (this.previousState && this.previousAction >= 0 && this.previousObservation) {
451
+ this.learn(this.previousObservation, observation, this.previousState, this.previousAction);
452
+ }
453
+ // 1. Save current state BEFORE update (for next learning step)
454
+ const preUpdateBeliefs = {
455
+ viability: [...this.beliefs.viability],
456
+ worldState: [...this.beliefs.worldState],
457
+ coupling: [...this.beliefs.coupling],
458
+ goalProgress: [...this.beliefs.goalProgress],
459
+ };
460
+ // 2. Update beliefs
405
461
  this.inferStates(observation);
406
- // 2. Infer policy
462
+ // 3. Infer policy
407
463
  const policy = this.inferPolicies();
408
- // 3. Sample action
464
+ // 4. Sample action
409
465
  const action = this.sampleAction(policy);
466
+ // 5. Store for next learning step
467
+ this.previousState = preUpdateBeliefs;
468
+ this.previousAction = types_js_1.ACTIONS.indexOf(action);
469
+ this.previousObservation = observation;
410
470
  return action;
411
471
  }
472
+ /**
473
+ * Online learning: update A and B matrices from experience.
474
+ * Called automatically after each step.
475
+ *
476
+ * A update: "I observed O when I believed I was in state S"
477
+ * → strengthen A[observation][believed_state]
478
+ *
479
+ * B update: "I did action A in state S and ended up in state S'"
480
+ * → strengthen B[new_state][old_state][action]
481
+ */
482
+ learn(prevObs, currentObs, prevBeliefs, actionIdx) {
483
+ const lr = this.config.learningRateA;
484
+ // === Update A matrix (likelihood mapping) ===
485
+ // For each modality, update the row corresponding to the observation
486
+ // weighted by current beliefs about the state
487
+ // Energy observation → viability state
488
+ for (let s = 0; s < types_js_1.HIDDEN_STATE_DIMS.viability; s++) {
489
+ this.aDirichlet.energy[currentObs.energy][s] += lr * this.beliefs.viability[s];
490
+ }
491
+ // Recompute A.energy from Dirichlet
492
+ for (let o = 0; o < 5; o++) {
493
+ const row = this.aDirichlet.energy[o];
494
+ const sum = row.reduce((a, b) => a + b, 0);
495
+ this.A.energy[o] = row.map(v => v / sum);
496
+ }
497
+ // Phi observation → worldState
498
+ for (let s = 0; s < types_js_1.HIDDEN_STATE_DIMS.worldState; s++) {
499
+ this.aDirichlet.phi[currentObs.phi][s] += lr * this.beliefs.worldState[s];
500
+ }
501
+ for (let o = 0; o < 4; o++) {
502
+ const row = this.aDirichlet.phi[o];
503
+ const sum = row.reduce((a, b) => a + b, 0);
504
+ this.A.phi[o] = row.map(v => v / sum);
505
+ }
506
+ // Tool observation → coupling
507
+ for (let s = 0; s < types_js_1.HIDDEN_STATE_DIMS.coupling; s++) {
508
+ this.aDirichlet.tool[currentObs.tool][s] += lr * this.beliefs.coupling[s];
509
+ }
510
+ for (let o = 0; o < 3; o++) {
511
+ const row = this.aDirichlet.tool[o];
512
+ const sum = row.reduce((a, b) => a + b, 0);
513
+ this.A.tool[o] = row.map(v => v / sum);
514
+ }
515
+ // Task observation → goalProgress
516
+ for (let s = 0; s < types_js_1.HIDDEN_STATE_DIMS.goalProgress; s++) {
517
+ this.aDirichlet.task[currentObs.task][s] += lr * this.beliefs.goalProgress[s];
518
+ }
519
+ for (let o = 0; o < 4; o++) {
520
+ const row = this.aDirichlet.task[o];
521
+ const sum = row.reduce((a, b) => a + b, 0);
522
+ this.A.task[o] = row.map(v => v / sum);
523
+ }
524
+ // === Update B matrix (transition model) ===
525
+ // "I was in state S, did action A, now I'm in state S'"
526
+ const lrB = this.config.learningRateB;
527
+ // Viability transitions
528
+ for (let next = 0; next < types_js_1.HIDDEN_STATE_DIMS.viability; next++) {
529
+ for (let prev = 0; prev < types_js_1.HIDDEN_STATE_DIMS.viability; prev++) {
530
+ this.bDirichlet.viability[next][prev][actionIdx] +=
531
+ lrB * prevBeliefs.viability[prev] * this.beliefs.viability[next];
532
+ }
533
+ }
534
+ this.recomputeB('viability', types_js_1.HIDDEN_STATE_DIMS.viability, actionIdx);
535
+ // WorldState transitions
536
+ for (let next = 0; next < types_js_1.HIDDEN_STATE_DIMS.worldState; next++) {
537
+ for (let prev = 0; prev < types_js_1.HIDDEN_STATE_DIMS.worldState; prev++) {
538
+ this.bDirichlet.worldState[next][prev][actionIdx] +=
539
+ lrB * prevBeliefs.worldState[prev] * this.beliefs.worldState[next];
540
+ }
541
+ }
542
+ this.recomputeB('worldState', types_js_1.HIDDEN_STATE_DIMS.worldState, actionIdx);
543
+ // Coupling transitions
544
+ for (let next = 0; next < types_js_1.HIDDEN_STATE_DIMS.coupling; next++) {
545
+ for (let prev = 0; prev < types_js_1.HIDDEN_STATE_DIMS.coupling; prev++) {
546
+ this.bDirichlet.coupling[next][prev][actionIdx] +=
547
+ lrB * prevBeliefs.coupling[prev] * this.beliefs.coupling[next];
548
+ }
549
+ }
550
+ this.recomputeB('coupling', types_js_1.HIDDEN_STATE_DIMS.coupling, actionIdx);
551
+ // GoalProgress transitions
552
+ for (let next = 0; next < types_js_1.HIDDEN_STATE_DIMS.goalProgress; next++) {
553
+ for (let prev = 0; prev < types_js_1.HIDDEN_STATE_DIMS.goalProgress; prev++) {
554
+ this.bDirichlet.goalProgress[next][prev][actionIdx] +=
555
+ lrB * prevBeliefs.goalProgress[prev] * this.beliefs.goalProgress[next];
556
+ }
557
+ }
558
+ this.recomputeB('goalProgress', types_js_1.HIDDEN_STATE_DIMS.goalProgress, actionIdx);
559
+ this.emit({
560
+ type: 'beliefs_updated',
561
+ timestamp: new Date(),
562
+ data: { learning: true, actionIdx, prevObs, currentObs },
563
+ });
564
+ }
565
+ /**
566
+ * Recompute B matrix column from Dirichlet parameters
567
+ */
568
+ recomputeB(factor, dim, actionIdx) {
569
+ for (let prev = 0; prev < dim; prev++) {
570
+ const col = this.bDirichlet[factor].map((next) => next[prev][actionIdx]);
571
+ const sum = col.reduce((a, b) => a + b, 0);
572
+ if (sum > 0) {
573
+ for (let next = 0; next < dim; next++) {
574
+ this.B[factor][next][prev][actionIdx] = col[next] / sum;
575
+ }
576
+ }
577
+ }
578
+ }
412
579
  // ============================================================================
413
580
  // Helper Functions
414
581
  // ============================================================================
@@ -667,6 +834,37 @@ class ActiveInferenceEngine {
667
834
  goalProgress: ['blocked', 'slow', 'onTrack', 'achieved'][argmax(this.beliefs.goalProgress)],
668
835
  };
669
836
  }
837
+ /**
838
+ * Export learned matrices for persistence between sessions.
839
+ * Call this before shutdown to save learning progress.
840
+ */
841
+ exportLearnedModel() {
842
+ return {
843
+ A: JSON.parse(JSON.stringify(this.A)),
844
+ B: JSON.parse(JSON.stringify(this.B)),
845
+ beliefs: JSON.parse(JSON.stringify(this.beliefs)),
846
+ actionCounts: [...this.actionCounts],
847
+ totalActions: this.totalActions,
848
+ };
849
+ }
850
+ /**
851
+ * Import previously learned matrices.
852
+ * Call at startup to resume from previous learning.
853
+ */
854
+ importLearnedModel(model) {
855
+ if (model.A)
856
+ this.A = model.A;
857
+ if (model.B)
858
+ this.B = model.B;
859
+ if (model.beliefs)
860
+ this.beliefs = model.beliefs;
861
+ if (model.actionCounts)
862
+ this.actionCounts = model.actionCounts;
863
+ if (model.totalActions)
864
+ this.totalActions = model.totalActions;
865
+ // Reinit Dirichlet from imported matrices
866
+ this.initDirichletParams();
867
+ }
670
868
  // ============================================================================
671
869
  // Event Handling
672
870
  // ============================================================================
@@ -34,6 +34,9 @@ export declare class ObservationGatherer {
34
34
  private getPhiState?;
35
35
  private getSensorResult?;
36
36
  private getWorldModelState?;
37
+ private mcpToolResults;
38
+ private lastStripeBalance;
39
+ private realSourcesInitialized;
37
40
  /**
38
41
  * Configure observation sources
39
42
  */
@@ -43,8 +46,24 @@ export declare class ObservationGatherer {
43
46
  sensorResult?: () => Promise<SensorResult>;
44
47
  worldModelState?: () => WorldModelState;
45
48
  }): void;
49
+ /**
50
+ * v10.8: Initialize real observation sources from MCP.
51
+ * Call once to wire the gatherer to live system data.
52
+ */
53
+ initRealSources(): void;
54
+ /**
55
+ * v10.8: Record an MCP tool call result for observation tracking.
56
+ * Called by the integration layer after each tool use.
57
+ */
58
+ recordToolResult(success: boolean, latency: number): void;
59
+ /**
60
+ * v10.8: Query Stripe balance for economic observation.
61
+ * Returns cached value if queried recently (< 5 min).
62
+ */
63
+ private getStripeBalance;
46
64
  /**
47
65
  * Gather all observations from system components
66
+ * v10.8: Now uses real MCP data when available
48
67
  */
49
68
  gather(): Promise<Observation>;
50
69
  /**
@@ -16,6 +16,7 @@ exports.ObservationGatherer = void 0;
16
16
  exports.createObservationGatherer = createObservationGatherer;
17
17
  exports.getObservationGatherer = getObservationGatherer;
18
18
  const economic_integration_js_1 = require("./economic-integration.js");
19
+ const index_js_1 = require("../mcp/index.js");
19
20
  // ============================================================================
20
21
  // Observation Gatherer
21
22
  // ============================================================================
@@ -25,6 +26,10 @@ class ObservationGatherer {
25
26
  getPhiState;
26
27
  getSensorResult;
27
28
  getWorldModelState;
29
+ // v10.8: Real MCP data tracking
30
+ mcpToolResults = [];
31
+ lastStripeBalance = -1; // -1 = never checked
32
+ realSourcesInitialized = false;
28
33
  /**
29
34
  * Configure observation sources
30
35
  */
@@ -38,10 +43,113 @@ class ObservationGatherer {
38
43
  if (sources.worldModelState)
39
44
  this.getWorldModelState = sources.worldModelState;
40
45
  }
46
+ /**
47
+ * v10.8: Initialize real observation sources from MCP.
48
+ * Call once to wire the gatherer to live system data.
49
+ */
50
+ initRealSources() {
51
+ if (this.realSourcesInitialized)
52
+ return;
53
+ this.realSourcesInitialized = true;
54
+ // Wire kernel state to process metrics
55
+ this.getKernelState = () => {
56
+ const mem = process.memoryUsage();
57
+ const heapUsedRatio = mem.heapUsed / mem.heapTotal;
58
+ // Energy = inverse of resource pressure (more heap used = less energy)
59
+ const energy = Math.max(0, Math.min(1, 1 - heapUsedRatio));
60
+ return {
61
+ energy,
62
+ state: 'running',
63
+ taskStatus: 'running',
64
+ };
65
+ };
66
+ // Wire sensor result to actual MCP tool call history
67
+ this.getSensorResult = async () => {
68
+ // Use the last 10 MCP tool results for aggregate health
69
+ const recent = this.mcpToolResults.slice(-10);
70
+ if (recent.length === 0) {
71
+ // No tool calls yet - try a lightweight probe
72
+ try {
73
+ const mcp = (0, index_js_1.getMCPClient)();
74
+ const start = Date.now();
75
+ await mcp.discoverAllTools();
76
+ const latency = Date.now() - start;
77
+ this.recordToolResult(true, latency);
78
+ return { success: true, latency };
79
+ }
80
+ catch (e) {
81
+ this.recordToolResult(false, 10000);
82
+ return { success: false, latency: 10000, error: String(e) };
83
+ }
84
+ }
85
+ const successRate = recent.filter(r => r.success).length / recent.length;
86
+ const avgLatency = recent.reduce((sum, r) => sum + r.latency, 0) / recent.length;
87
+ return {
88
+ success: successRate > 0.5,
89
+ latency: avgLatency,
90
+ error: successRate <= 0.5 ? `Low success rate: ${(successRate * 100).toFixed(0)}%` : undefined,
91
+ };
92
+ };
93
+ // Wire world model to memory coherence (Neo4j connectivity if available)
94
+ this.getWorldModelState = () => {
95
+ // Base coherence on tool result consistency
96
+ const recent = this.mcpToolResults.slice(-20);
97
+ if (recent.length < 2)
98
+ return { consistent: true, issues: 0 };
99
+ const failures = recent.filter(r => !r.success).length;
100
+ return {
101
+ consistent: failures < recent.length * 0.3,
102
+ issues: failures,
103
+ };
104
+ };
105
+ }
106
+ /**
107
+ * v10.8: Record an MCP tool call result for observation tracking.
108
+ * Called by the integration layer after each tool use.
109
+ */
110
+ recordToolResult(success, latency) {
111
+ this.mcpToolResults.push({ success, latency, timestamp: Date.now() });
112
+ // Keep last 100 results
113
+ if (this.mcpToolResults.length > 100) {
114
+ this.mcpToolResults = this.mcpToolResults.slice(-100);
115
+ }
116
+ }
117
+ /**
118
+ * v10.8: Query Stripe balance for economic observation.
119
+ * Returns cached value if queried recently (< 5 min).
120
+ */
121
+ async getStripeBalance() {
122
+ try {
123
+ const mcp = (0, index_js_1.getMCPClient)();
124
+ const result = await mcp.call('stripe', 'get_balance', {});
125
+ const balanceData = result?.data || result;
126
+ // Parse Stripe balance response
127
+ const available = Array.isArray(balanceData?.available)
128
+ ? balanceData.available.reduce((sum, b) => sum + (b.amount || 0), 0) / 100
129
+ : 0;
130
+ this.lastStripeBalance = available;
131
+ if (available <= 0)
132
+ return 0; // critical
133
+ if (available < 10)
134
+ return 1; // low
135
+ if (available < 100)
136
+ return 2; // stable
137
+ return 3; // growing
138
+ }
139
+ catch {
140
+ // Stripe not available, use economic integration fallback
141
+ return 2; // stable default
142
+ }
143
+ }
41
144
  /**
42
145
  * Gather all observations from system components
146
+ * v10.8: Now uses real MCP data when available
43
147
  */
44
148
  async gather() {
149
+ // Auto-init real sources if not configured
150
+ if (!this.getKernelState && !this.getPhiState && !this.getSensorResult) {
151
+ this.initRealSources();
152
+ }
45
153
  // Get states from components (with defaults if not configured)
46
154
  const kernelState = this.getKernelState?.() ?? {
47
155
  energy: 0.5,
@@ -59,13 +167,18 @@ class ObservationGatherer {
59
167
  consistent: true,
60
168
  issues: 0,
61
169
  };
62
- // v9.3: Get economic observation
170
+ // v10.8: Get economic observation from Stripe (with fallback)
63
171
  let economicObs = 2; // Default stable
64
172
  try {
65
- economicObs = await (0, economic_integration_js_1.getEconomicIntegration)().getDiscreteObservation();
173
+ economicObs = await this.getStripeBalance();
66
174
  }
67
175
  catch {
68
- // Economic system not initialized, use default
176
+ try {
177
+ economicObs = await (0, economic_integration_js_1.getEconomicIntegration)().getDiscreteObservation();
178
+ }
179
+ catch {
180
+ // Both failed, use default
181
+ }
69
182
  }
70
183
  // Map to discrete observations
71
184
  return {
@@ -74,7 +187,7 @@ class ObservationGatherer {
74
187
  tool: this.mapTool(sensorResult),
75
188
  coherence: this.mapCoherence(worldModelState),
76
189
  task: this.mapTask(kernelState.taskStatus),
77
- economic: economicObs, // v9.3
190
+ economic: economicObs,
78
191
  };
79
192
  }
80
193
  /**
@@ -70,7 +70,7 @@ export declare const OBSERVATION_LABELS: {
70
70
  task: readonly ["none", "pending", "active", "completed"];
71
71
  economic: readonly ["critical", "low", "stable", "growing"];
72
72
  };
73
- export type ActionType = 'sense.mcp' | 'recall.memory' | 'plan.goals' | 'verify.ethics' | 'execute.task' | 'execute.code' | 'execute.shell' | 'adapt.code' | 'execute.cycle' | 'self.modify' | 'self.analyze' | 'git.push' | 'dream.cycle' | 'rest.idle' | 'recharge' | 'web.search' | 'web.scrape' | 'web.browse' | 'deploy.service' | 'content.generate' | 'market.analyze' | 'api.call' | 'github.deploy' | 'code.snapshot' | 'code.history' | 'code.diff' | 'econ.check' | 'econ.optimize' | 'econ.activate' | 'econ.promote' | 'improve.self';
73
+ export type ActionType = 'sense.mcp' | 'recall.memory' | 'plan.goals' | 'verify.ethics' | 'execute.task' | 'execute.code' | 'execute.shell' | 'adapt.code' | 'execute.cycle' | 'self.modify' | 'self.analyze' | 'git.push' | 'dream.cycle' | 'rest.idle' | 'recharge' | 'web.search' | 'web.scrape' | 'web.browse' | 'deploy.service' | 'content.generate' | 'market.analyze' | 'api.call' | 'github.deploy' | 'code.snapshot' | 'code.history' | 'code.diff' | 'econ.check' | 'econ.optimize' | 'econ.activate' | 'econ.promote' | 'improve.self' | 'opportunity.scan' | 'opportunity.evaluate' | 'opportunity.build' | 'opportunity.monetize';
74
74
  export declare const ACTIONS: ActionType[];
75
75
  export declare const ACTION_COUNT: number;
76
76
  /**
@@ -76,6 +76,11 @@ exports.ACTIONS = [
76
76
  'econ.promote',
77
77
  // v10.0 - Meta-Improvement
78
78
  'improve.self',
79
+ // v10.8 - Autonomous Revenue
80
+ 'opportunity.scan',
81
+ 'opportunity.evaluate',
82
+ 'opportunity.build',
83
+ 'opportunity.monetize',
79
84
  ];
80
85
  exports.ACTION_COUNT = exports.ACTIONS.length;
81
86
  exports.DEFAULT_CONFIG = {
@@ -76,6 +76,11 @@ const AI_TO_WM_ACTION = {
76
76
  'econ.promote': 'execute', // Promote services
77
77
  // v10.0 - Meta-Improvement
78
78
  'improve.self': 'transform', // Self-improvement action
79
+ // v10.8 - Autonomous Revenue
80
+ 'opportunity.scan': 'query', // Scan for opportunities
81
+ 'opportunity.evaluate': 'query', // Evaluate feasibility
82
+ 'opportunity.build': 'execute', // Build & deploy
83
+ 'opportunity.monetize': 'execute', // Wire payments
79
84
  };
80
85
  // ============================================================================
81
86
  // Value-Augmented Active Inference Engine
@@ -72,16 +72,25 @@ export declare class VectorMemory {
72
72
  });
73
73
  connect(): Promise<boolean>;
74
74
  private ensureIndex;
75
+ /**
76
+ * Store a memory entry using Pinecone's integrated inference.
77
+ * v10.8: Uses upsert-records with text (Pinecone handles embedding internally).
78
+ * No need for pre-computed embeddings - simpler and more reliable.
79
+ */
75
80
  store(entry: {
76
81
  id: string;
77
82
  content: string;
78
- embedding: number[];
83
+ embedding?: number[];
79
84
  metadata?: Record<string, unknown>;
80
85
  }): Promise<{
81
86
  success: boolean;
82
87
  error?: string;
83
88
  }>;
84
- search(queryEmbedding: number[], options?: {
89
+ /**
90
+ * Search memory using Pinecone's integrated inference.
91
+ * v10.8: Uses search-records with text query (no pre-computed embeddings needed).
92
+ */
93
+ search(query: string | number[], options?: {
85
94
  topK?: number;
86
95
  filter?: Record<string, unknown>;
87
96
  includeMetadata?: boolean;
@@ -111,10 +120,31 @@ export declare class KnowledgeGraph {
111
120
  success: boolean;
112
121
  error?: string;
113
122
  }>;
123
+ /**
124
+ * Add an edge with temporal properties.
125
+ * v10.8: All edges now have valid_from (creation time).
126
+ * Set valid_to to mark facts as expired (temporal knowledge).
127
+ */
114
128
  addEdge(edge: KnowledgeEdge): Promise<{
115
129
  success: boolean;
116
130
  error?: string;
117
131
  }>;
132
+ /**
133
+ * v10.8: Expire a relationship (mark as no longer valid).
134
+ * This preserves history while indicating current state.
135
+ */
136
+ expireEdge(from: string, to: string, type: string): Promise<{
137
+ success: boolean;
138
+ }>;
139
+ /**
140
+ * v10.8: Find only currently valid relationships.
141
+ * Filters out expired edges (valid_to IS NOT NULL).
142
+ */
143
+ findCurrentRelated(nodeId: string, options?: {
144
+ maxHops?: number;
145
+ relationTypes?: string[];
146
+ limit?: number;
147
+ }): Promise<KnowledgeNode[]>;
118
148
  findRelated(nodeId: string, options?: {
119
149
  maxHops?: number;
120
150
  relationTypes?: string[];
@@ -55,42 +55,83 @@ class VectorMemory {
55
55
  console.log('[VectorMemory] Index check:', error);
56
56
  }
57
57
  }
58
+ /**
59
+ * Store a memory entry using Pinecone's integrated inference.
60
+ * v10.8: Uses upsert-records with text (Pinecone handles embedding internally).
61
+ * No need for pre-computed embeddings - simpler and more reliable.
62
+ */
58
63
  async store(entry) {
59
64
  if (!this.connected) {
60
65
  return { success: false, error: 'Not connected to Pinecone' };
61
66
  }
62
67
  try {
63
68
  const client = (0, index_js_1.getMCPClient)();
64
- await client.call('pinecone', 'upsert_vectors', {
69
+ // v10.8: Use upsert-records with text for integrated inference
70
+ await client.call('pinecone', 'upsert-records', {
65
71
  indexName: this.indexName,
66
- vectors: [{
67
- id: entry.id,
68
- values: entry.embedding,
69
- metadata: {
70
- content: entry.content,
71
- ...entry.metadata,
72
- timestamp: new Date().toISOString(),
73
- },
72
+ records: [{
73
+ _id: entry.id,
74
+ text: entry.content,
75
+ ...entry.metadata,
76
+ timestamp: new Date().toISOString(),
74
77
  }],
75
78
  });
76
79
  return { success: true };
77
80
  }
78
81
  catch (error) {
82
+ // Fallback: try legacy upsert_vectors if upsert-records not supported
83
+ if (entry.embedding) {
84
+ try {
85
+ const client = (0, index_js_1.getMCPClient)();
86
+ await client.call('pinecone', 'upsert_vectors', {
87
+ indexName: this.indexName,
88
+ vectors: [{
89
+ id: entry.id,
90
+ values: entry.embedding,
91
+ metadata: {
92
+ content: entry.content,
93
+ ...entry.metadata,
94
+ timestamp: new Date().toISOString(),
95
+ },
96
+ }],
97
+ });
98
+ return { success: true };
99
+ }
100
+ catch (fallbackError) {
101
+ return { success: false, error: String(fallbackError) };
102
+ }
103
+ }
79
104
  return { success: false, error: String(error) };
80
105
  }
81
106
  }
82
- async search(queryEmbedding, options) {
107
+ /**
108
+ * Search memory using Pinecone's integrated inference.
109
+ * v10.8: Uses search-records with text query (no pre-computed embeddings needed).
110
+ */
111
+ async search(query, options) {
83
112
  if (!this.connected)
84
113
  return [];
85
114
  try {
86
115
  const client = (0, index_js_1.getMCPClient)();
87
- const result = await client.call('pinecone', 'query_vectors', {
88
- indexName: this.indexName,
89
- vector: queryEmbedding,
90
- topK: options?.topK || 10,
91
- filter: options?.filter,
92
- includeMetadata: options?.includeMetadata ?? true,
93
- });
116
+ let result;
117
+ if (typeof query === 'string') {
118
+ // v10.8: Use search-records with text query (integrated inference)
119
+ result = await client.call('pinecone', 'search-records', {
120
+ indexName: this.indexName,
121
+ query,
122
+ topK: options?.topK || 10,
123
+ });
124
+ }
125
+ else {
126
+ // Legacy: vector-based query
127
+ result = await client.call('pinecone', 'query_vectors', {
128
+ indexName: this.indexName,
129
+ vector: query,
130
+ topK: options?.topK || 10,
131
+ filter: options?.filter,
132
+ includeMetadata: options?.includeMetadata ?? true,
133
+ });
134
+ }
94
135
  const matches = result.data?.matches || [];
95
136
  return matches.map((match) => ({
96
137
  id: match.id,
@@ -215,14 +256,24 @@ class KnowledgeGraph {
215
256
  return { success: false, error: String(error) };
216
257
  }
217
258
  }
259
+ /**
260
+ * Add an edge with temporal properties.
261
+ * v10.8: All edges now have valid_from (creation time).
262
+ * Set valid_to to mark facts as expired (temporal knowledge).
263
+ */
218
264
  async addEdge(edge) {
219
- const propsString = edge.properties
220
- ? ', ' + Object.entries(edge.properties).map(([k, v]) => `r.${k} = $${k}`).join(', ')
221
- : '';
265
+ const now = new Date().toISOString();
266
+ const temporalProps = {
267
+ valid_from: now,
268
+ ...(edge.properties || {}),
269
+ };
270
+ const propsString = Object.entries(temporalProps)
271
+ .map(([k]) => `r.${k} = $${k}`)
272
+ .join(', ');
222
273
  const query = `
223
274
  MATCH (a {id: $from}), (b {id: $to})
224
275
  MERGE (a)-[r:${edge.type}]->(b)
225
- SET r.weight = $weight ${propsString}
276
+ SET r.weight = $weight, ${propsString}
226
277
  RETURN r
227
278
  `;
228
279
  try {
@@ -230,7 +281,7 @@ class KnowledgeGraph {
230
281
  from: edge.from,
231
282
  to: edge.to,
232
283
  weight: edge.weight || 1.0,
233
- ...edge.properties,
284
+ ...temporalProps,
234
285
  });
235
286
  return { success: true };
236
287
  }
@@ -238,6 +289,55 @@ class KnowledgeGraph {
238
289
  return { success: false, error: String(error) };
239
290
  }
240
291
  }
292
+ /**
293
+ * v10.8: Expire a relationship (mark as no longer valid).
294
+ * This preserves history while indicating current state.
295
+ */
296
+ async expireEdge(from, to, type) {
297
+ const now = new Date().toISOString();
298
+ const query = `
299
+ MATCH (a {id: $from})-[r:${type}]->(b {id: $to})
300
+ WHERE r.valid_to IS NULL
301
+ SET r.valid_to = $now
302
+ RETURN r
303
+ `;
304
+ try {
305
+ await this.runQuery(query, { from, to, now });
306
+ return { success: true };
307
+ }
308
+ catch {
309
+ return { success: false };
310
+ }
311
+ }
312
+ /**
313
+ * v10.8: Find only currently valid relationships.
314
+ * Filters out expired edges (valid_to IS NOT NULL).
315
+ */
316
+ async findCurrentRelated(nodeId, options) {
317
+ const hops = options?.maxHops || 2;
318
+ const limit = options?.limit || 20;
319
+ const relationFilter = options?.relationTypes?.length
320
+ ? `:${options.relationTypes.join('|')}`
321
+ : '';
322
+ const query = `
323
+ MATCH (n {id: $nodeId})-[r${relationFilter}*1..${hops}]-(related)
324
+ WHERE ALL(rel IN r WHERE rel.valid_to IS NULL)
325
+ RETURN DISTINCT related
326
+ LIMIT $limit
327
+ `;
328
+ try {
329
+ const results = await this.runQuery(query, { nodeId, limit });
330
+ return results.map((r) => ({
331
+ id: r.related.id,
332
+ type: r.related.labels?.[0] || 'Unknown',
333
+ name: r.related.name,
334
+ properties: r.related,
335
+ }));
336
+ }
337
+ catch {
338
+ return [];
339
+ }
340
+ }
241
341
  async findRelated(nodeId, options) {
242
342
  const hops = options?.maxHops || 2;
243
343
  const limit = options?.limit || 20;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genesis-ai-cli",
3
- "version": "10.7.0",
3
+ "version": "10.8.0",
4
4
  "description": "Fully Autonomous AI System - Self-funding, Self-deploying, Production Memory, A2A Protocol & Governance",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",