tuna-agent 0.1.53 → 0.1.55

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.
@@ -1,6 +1,12 @@
1
1
  import type { AgentAdapter, AgentType } from './types.js';
2
2
  import type { AgentConfig, TaskAssignment, InputResponse } from '../types/index.js';
3
3
  import type { AgentWebSocketClient } from '../daemon/ws-client.js';
4
+ export interface LearnedRule {
5
+ content: string;
6
+ confidence: number;
7
+ sourceCount: number;
8
+ createdAt: string;
9
+ }
4
10
  export interface AgentMetrics {
5
11
  taskCount: number;
6
12
  successCount: number;
@@ -25,6 +31,7 @@ export declare class ClaudeCodeAdapter implements AgentAdapter {
25
31
  private taskCount;
26
32
  private static readonly PATTERN_CHECK_INTERVAL;
27
33
  private metricsMap;
34
+ private learnedRulesMap;
28
35
  private currentAgentId;
29
36
  /** Folder basename of current agent (e.g. "co-founder"). Used as Mem0 user_id. */
30
37
  private currentAgentName;
@@ -58,6 +65,11 @@ export declare class ClaudeCodeAdapter implements AgentAdapter {
58
65
  * Runs every N tasks to evolve the agent's permanent knowledge.
59
66
  */
60
67
  runSelfImprovement(cwd: string): Promise<void>;
68
+ /**
69
+ * Parse "## Learned Rules" section from CLAUDE.md and store in learnedRulesMap.
70
+ * Rule format: `- Rule text (confidence: 0.7)`
71
+ */
72
+ private parseLearnedRules;
61
73
  /** Track task completion metrics (public for daemon resume path). */
62
74
  trackMetricsPublic(status: 'done' | 'failed', durationMs: number): void;
63
75
  /** Track task completion metrics. */
@@ -16,6 +16,7 @@ export class ClaudeCodeAdapter {
16
16
  static PATTERN_CHECK_INTERVAL = 1; // Check patterns every N tasks
17
17
  // Per-agent state (one daemon handles multiple agents)
18
18
  metricsMap = new Map();
19
+ learnedRulesMap = new Map();
19
20
  currentAgentId = '';
20
21
  /** Folder basename of current agent (e.g. "co-founder"). Used as Mem0 user_id. */
21
22
  currentAgentName = '';
@@ -49,7 +50,12 @@ export class ClaudeCodeAdapter {
49
50
  getMetrics() {
50
51
  const agentMetricsMap = {};
51
52
  this.metricsMap.forEach((m, agentId) => {
52
- agentMetricsMap[agentId] = { ...m };
53
+ const entry = { ...m };
54
+ const rules = this.learnedRulesMap.get(agentId);
55
+ if (rules && rules.length > 0) {
56
+ entry.learnedRules = rules;
57
+ }
58
+ agentMetricsMap[agentId] = entry;
53
59
  });
54
60
  return { agentMetricsMap };
55
61
  }
@@ -91,6 +97,11 @@ export class ClaudeCodeAdapter {
91
97
  this.currentAgentId = task.agentId || '';
92
98
  const defaultWorkspaceEarly = path.join(os.homedir(), 'tuna-workspace');
93
99
  this.currentAgentName = path.basename(task.repoPath || defaultWorkspaceEarly);
100
+ // Parse existing learned rules on first task (sync to API on next heartbeat)
101
+ if (!this.learnedRulesMap.has(this.currentAgentId)) {
102
+ const cwd = task.repoPath || defaultWorkspaceEarly;
103
+ this.parseLearnedRules(path.join(cwd, 'CLAUDE.md'));
104
+ }
94
105
  if (task.mode !== 'tuna') {
95
106
  console.log(`[ClaudeCode] Agent Team mode — direct chat with Claude CLI`);
96
107
  ws.sendProgress(task.id, 'executing', { startedAt: new Date().toISOString() });
@@ -848,11 +859,56 @@ export class ClaudeCodeAdapter {
848
859
  this.metrics.latestLearnedRule = newPatterns[newPatterns.length - 1].rule.substring(0, 500);
849
860
  console.log(`[Self-Improve] Added ${newPatterns.length} new rules to CLAUDE.md:`);
850
861
  newPatterns.forEach(p => console.log(`[Self-Improve] - ${p.rule}`));
862
+ // Sync learned rules to heartbeat metrics
863
+ this.parseLearnedRules(claudeMdPath);
851
864
  }
852
865
  catch (err) {
853
866
  console.warn(`[Self-Improve] Failed:`, err instanceof Error ? err.message : err);
854
867
  }
855
868
  }
869
+ /**
870
+ * Parse "## Learned Rules" section from CLAUDE.md and store in learnedRulesMap.
871
+ * Rule format: `- Rule text (confidence: 0.7)`
872
+ */
873
+ parseLearnedRules(claudeMdPath) {
874
+ try {
875
+ if (!fs.existsSync(claudeMdPath))
876
+ return;
877
+ const content = fs.readFileSync(claudeMdPath, 'utf-8');
878
+ const SECTION_HEADER = '## Learned Rules';
879
+ const sectionIdx = content.indexOf(SECTION_HEADER);
880
+ if (sectionIdx === -1)
881
+ return;
882
+ const sectionContent = content.substring(sectionIdx + SECTION_HEADER.length);
883
+ // End at next ## heading or end of file
884
+ const nextSection = sectionContent.indexOf('\n## ');
885
+ const rulesText = nextSection !== -1 ? sectionContent.substring(0, nextSection) : sectionContent;
886
+ const rules = [];
887
+ const ruleRegex = /^- (.+?)(?:\s*\(confidence:\s*([\d.]+)\))?$/;
888
+ for (const line of rulesText.split('\n')) {
889
+ const trimmed = line.trim();
890
+ if (!trimmed || !trimmed.startsWith('-'))
891
+ continue;
892
+ const match = ruleRegex.exec(trimmed);
893
+ if (match) {
894
+ rules.push({
895
+ content: match[1].trim(),
896
+ confidence: match[2] ? parseFloat(match[2]) : 0.3,
897
+ sourceCount: 1,
898
+ createdAt: new Date().toISOString(),
899
+ });
900
+ }
901
+ }
902
+ if (rules.length > 0) {
903
+ this.learnedRulesMap.set(this.currentAgentId, rules);
904
+ this.metrics.rulesCount = rules.length;
905
+ console.log(`[Self-Improve] Parsed ${rules.length} rules from CLAUDE.md for heartbeat sync`);
906
+ }
907
+ }
908
+ catch (err) {
909
+ console.warn(`[Self-Improve] Failed to parse learned rules:`, err instanceof Error ? err.message : err);
910
+ }
911
+ }
856
912
  /** Track task completion metrics (public for daemon resume path). */
857
913
  trackMetricsPublic(status, durationMs) {
858
914
  this.trackMetrics(status, durationMs);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tuna-agent",
3
- "version": "0.1.53",
3
+ "version": "0.1.55",
4
4
  "description": "Tuna Agent - Run AI coding tasks on your machine",
5
5
  "bin": {
6
6
  "tuna-agent": "dist/cli/index.js"