@soleri/core 2.0.2 → 2.4.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.
Files changed (226) hide show
  1. package/dist/brain/brain.d.ts +14 -50
  2. package/dist/brain/brain.d.ts.map +1 -1
  3. package/dist/brain/brain.js +207 -16
  4. package/dist/brain/brain.js.map +1 -1
  5. package/dist/brain/intelligence.d.ts +86 -0
  6. package/dist/brain/intelligence.d.ts.map +1 -0
  7. package/dist/brain/intelligence.js +771 -0
  8. package/dist/brain/intelligence.js.map +1 -0
  9. package/dist/brain/types.d.ts +197 -0
  10. package/dist/brain/types.d.ts.map +1 -0
  11. package/dist/brain/types.js +2 -0
  12. package/dist/brain/types.js.map +1 -0
  13. package/dist/cognee/client.d.ts +35 -0
  14. package/dist/cognee/client.d.ts.map +1 -0
  15. package/dist/cognee/client.js +291 -0
  16. package/dist/cognee/client.js.map +1 -0
  17. package/dist/cognee/types.d.ts +46 -0
  18. package/dist/cognee/types.d.ts.map +1 -0
  19. package/dist/cognee/types.js +3 -0
  20. package/dist/cognee/types.js.map +1 -0
  21. package/dist/control/identity-manager.d.ts +22 -0
  22. package/dist/control/identity-manager.d.ts.map +1 -0
  23. package/dist/control/identity-manager.js +233 -0
  24. package/dist/control/identity-manager.js.map +1 -0
  25. package/dist/control/intent-router.d.ts +32 -0
  26. package/dist/control/intent-router.d.ts.map +1 -0
  27. package/dist/control/intent-router.js +242 -0
  28. package/dist/control/intent-router.js.map +1 -0
  29. package/dist/control/types.d.ts +68 -0
  30. package/dist/control/types.d.ts.map +1 -0
  31. package/dist/control/types.js +9 -0
  32. package/dist/control/types.js.map +1 -0
  33. package/dist/curator/curator.d.ts +29 -0
  34. package/dist/curator/curator.d.ts.map +1 -1
  35. package/dist/curator/curator.js +142 -5
  36. package/dist/curator/curator.js.map +1 -1
  37. package/dist/facades/types.d.ts +1 -1
  38. package/dist/governance/governance.d.ts +42 -0
  39. package/dist/governance/governance.d.ts.map +1 -0
  40. package/dist/governance/governance.js +488 -0
  41. package/dist/governance/governance.js.map +1 -0
  42. package/dist/governance/index.d.ts +3 -0
  43. package/dist/governance/index.d.ts.map +1 -0
  44. package/dist/governance/index.js +2 -0
  45. package/dist/governance/index.js.map +1 -0
  46. package/dist/governance/types.d.ts +102 -0
  47. package/dist/governance/types.d.ts.map +1 -0
  48. package/dist/governance/types.js +3 -0
  49. package/dist/governance/types.js.map +1 -0
  50. package/dist/index.d.ts +35 -3
  51. package/dist/index.d.ts.map +1 -1
  52. package/dist/index.js +32 -1
  53. package/dist/index.js.map +1 -1
  54. package/dist/llm/llm-client.d.ts.map +1 -1
  55. package/dist/llm/llm-client.js +9 -2
  56. package/dist/llm/llm-client.js.map +1 -1
  57. package/dist/logging/logger.d.ts +37 -0
  58. package/dist/logging/logger.d.ts.map +1 -0
  59. package/dist/logging/logger.js +145 -0
  60. package/dist/logging/logger.js.map +1 -0
  61. package/dist/logging/types.d.ts +19 -0
  62. package/dist/logging/types.d.ts.map +1 -0
  63. package/dist/logging/types.js +2 -0
  64. package/dist/logging/types.js.map +1 -0
  65. package/dist/loop/loop-manager.d.ts +49 -0
  66. package/dist/loop/loop-manager.d.ts.map +1 -0
  67. package/dist/loop/loop-manager.js +105 -0
  68. package/dist/loop/loop-manager.js.map +1 -0
  69. package/dist/loop/types.d.ts +35 -0
  70. package/dist/loop/types.d.ts.map +1 -0
  71. package/dist/loop/types.js +8 -0
  72. package/dist/loop/types.js.map +1 -0
  73. package/dist/planning/gap-analysis.d.ts +29 -0
  74. package/dist/planning/gap-analysis.d.ts.map +1 -0
  75. package/dist/planning/gap-analysis.js +265 -0
  76. package/dist/planning/gap-analysis.js.map +1 -0
  77. package/dist/planning/gap-types.d.ts +29 -0
  78. package/dist/planning/gap-types.d.ts.map +1 -0
  79. package/dist/planning/gap-types.js +28 -0
  80. package/dist/planning/gap-types.js.map +1 -0
  81. package/dist/planning/planner.d.ts +150 -1
  82. package/dist/planning/planner.d.ts.map +1 -1
  83. package/dist/planning/planner.js +365 -2
  84. package/dist/planning/planner.js.map +1 -1
  85. package/dist/project/project-registry.d.ts +79 -0
  86. package/dist/project/project-registry.d.ts.map +1 -0
  87. package/dist/project/project-registry.js +276 -0
  88. package/dist/project/project-registry.js.map +1 -0
  89. package/dist/project/types.d.ts +28 -0
  90. package/dist/project/types.d.ts.map +1 -0
  91. package/dist/project/types.js +5 -0
  92. package/dist/project/types.js.map +1 -0
  93. package/dist/runtime/admin-extra-ops.d.ts +13 -0
  94. package/dist/runtime/admin-extra-ops.d.ts.map +1 -0
  95. package/dist/runtime/admin-extra-ops.js +284 -0
  96. package/dist/runtime/admin-extra-ops.js.map +1 -0
  97. package/dist/runtime/admin-ops.d.ts +15 -0
  98. package/dist/runtime/admin-ops.d.ts.map +1 -0
  99. package/dist/runtime/admin-ops.js +322 -0
  100. package/dist/runtime/admin-ops.js.map +1 -0
  101. package/dist/runtime/capture-ops.d.ts +15 -0
  102. package/dist/runtime/capture-ops.d.ts.map +1 -0
  103. package/dist/runtime/capture-ops.js +345 -0
  104. package/dist/runtime/capture-ops.js.map +1 -0
  105. package/dist/runtime/core-ops.d.ts +7 -3
  106. package/dist/runtime/core-ops.d.ts.map +1 -1
  107. package/dist/runtime/core-ops.js +646 -15
  108. package/dist/runtime/core-ops.js.map +1 -1
  109. package/dist/runtime/curator-extra-ops.d.ts +9 -0
  110. package/dist/runtime/curator-extra-ops.d.ts.map +1 -0
  111. package/dist/runtime/curator-extra-ops.js +59 -0
  112. package/dist/runtime/curator-extra-ops.js.map +1 -0
  113. package/dist/runtime/domain-ops.d.ts.map +1 -1
  114. package/dist/runtime/domain-ops.js +59 -13
  115. package/dist/runtime/domain-ops.js.map +1 -1
  116. package/dist/runtime/grading-ops.d.ts +14 -0
  117. package/dist/runtime/grading-ops.d.ts.map +1 -0
  118. package/dist/runtime/grading-ops.js +105 -0
  119. package/dist/runtime/grading-ops.js.map +1 -0
  120. package/dist/runtime/loop-ops.d.ts +13 -0
  121. package/dist/runtime/loop-ops.d.ts.map +1 -0
  122. package/dist/runtime/loop-ops.js +179 -0
  123. package/dist/runtime/loop-ops.js.map +1 -0
  124. package/dist/runtime/memory-cross-project-ops.d.ts +12 -0
  125. package/dist/runtime/memory-cross-project-ops.d.ts.map +1 -0
  126. package/dist/runtime/memory-cross-project-ops.js +165 -0
  127. package/dist/runtime/memory-cross-project-ops.js.map +1 -0
  128. package/dist/runtime/memory-extra-ops.d.ts +13 -0
  129. package/dist/runtime/memory-extra-ops.d.ts.map +1 -0
  130. package/dist/runtime/memory-extra-ops.js +173 -0
  131. package/dist/runtime/memory-extra-ops.js.map +1 -0
  132. package/dist/runtime/orchestrate-ops.d.ts +17 -0
  133. package/dist/runtime/orchestrate-ops.d.ts.map +1 -0
  134. package/dist/runtime/orchestrate-ops.js +240 -0
  135. package/dist/runtime/orchestrate-ops.js.map +1 -0
  136. package/dist/runtime/planning-extra-ops.d.ts +17 -0
  137. package/dist/runtime/planning-extra-ops.d.ts.map +1 -0
  138. package/dist/runtime/planning-extra-ops.js +300 -0
  139. package/dist/runtime/planning-extra-ops.js.map +1 -0
  140. package/dist/runtime/project-ops.d.ts +15 -0
  141. package/dist/runtime/project-ops.d.ts.map +1 -0
  142. package/dist/runtime/project-ops.js +181 -0
  143. package/dist/runtime/project-ops.js.map +1 -0
  144. package/dist/runtime/runtime.d.ts.map +1 -1
  145. package/dist/runtime/runtime.js +48 -1
  146. package/dist/runtime/runtime.js.map +1 -1
  147. package/dist/runtime/types.d.ts +23 -0
  148. package/dist/runtime/types.d.ts.map +1 -1
  149. package/dist/runtime/vault-extra-ops.d.ts +9 -0
  150. package/dist/runtime/vault-extra-ops.d.ts.map +1 -0
  151. package/dist/runtime/vault-extra-ops.js +195 -0
  152. package/dist/runtime/vault-extra-ops.js.map +1 -0
  153. package/dist/telemetry/telemetry.d.ts +48 -0
  154. package/dist/telemetry/telemetry.d.ts.map +1 -0
  155. package/dist/telemetry/telemetry.js +87 -0
  156. package/dist/telemetry/telemetry.js.map +1 -0
  157. package/dist/vault/vault.d.ts +94 -0
  158. package/dist/vault/vault.d.ts.map +1 -1
  159. package/dist/vault/vault.js +340 -1
  160. package/dist/vault/vault.js.map +1 -1
  161. package/package.json +1 -1
  162. package/src/__tests__/admin-extra-ops.test.ts +420 -0
  163. package/src/__tests__/admin-ops.test.ts +271 -0
  164. package/src/__tests__/brain-intelligence.test.ts +828 -0
  165. package/src/__tests__/brain.test.ts +396 -27
  166. package/src/__tests__/capture-ops.test.ts +509 -0
  167. package/src/__tests__/cognee-client.test.ts +524 -0
  168. package/src/__tests__/core-ops.test.ts +341 -49
  169. package/src/__tests__/curator-extra-ops.test.ts +359 -0
  170. package/src/__tests__/curator.test.ts +126 -31
  171. package/src/__tests__/domain-ops.test.ts +111 -9
  172. package/src/__tests__/governance.test.ts +522 -0
  173. package/src/__tests__/grading-ops.test.ts +340 -0
  174. package/src/__tests__/identity-manager.test.ts +243 -0
  175. package/src/__tests__/intent-router.test.ts +222 -0
  176. package/src/__tests__/logger.test.ts +200 -0
  177. package/src/__tests__/loop-ops.test.ts +398 -0
  178. package/src/__tests__/memory-cross-project-ops.test.ts +246 -0
  179. package/src/__tests__/memory-extra-ops.test.ts +352 -0
  180. package/src/__tests__/orchestrate-ops.test.ts +284 -0
  181. package/src/__tests__/planner.test.ts +331 -0
  182. package/src/__tests__/planning-extra-ops.test.ts +548 -0
  183. package/src/__tests__/project-ops.test.ts +367 -0
  184. package/src/__tests__/runtime.test.ts +13 -11
  185. package/src/__tests__/vault-extra-ops.test.ts +407 -0
  186. package/src/brain/brain.ts +308 -72
  187. package/src/brain/intelligence.ts +1230 -0
  188. package/src/brain/types.ts +214 -0
  189. package/src/cognee/client.ts +352 -0
  190. package/src/cognee/types.ts +62 -0
  191. package/src/control/identity-manager.ts +354 -0
  192. package/src/control/intent-router.ts +326 -0
  193. package/src/control/types.ts +102 -0
  194. package/src/curator/curator.ts +265 -15
  195. package/src/governance/governance.ts +698 -0
  196. package/src/governance/index.ts +18 -0
  197. package/src/governance/types.ts +111 -0
  198. package/src/index.ts +128 -3
  199. package/src/llm/llm-client.ts +18 -24
  200. package/src/logging/logger.ts +154 -0
  201. package/src/logging/types.ts +21 -0
  202. package/src/loop/loop-manager.ts +130 -0
  203. package/src/loop/types.ts +44 -0
  204. package/src/planning/gap-analysis.ts +506 -0
  205. package/src/planning/gap-types.ts +58 -0
  206. package/src/planning/planner.ts +478 -2
  207. package/src/project/project-registry.ts +358 -0
  208. package/src/project/types.ts +31 -0
  209. package/src/runtime/admin-extra-ops.ts +307 -0
  210. package/src/runtime/admin-ops.ts +329 -0
  211. package/src/runtime/capture-ops.ts +385 -0
  212. package/src/runtime/core-ops.ts +747 -26
  213. package/src/runtime/curator-extra-ops.ts +71 -0
  214. package/src/runtime/domain-ops.ts +65 -13
  215. package/src/runtime/grading-ops.ts +121 -0
  216. package/src/runtime/loop-ops.ts +194 -0
  217. package/src/runtime/memory-cross-project-ops.ts +192 -0
  218. package/src/runtime/memory-extra-ops.ts +186 -0
  219. package/src/runtime/orchestrate-ops.ts +272 -0
  220. package/src/runtime/planning-extra-ops.ts +327 -0
  221. package/src/runtime/project-ops.ts +196 -0
  222. package/src/runtime/runtime.ts +54 -1
  223. package/src/runtime/types.ts +23 -0
  224. package/src/runtime/vault-extra-ops.ts +225 -0
  225. package/src/telemetry/telemetry.ts +118 -0
  226. package/src/vault/vault.ts +412 -1
@@ -0,0 +1,111 @@
1
+ // ─── Policy Types ───────────────────────────────────────────────────
2
+
3
+ export type PolicyType = 'quota' | 'retention' | 'auto-capture';
4
+ export type PolicyPreset = 'strict' | 'moderate' | 'permissive';
5
+ export type PolicyAction = 'capture' | 'quarantine' | 'reject' | 'propose';
6
+
7
+ export interface QuotaPolicy {
8
+ maxEntriesTotal: number;
9
+ maxEntriesPerCategory: number;
10
+ maxEntriesPerType: number;
11
+ warnAtPercent: number;
12
+ }
13
+
14
+ export interface RetentionPolicy {
15
+ archiveAfterDays: number;
16
+ minHitsToKeep: number;
17
+ deleteArchivedAfterDays: number;
18
+ }
19
+
20
+ export interface AutoCapturePolicy {
21
+ enabled: boolean;
22
+ requireReview: boolean;
23
+ maxPendingProposals: number;
24
+ autoExpireDays: number;
25
+ }
26
+
27
+ export interface VaultPolicy {
28
+ projectPath: string;
29
+ quotas: QuotaPolicy;
30
+ retention: RetentionPolicy;
31
+ autoCapture: AutoCapturePolicy;
32
+ }
33
+
34
+ export interface QuotaStatus {
35
+ total: number;
36
+ maxTotal: number;
37
+ byCategory: Record<string, number>;
38
+ byType: Record<string, number>;
39
+ warnAtPercent: number;
40
+ isWarning: boolean;
41
+ }
42
+
43
+ export interface PolicyDecision {
44
+ allowed: boolean;
45
+ action: PolicyAction;
46
+ reason?: string;
47
+ quotaStatus?: QuotaStatus;
48
+ }
49
+
50
+ export interface BatchDecision {
51
+ entry: { type: string; category: string; title?: string };
52
+ decision: PolicyDecision;
53
+ }
54
+
55
+ export interface PolicyAuditEntry {
56
+ id: number;
57
+ projectPath: string;
58
+ policyType: string;
59
+ oldConfig: Record<string, unknown> | null;
60
+ newConfig: Record<string, unknown>;
61
+ changedBy: string | null;
62
+ changedAt: number;
63
+ }
64
+
65
+ // ─── Proposal Types ─────────────────────────────────────────────────
66
+
67
+ export type ProposalStatus = 'pending' | 'approved' | 'rejected' | 'modified' | 'expired';
68
+
69
+ export interface Proposal {
70
+ id: number;
71
+ projectPath: string;
72
+ entryId: string | null;
73
+ title: string;
74
+ type: string;
75
+ category: string;
76
+ proposedData: Record<string, unknown>;
77
+ status: ProposalStatus;
78
+ proposedAt: number;
79
+ decidedAt: number | null;
80
+ decidedBy: string | null;
81
+ modificationNote: string | null;
82
+ source: string;
83
+ }
84
+
85
+ export interface ProposalStats {
86
+ total: number;
87
+ pending: number;
88
+ approved: number;
89
+ rejected: number;
90
+ modified: number;
91
+ expired: number;
92
+ acceptanceRate: number;
93
+ byCategory: Record<string, { total: number; accepted: number; rate: number }>;
94
+ }
95
+
96
+ // ─── Dashboard ──────────────────────────────────────────────────────
97
+
98
+ export interface GovernanceDashboard {
99
+ vaultSize: number;
100
+ quotaPercent: number;
101
+ quotaStatus: QuotaStatus;
102
+ pendingProposals: number;
103
+ acceptanceRate: number;
104
+ evaluationTrend: Record<string, number>;
105
+ policySummary: {
106
+ maxEntries: number;
107
+ requireReview: boolean;
108
+ archiveAfterDays: number;
109
+ autoExpireDays: number;
110
+ };
111
+ }
package/src/index.ts CHANGED
@@ -37,8 +37,29 @@ export type {
37
37
  CuratorStatus,
38
38
  } from './curator/types.js';
39
39
 
40
+ // ─── Governance ─────────────────────────────────────────────────────
41
+ export { Governance } from './governance/governance.js';
42
+ export type {
43
+ PolicyType,
44
+ PolicyPreset,
45
+ PolicyAction,
46
+ QuotaPolicy,
47
+ RetentionPolicy,
48
+ AutoCapturePolicy,
49
+ VaultPolicy,
50
+ QuotaStatus,
51
+ PolicyDecision,
52
+ BatchDecision,
53
+ PolicyAuditEntry,
54
+ ProposalStatus,
55
+ Proposal,
56
+ ProposalStats,
57
+ GovernanceDashboard,
58
+ } from './governance/types.js';
59
+
40
60
  // ─── Brain ───────────────────────────────────────────────────────────
41
61
  export { Brain } from './brain/brain.js';
62
+ export { BrainIntelligence } from './brain/intelligence.js';
42
63
  export type {
43
64
  ScoringWeights,
44
65
  ScoreBreakdown,
@@ -47,11 +68,74 @@ export type {
47
68
  CaptureResult,
48
69
  BrainStats,
49
70
  QueryContext,
50
- } from './brain/brain.js';
71
+ FeedbackType,
72
+ FeedbackSource,
73
+ FeedbackInput,
74
+ FeedbackEntry,
75
+ FeedbackStats,
76
+ PatternStrength,
77
+ StrengthsQuery,
78
+ BrainSession,
79
+ SessionLifecycleInput,
80
+ KnowledgeProposal,
81
+ ExtractionResult,
82
+ GlobalPattern,
83
+ DomainProfile,
84
+ BuildIntelligenceResult,
85
+ BrainIntelligenceStats,
86
+ SessionContext,
87
+ BrainExportData,
88
+ BrainImportResult,
89
+ } from './brain/types.js';
90
+
91
+ // ─── Cognee ─────────────────────────────────────────────────────────
92
+ export { CogneeClient } from './cognee/client.js';
93
+ export type {
94
+ CogneeConfig,
95
+ CogneeSearchResult,
96
+ CogneeSearchType,
97
+ CogneeStatus,
98
+ CogneeAddResult,
99
+ CogneeCognifyResult,
100
+ } from './cognee/types.js';
51
101
 
52
102
  // ─── Planning ────────────────────────────────────────────────────────
53
- export { Planner } from './planning/planner.js';
54
- export type { PlanStatus, TaskStatus, PlanTask, Plan, PlanStore } from './planning/planner.js';
103
+ export { Planner, calculateScore } from './planning/planner.js';
104
+ export type {
105
+ PlanStatus,
106
+ TaskStatus,
107
+ PlanTask,
108
+ Plan,
109
+ PlanStore,
110
+ DriftItem,
111
+ ReconciliationReport,
112
+ ReviewEvidence,
113
+ PlanGrade,
114
+ PlanCheck,
115
+ } from './planning/planner.js';
116
+
117
+ // ─── Plan Gap Analysis ──────────────────────────────────────────────
118
+ export { runGapAnalysis } from './planning/gap-analysis.js';
119
+ export type { GapAnalysisOptions, GapAnalysisPass } from './planning/gap-analysis.js';
120
+ export {
121
+ SEVERITY_WEIGHTS,
122
+ CATEGORY_PENALTY_CAPS,
123
+ MIN_OBJECTIVE_LENGTH,
124
+ MIN_SCOPE_LENGTH,
125
+ MIN_DECISION_LENGTH,
126
+ generateGapId,
127
+ } from './planning/gap-types.js';
128
+ export type { GapSeverity, GapCategory, PlanGap } from './planning/gap-types.js';
129
+
130
+ // ─── Loop ────────────────────────────────────────────────────────────
131
+ export { LoopManager } from './loop/loop-manager.js';
132
+ export type {
133
+ LoopMode,
134
+ LoopConfig,
135
+ LoopIteration,
136
+ LoopStatus,
137
+ LoopState,
138
+ } from './loop/types.js';
55
139
 
56
140
  // ─── LLM Types ───────────────────────────────────────────────────────
57
141
  export { SecretString, LLMError } from './llm/types.js';
@@ -97,8 +181,49 @@ export type {
97
181
  // ─── LLM Client ─────────────────────────────────────────────────────
98
182
  export { LLMClient } from './llm/llm-client.js';
99
183
 
184
+ // ─── Control ────────────────────────────────────────────────────────
185
+ export { IdentityManager } from './control/identity-manager.js';
186
+ export { IntentRouter } from './control/intent-router.js';
187
+ export type {
188
+ GuidelineCategory,
189
+ Guideline,
190
+ AgentIdentity,
191
+ IdentityVersion,
192
+ IdentityUpdateInput,
193
+ GuidelineInput,
194
+ IntentType,
195
+ OperationalMode,
196
+ IntentClassification,
197
+ ModeConfig,
198
+ MorphResult,
199
+ } from './control/types.js';
200
+
201
+ // ─── Project Registry ──────────────────────────────────────────────
202
+ export { ProjectRegistry } from './project/project-registry.js';
203
+ export type { RegisteredProject, ProjectRule, LinkType, ProjectLink } from './project/types.js';
204
+
205
+ // ─── Telemetry ─────────────────────────────────────────────────────
206
+ export { Telemetry } from './telemetry/telemetry.js';
207
+ export type { FacadeCall, TelemetryStats } from './telemetry/telemetry.js';
208
+
209
+ // ─── Logging ────────────────────────────────────────────────────────
210
+ export { Logger, createLogger } from './logging/logger.js';
211
+ export type { LogLevel, LogEntry, LogContext, LoggerConfig } from './logging/types.js';
212
+
100
213
  // ─── Runtime Factory ────────────────────────────────────────────────
101
214
  export { createAgentRuntime } from './runtime/runtime.js';
102
215
  export { createCoreOps } from './runtime/core-ops.js';
103
216
  export { createDomainFacade, createDomainFacades } from './runtime/domain-ops.js';
217
+ export { createPlanningExtraOps } from './runtime/planning-extra-ops.js';
218
+ export { createMemoryExtraOps } from './runtime/memory-extra-ops.js';
219
+ export { createVaultExtraOps } from './runtime/vault-extra-ops.js';
220
+ export { createAdminOps } from './runtime/admin-ops.js';
221
+ export { createAdminExtraOps } from './runtime/admin-extra-ops.js';
222
+ export { createLoopOps } from './runtime/loop-ops.js';
223
+ export { createOrchestrateOps } from './runtime/orchestrate-ops.js';
224
+ export { createGradingOps } from './runtime/grading-ops.js';
225
+ export { createCaptureOps } from './runtime/capture-ops.js';
226
+ export { createCuratorExtraOps } from './runtime/curator-extra-ops.js';
227
+ export { createProjectOps } from './runtime/project-ops.js';
228
+ export { createMemoryCrossProjectOps } from './runtime/memory-cross-project-ops.js';
104
229
  export type { AgentRuntimeConfig, AgentRuntime } from './runtime/types.js';
@@ -11,12 +11,7 @@ import * as path from 'node:path';
11
11
  import { homedir } from 'node:os';
12
12
  import { LLMError } from './types.js';
13
13
  import { CircuitBreaker, retry, parseRateLimitHeaders } from './utils.js';
14
- import type {
15
- LLMCallOptions,
16
- LLMCallResult,
17
- RouteEntry,
18
- RoutingConfig,
19
- } from './types.js';
14
+ import type { LLMCallOptions, LLMCallResult, RouteEntry, RoutingConfig } from './types.js';
20
15
  import type { KeyPool } from './key-pool.js';
21
16
 
22
17
  // =============================================================================
@@ -69,7 +64,11 @@ class ModelRouter {
69
64
  private config: RoutingConfig;
70
65
 
71
66
  constructor(config?: RoutingConfig) {
72
- this.config = config ?? { routes: [], defaultOpenAIModel: 'gpt-4o-mini', defaultAnthropicModel: 'claude-sonnet-4-20250514' };
67
+ this.config = config ?? {
68
+ routes: [],
69
+ defaultOpenAIModel: 'gpt-4o-mini',
70
+ defaultAnthropicModel: 'claude-sonnet-4-20250514',
71
+ };
73
72
  }
74
73
 
75
74
  resolve(
@@ -78,17 +77,13 @@ class ModelRouter {
78
77
  originalModel?: string,
79
78
  ): { model: string; provider: 'openai' | 'anthropic' } {
80
79
  if (task) {
81
- const exactMatch = this.config.routes.find(
82
- (r) => r.caller === caller && r.task === task,
83
- );
80
+ const exactMatch = this.config.routes.find((r) => r.caller === caller && r.task === task);
84
81
  if (exactMatch) {
85
82
  return { model: exactMatch.model, provider: exactMatch.provider };
86
83
  }
87
84
  }
88
85
 
89
- const callerMatch = this.config.routes.find(
90
- (r) => r.caller === caller && !r.task,
91
- );
86
+ const callerMatch = this.config.routes.find((r) => r.caller === caller && !r.task);
92
87
  if (callerMatch) {
93
88
  return { model: callerMatch.model, provider: callerMatch.provider };
94
89
  }
@@ -148,11 +143,7 @@ export class LLMClient {
148
143
  }
149
144
 
150
145
  async complete(options: LLMCallOptions): Promise<LLMCallResult> {
151
- const routed = this.router.resolve(
152
- options.caller,
153
- options.task,
154
- options.model,
155
- );
146
+ const routed = this.router.resolve(options.caller, options.task, options.model);
156
147
  const resolvedOptions = { ...options, model: routed.model, provider: routed.provider };
157
148
 
158
149
  return resolvedOptions.provider === 'anthropic'
@@ -219,10 +210,10 @@ export class LLMClient {
219
210
  }
220
211
 
221
212
  const errorBody = await response.text();
222
- throw new LLMError(
223
- `OpenAI API error: ${response.status} - ${errorBody}`,
224
- { retryable: response.status === 429 || response.status >= 500, statusCode: response.status },
225
- );
213
+ throw new LLMError(`OpenAI API error: ${response.status} - ${errorBody}`, {
214
+ retryable: response.status === 429 || response.status >= 500,
215
+ statusCode: response.status,
216
+ });
226
217
  }
227
218
 
228
219
  const data = (await response.json()) as {
@@ -270,7 +261,8 @@ export class LLMClient {
270
261
 
271
262
  const text = response.content
272
263
  .filter(
273
- (block): block is { type: 'text'; text: string } => block.type === 'text' && typeof block.text === 'string',
264
+ (block): block is { type: 'text'; text: string } =>
265
+ block.type === 'text' && typeof block.text === 'string',
274
266
  )
275
267
  .map((block) => block.text)
276
268
  .join('\n');
@@ -305,7 +297,9 @@ export class LLMClient {
305
297
  try {
306
298
  // Dynamic import — @anthropic-ai/sdk is an optional peer dep.
307
299
  // eslint-disable-next-line @typescript-eslint/no-require-imports
308
- const mod = await (Function('return import("@anthropic-ai/sdk")')() as Promise<{ default: new (opts: { apiKey: string }) => AnthropicClient }>);
300
+ const mod = await (Function('return import("@anthropic-ai/sdk")')() as Promise<{
301
+ default: new (opts: { apiKey: string }) => AnthropicClient;
302
+ }>);
309
303
  this.anthropicClient = new mod.default({ apiKey: currentKey });
310
304
  return this.anthropicClient;
311
305
  } catch {
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Structured logger for Soleri agents.
3
+ *
4
+ * All output routes through stderr (stdout is reserved for MCP JSON-RPC).
5
+ * Supports optional file logging with daily rotation and 7-day retention.
6
+ *
7
+ * Ported from Salvador MCP's src/utils/logger.ts.
8
+ */
9
+
10
+ import { appendFileSync, mkdirSync, readdirSync, unlinkSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import type { LogLevel, LogContext, LoggerConfig } from './types.js';
13
+
14
+ const LEVEL_ORDER: LogLevel[] = ['debug', 'info', 'warn', 'error'];
15
+
16
+ // MCP stdio servers must keep stdout clean for JSON-RPC.
17
+ // Route ALL log levels through stderr (console.error/console.warn).
18
+ const LEVEL_METHODS: Record<LogLevel, 'warn' | 'error'> = {
19
+ debug: 'error',
20
+ info: 'error',
21
+ warn: 'warn',
22
+ error: 'error',
23
+ };
24
+
25
+ /** Max age for log files before auto-pruning (7 days) */
26
+ const LOG_RETENTION_DAYS = 7;
27
+
28
+ export class Logger {
29
+ private readonly prefix: string;
30
+ private readonly minLevel: number;
31
+ private fileLogDir: string | null = null;
32
+ private fileLogPrefix: string;
33
+ private currentLogDate: string | null = null;
34
+ private currentLogPath: string | null = null;
35
+
36
+ constructor(config?: LoggerConfig) {
37
+ this.prefix = config?.prefix ?? '[Soleri]';
38
+ this.fileLogPrefix = 'agent';
39
+ const envLevel = process.env.SOLERI_LOG_LEVEL as LogLevel | undefined;
40
+ const level = config?.level ?? envLevel ?? 'info';
41
+ const levelIndex = LEVEL_ORDER.indexOf(level);
42
+ this.minLevel = levelIndex >= 0 ? levelIndex : LEVEL_ORDER.indexOf('info');
43
+
44
+ if (config?.fileLogDir) {
45
+ this.enableFileLog(config.fileLogDir);
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Enable file-based logging. Output is teed to
51
+ * {dir}/{prefix}-YYYY-MM-DD.log in addition to stderr.
52
+ * Automatically prunes log files older than 7 days.
53
+ */
54
+ enableFileLog(dir: string, prefix?: string): void {
55
+ mkdirSync(dir, { recursive: true });
56
+ this.fileLogDir = dir;
57
+ if (prefix) this.fileLogPrefix = prefix;
58
+ this.rotateFileIfNeeded();
59
+ this.pruneOldLogs();
60
+ }
61
+
62
+ debug(message: string, context?: LogContext): void {
63
+ this.log('debug', message, context);
64
+ }
65
+
66
+ info(message: string, context?: LogContext): void {
67
+ this.log('info', message, context);
68
+ }
69
+
70
+ warn(message: string, context?: LogContext): void {
71
+ this.log('warn', message, context);
72
+ }
73
+
74
+ error(message: string, context?: LogContext): void {
75
+ this.log('error', message, context);
76
+ }
77
+
78
+ private log(level: LogLevel, message: string, context?: LogContext): void {
79
+ if (LEVEL_ORDER.indexOf(level) < this.minLevel) return;
80
+ const method = LEVEL_METHODS[level];
81
+ const tag = level.toUpperCase();
82
+
83
+ // Console output (stderr)
84
+ if (context) {
85
+ console[method](`${this.prefix}[${tag}] ${message}`, context);
86
+ } else {
87
+ console[method](`${this.prefix}[${tag}] ${message}`);
88
+ }
89
+
90
+ // File output (if enabled)
91
+ if (this.fileLogDir) {
92
+ this.writeToFile(tag, message, context);
93
+ }
94
+ }
95
+
96
+ private writeToFile(tag: string, message: string, context?: LogContext): void {
97
+ this.rotateFileIfNeeded();
98
+ if (!this.currentLogPath) return;
99
+
100
+ const ts = new Date().toISOString();
101
+ let line = `${ts} [${tag}] ${message}`;
102
+ if (context) {
103
+ try {
104
+ line += ' ' + JSON.stringify(context);
105
+ } catch {
106
+ // Skip unserializable context
107
+ }
108
+ }
109
+ try {
110
+ appendFileSync(this.currentLogPath, line + '\n');
111
+ } catch {
112
+ // Silently fail — file logging should never break the app
113
+ }
114
+ }
115
+
116
+ /** Switch to a new log file if the date has changed */
117
+ private rotateFileIfNeeded(): void {
118
+ if (!this.fileLogDir) return;
119
+ const today = new Date().toISOString().slice(0, 10); // YYYY-MM-DD
120
+ if (today !== this.currentLogDate) {
121
+ this.currentLogDate = today;
122
+ this.currentLogPath = join(this.fileLogDir, `${this.fileLogPrefix}-${today}.log`);
123
+ }
124
+ }
125
+
126
+ /** Remove log files older than LOG_RETENTION_DAYS */
127
+ private pruneOldLogs(): void {
128
+ if (!this.fileLogDir) return;
129
+ const prefix = this.fileLogPrefix;
130
+ try {
131
+ const cutoff = Date.now() - LOG_RETENTION_DAYS * 24 * 60 * 60 * 1000;
132
+ const files = readdirSync(this.fileLogDir);
133
+ for (const file of files) {
134
+ if (!file.startsWith(`${prefix}-`) || !file.endsWith('.log')) continue;
135
+ const dateStr = file.slice(`${prefix}-`.length, -'.log'.length);
136
+ const fileDate = new Date(dateStr).getTime();
137
+ if (!isNaN(fileDate) && fileDate < cutoff) {
138
+ try {
139
+ unlinkSync(join(this.fileLogDir, file));
140
+ } catch {
141
+ // Ignore individual file deletion errors
142
+ }
143
+ }
144
+ }
145
+ } catch {
146
+ // Ignore pruning errors
147
+ }
148
+ }
149
+ }
150
+
151
+ /** Factory function for creating a logger. */
152
+ export function createLogger(config?: LoggerConfig): Logger {
153
+ return new Logger(config);
154
+ }
@@ -0,0 +1,21 @@
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
2
+
3
+ export interface LogContext {
4
+ [key: string]: unknown;
5
+ }
6
+
7
+ export interface LogEntry {
8
+ level: LogLevel;
9
+ message: string;
10
+ context?: LogContext;
11
+ timestamp: string;
12
+ }
13
+
14
+ export interface LoggerConfig {
15
+ /** Minimum log level. Default: 'info' (or SOLERI_LOG_LEVEL env var) */
16
+ level?: LogLevel;
17
+ /** Prefix for log messages. Default: '[Soleri]' */
18
+ prefix?: string;
19
+ /** Directory for file logging. If set, enables file output on construction. */
20
+ fileLogDir?: string;
21
+ }
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Loop manager — lightweight in-memory state tracker for iterative
3
+ * validation loops.
4
+ *
5
+ * Tracks active loop, iteration history, and past loop results.
6
+ * Session-scoped (no persistence across restarts).
7
+ */
8
+
9
+ import type { LoopConfig, LoopIteration, LoopState } from './types.js';
10
+
11
+ export class LoopManager {
12
+ private activeLoop: LoopState | null = null;
13
+ private completedLoops: LoopState[] = [];
14
+
15
+ /**
16
+ * Start a new validation loop.
17
+ * Throws if a loop is already active.
18
+ */
19
+ startLoop(config: LoopConfig): LoopState {
20
+ if (this.activeLoop) {
21
+ throw new Error(
22
+ `Loop already active: ${this.activeLoop.id} (mode: ${this.activeLoop.config.mode}). ` +
23
+ 'Cancel or complete it first.',
24
+ );
25
+ }
26
+
27
+ const loop: LoopState = {
28
+ id: `loop-${Date.now()}`,
29
+ config,
30
+ iterations: [],
31
+ status: 'active',
32
+ startedAt: new Date().toISOString(),
33
+ };
34
+
35
+ this.activeLoop = loop;
36
+ return loop;
37
+ }
38
+
39
+ /**
40
+ * Record an iteration result on the active loop.
41
+ * If the iteration passes, the loop status is NOT automatically changed —
42
+ * call `completeLoop()` explicitly when validation is confirmed.
43
+ * If max iterations reached and this iteration fails, status becomes 'max-iterations'.
44
+ */
45
+ iterate(result: {
46
+ validationScore?: number;
47
+ validationResult?: string;
48
+ passed: boolean;
49
+ }): LoopIteration {
50
+ if (!this.activeLoop) {
51
+ throw new Error('No active loop. Start one first.');
52
+ }
53
+
54
+ const iteration: LoopIteration = {
55
+ iteration: this.activeLoop.iterations.length + 1,
56
+ timestamp: new Date().toISOString(),
57
+ validationScore: result.validationScore,
58
+ validationResult: result.validationResult,
59
+ passed: result.passed,
60
+ };
61
+
62
+ this.activeLoop.iterations.push(iteration);
63
+
64
+ // Auto-transition to max-iterations if limit reached and not passing
65
+ if (
66
+ !result.passed &&
67
+ this.activeLoop.iterations.length >= this.activeLoop.config.maxIterations
68
+ ) {
69
+ this.activeLoop.status = 'max-iterations';
70
+ this.activeLoop.completedAt = new Date().toISOString();
71
+ this.completedLoops.push(this.activeLoop);
72
+ this.activeLoop = null;
73
+ }
74
+
75
+ return iteration;
76
+ }
77
+
78
+ /**
79
+ * Mark the active loop as completed (validation passed).
80
+ */
81
+ completeLoop(): LoopState {
82
+ if (!this.activeLoop) {
83
+ throw new Error('No active loop to complete.');
84
+ }
85
+
86
+ this.activeLoop.status = 'completed';
87
+ this.activeLoop.completedAt = new Date().toISOString();
88
+ const completed = this.activeLoop;
89
+ this.completedLoops.push(completed);
90
+ this.activeLoop = null;
91
+ return completed;
92
+ }
93
+
94
+ /**
95
+ * Cancel the active loop.
96
+ */
97
+ cancelLoop(): LoopState {
98
+ if (!this.activeLoop) {
99
+ throw new Error('No active loop to cancel.');
100
+ }
101
+
102
+ this.activeLoop.status = 'cancelled';
103
+ this.activeLoop.completedAt = new Date().toISOString();
104
+ const cancelled = this.activeLoop;
105
+ this.completedLoops.push(cancelled);
106
+ this.activeLoop = null;
107
+ return cancelled;
108
+ }
109
+
110
+ /**
111
+ * Get current loop status. Returns null if no active loop.
112
+ */
113
+ getStatus(): LoopState | null {
114
+ return this.activeLoop;
115
+ }
116
+
117
+ /**
118
+ * Get history of all completed/cancelled/max-iterations loops.
119
+ */
120
+ getHistory(): LoopState[] {
121
+ return [...this.completedLoops];
122
+ }
123
+
124
+ /**
125
+ * Check if a loop is currently active.
126
+ */
127
+ isActive(): boolean {
128
+ return this.activeLoop !== null;
129
+ }
130
+ }