@lssm/lib.evolution 0.0.0-canary-20251217054315 → 0.0.0-canary-20251217060433
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analyzer/spec-analyzer.d.ts +34 -0
- package/dist/analyzer/spec-analyzer.js +1 -1
- package/dist/approval/integration.d.ts +42 -0
- package/dist/approval/integration.js +1 -1
- package/dist/generator/ai-spec-generator.d.ts +55 -0
- package/dist/generator/spec-generator.d.ts +46 -0
- package/dist/generator/spec-generator.js +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/types.d.ts +131 -0
- package/package.json +9 -9
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { IntentPattern, OperationMetricSample, OptimizationHint, SpecAnomaly, SpecUsageStats } from "../types.js";
|
|
2
|
+
import { Logger } from "@lssm/lib.observability";
|
|
3
|
+
import { LifecycleStage } from "@lssm/lib.lifecycle";
|
|
4
|
+
|
|
5
|
+
//#region src/analyzer/spec-analyzer.d.ts
|
|
6
|
+
interface SpecAnalyzerOptions {
|
|
7
|
+
logger?: Logger;
|
|
8
|
+
minSampleSize?: number;
|
|
9
|
+
errorRateThreshold?: number;
|
|
10
|
+
latencyP99ThresholdMs?: number;
|
|
11
|
+
throughputDropThreshold?: number;
|
|
12
|
+
}
|
|
13
|
+
declare class SpecAnalyzer {
|
|
14
|
+
private readonly logger?;
|
|
15
|
+
private readonly minSampleSize;
|
|
16
|
+
private readonly errorRateThreshold;
|
|
17
|
+
private readonly latencyP99ThresholdMs;
|
|
18
|
+
private readonly throughputDropThreshold;
|
|
19
|
+
constructor(options?: SpecAnalyzerOptions);
|
|
20
|
+
analyzeSpecUsage(samples: OperationMetricSample[]): SpecUsageStats[];
|
|
21
|
+
detectAnomalies(stats: SpecUsageStats[], baseline?: SpecUsageStats[]): SpecAnomaly[];
|
|
22
|
+
toIntentPatterns(anomalies: SpecAnomaly[], stats: SpecUsageStats[]): IntentPattern[];
|
|
23
|
+
suggestOptimizations(stats: SpecUsageStats[], anomalies: SpecAnomaly[], lifecycleContext?: {
|
|
24
|
+
stage: LifecycleStage;
|
|
25
|
+
}): OptimizationHint[];
|
|
26
|
+
private operationKey;
|
|
27
|
+
private buildUsageStats;
|
|
28
|
+
private toSeverity;
|
|
29
|
+
private mapMetricToIntent;
|
|
30
|
+
private groupByOperation;
|
|
31
|
+
private applyLifecycleContext;
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
export { SpecAnalyzer, SpecAnalyzerOptions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"@lssm/lib.observability";import{randomUUID as
|
|
1
|
+
import{Logger as e}from"@lssm/lib.observability";import{randomUUID as t}from"node:crypto";import{LifecycleStage as n}from"@lssm/lib.lifecycle";const r={minSampleSize:50,errorRateThreshold:.05,latencyP99ThresholdMs:750};var i=class{logger;minSampleSize;errorRateThreshold;latencyP99ThresholdMs;throughputDropThreshold;constructor(e={}){this.logger=e.logger,this.minSampleSize=e.minSampleSize??r.minSampleSize,this.errorRateThreshold=e.errorRateThreshold??r.errorRateThreshold,this.latencyP99ThresholdMs=e.latencyP99ThresholdMs??r.latencyP99ThresholdMs,this.throughputDropThreshold=e.throughputDropThreshold??.2}analyzeSpecUsage(e){if(!e.length)return this.logger?.debug(`SpecAnalyzer.analyzeSpecUsage.skip`,{reason:`no-samples`}),[];let t=new Map;for(let n of e){let e=this.operationKey(n),r=t.get(e)??[];r.push(n),t.set(e,r)}return[...t.values()].filter(e=>{let t=e.length>=this.minSampleSize;return t||this.logger?.debug(`SpecAnalyzer.analyzeSpecUsage.skipOperation`,{operation:this.operationKey(e[0]),sampleSize:e.length,minSampleSize:this.minSampleSize}),t}).map(e=>this.buildUsageStats(e))}detectAnomalies(e,t){let n=[];if(!e.length)return this.logger?.debug(`SpecAnalyzer.detectAnomalies.skip`,{reason:`no-stats`}),n;let r=new Map((t??[]).map(e=>[this.operationKey(e.operation),e]));for(let t of e){let e=[];if(t.errorRate>=this.errorRateThreshold){e.push({type:`telemetry`,description:`Error rate ${t.errorRate.toFixed(2)} exceeded threshold ${this.errorRateThreshold}`,data:{errorRate:t.errorRate}}),n.push({operation:t.operation,severity:this.toSeverity(t.errorRate/this.errorRateThreshold),metric:`error-rate`,description:`Error rate spike`,detectedAt:new Date,threshold:this.errorRateThreshold,observedValue:t.errorRate,evidence:e});continue}if(t.p99LatencyMs>=this.latencyP99ThresholdMs){e.push({type:`telemetry`,description:`P99 latency ${t.p99LatencyMs}ms exceeded threshold ${this.latencyP99ThresholdMs}ms`,data:{p99LatencyMs:t.p99LatencyMs}}),n.push({operation:t.operation,severity:this.toSeverity(t.p99LatencyMs/this.latencyP99ThresholdMs),metric:`latency`,description:`Latency regression detected`,detectedAt:new Date,threshold:this.latencyP99ThresholdMs,observedValue:t.p99LatencyMs,evidence:e});continue}let i=r.get(this.operationKey(t.operation));if(i){let r=(i.totalCalls-t.totalCalls)/i.totalCalls;r>=this.throughputDropThreshold&&(e.push({type:`telemetry`,description:`Throughput dropped by ${(r*100).toFixed(1)}% compared to baseline`,data:{baselineCalls:i.totalCalls,currentCalls:t.totalCalls}}),n.push({operation:t.operation,severity:this.toSeverity(r/this.throughputDropThreshold),metric:`throughput`,description:`Usage drop detected`,detectedAt:new Date,threshold:this.throughputDropThreshold,observedValue:r,evidence:e}))}}return n}toIntentPatterns(e,n){let r=new Map(n.map(e=>[this.operationKey(e.operation),e]));return e.map(e=>{let n=r.get(this.operationKey(e.operation)),i={score:Math.min(1,(e.observedValue??0)/(e.threshold??1)),sampleSize:n?.totalCalls??0,pValue:void 0};return{id:t(),type:this.mapMetricToIntent(e.metric),description:e.description,operation:e.operation,confidence:i,metadata:{observedValue:e.observedValue,threshold:e.threshold},evidence:e.evidence}})}suggestOptimizations(e,t,n){let r=new Map(this.groupByOperation(t)),i=[];for(let t of e){let e=this.operationKey(t.operation),a=r.get(e)??[];for(let e of a)if(e.metric===`latency`)i.push(this.applyLifecycleContext({operation:t.operation,category:`performance`,summary:`Latency regression detected`,justification:`P99 latency at ${t.p99LatencyMs}ms`,recommendedActions:[`Add batching or caching layer`,`Replay golden tests to capture slow inputs`]},n?.stage));else if(e.metric===`error-rate`){let e=Object.entries(t.topErrors).sort((e,t)=>t[1]-e[1])[0]?.[0];i.push(this.applyLifecycleContext({operation:t.operation,category:`error-handling`,summary:`Error spike detected`,justification:e?`Dominant error code ${e}`:`Increase in failures`,recommendedActions:[`Generate regression spec from failing payloads`,`Add policy guardrails before rollout`]},n?.stage))}else e.metric===`throughput`&&i.push(this.applyLifecycleContext({operation:t.operation,category:`performance`,summary:`Throughput drop detected`,justification:`Significant traffic reduction relative to baseline`,recommendedActions:[`Validate routing + feature flag bucketing`,`Backfill spec variant to rehydrate demand`]},n?.stage))}return i}operationKey(e){let t=`operation`in e?e.operation:e;return`${t.name}.v${t.version}${t.tenantId?`@${t.tenantId}`:``}`}buildUsageStats(e){let t=e.map(e=>e.durationMs).sort((e,t)=>e-t),n=e.filter(e=>!e.success),r=e.length,i=(r-n.length)/r,o=n.length/r,s=t.reduce((e,t)=>e+t,0)/r,c=n.reduce((e,t)=>(t.errorCode&&(e[t.errorCode]=(e[t.errorCode]??0)+1),e),{}),l=e.map(e=>e.timestamp.getTime()),u=new Date(Math.min(...l)),d=new Date(Math.max(...l));return{operation:e[0].operation,totalCalls:r,successRate:i,errorRate:o,averageLatencyMs:s,p95LatencyMs:a(t,.95),p99LatencyMs:a(t,.99),maxLatencyMs:Math.max(...t),lastSeenAt:d,windowStart:u,windowEnd:d,topErrors:c}}toSeverity(e){return e>=2?`high`:e>=1.3?`medium`:`low`}mapMetricToIntent(e){switch(e){case`error-rate`:return`error-spike`;case`latency`:return`latency-regression`;case`throughput`:return`throughput-drop`;default:return`schema-mismatch`}}groupByOperation(e){let t=new Map;for(let n of e){let e=this.operationKey(n.operation),r=t.get(e)??[];r.push(n),t.set(e,r)}return t}applyLifecycleContext(e,t){if(t===void 0)return e;let n=s[o(t)]?.[e.category];return n?{...e,lifecycleStage:t,lifecycleNotes:n.message,recommendedActions:c([...e.recommendedActions,...n.supplementalActions])}:{...e,lifecycleStage:t}}};function a(e,t){return e.length?e.length===1?e[0]:e[Math.min(e.length-1,Math.floor(t*e.length))]:0}const o=e=>e<=2?`early`:e===n.ProductMarketFit?`pmf`:e===n.GrowthScaleUp||e===n.ExpansionPlatform?`scale`:`mature`,s={early:{performance:{message:`Favor guardrails that protect learning velocity before heavy rewrites.`,supplementalActions:[`Wrap risky changes behind progressive delivery flags`]},"error-handling":{message:`Make failures loud and recoverable so you can learn faster.`,supplementalActions:[`Add auto-rollbacks or manual kill switches`]}},pmf:{performance:{message:`Stabilize the core use case to avoid regressions while demand grows.`,supplementalActions:[`Instrument regression tests on critical specs`]}},scale:{performance:{message:`Prioritize resilience and multi-tenant safety as volumes expand.`,supplementalActions:[`Introduce workload partitioning or isolation per tenant`]},"error-handling":{message:`Contain blast radius with policy fallbacks and circuit breakers.`,supplementalActions:[`Add circuit breakers to high-risk operations`]}},mature:{performance:{message:`Optimize for margins and predictable SLAs.`,supplementalActions:[`Capture unit-cost impacts alongside latency fixes`]},"error-handling":{message:`Prevent regressions with automated regression specs before deploy.`,supplementalActions:[`Run auto-evolution simulations on renewal scenarios`]}}},c=e=>{let t=new Set,n=[];for(let r of e)t.has(r)||(t.add(r),n.push(r));return n};export{i as SpecAnalyzer};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SpecSuggestion, SpecSuggestionFilters, SpecSuggestionRepository, SpecSuggestionWriter, SuggestionStatus } from "../types.js";
|
|
2
|
+
import { ApprovalWorkflow } from "@lssm/lib.ai-agent/approval";
|
|
3
|
+
import { AgentSessionState } from "@lssm/lib.ai-agent/types";
|
|
4
|
+
|
|
5
|
+
//#region src/approval/integration.d.ts
|
|
6
|
+
interface SpecSuggestionOrchestratorOptions {
|
|
7
|
+
repository: SpecSuggestionRepository;
|
|
8
|
+
approval?: ApprovalWorkflow;
|
|
9
|
+
writer?: SpecSuggestionWriter;
|
|
10
|
+
}
|
|
11
|
+
declare class SpecSuggestionOrchestrator {
|
|
12
|
+
private readonly options;
|
|
13
|
+
constructor(options: SpecSuggestionOrchestratorOptions);
|
|
14
|
+
submit(suggestion: SpecSuggestion, session?: AgentSessionState, approvalReason?: string): Promise<SpecSuggestion>;
|
|
15
|
+
approve(id: string, reviewer: string, notes?: string): Promise<void>;
|
|
16
|
+
reject(id: string, reviewer: string, notes?: string): Promise<void>;
|
|
17
|
+
list(filters?: SpecSuggestionFilters): Promise<SpecSuggestion[]>;
|
|
18
|
+
private ensureSuggestion;
|
|
19
|
+
}
|
|
20
|
+
interface FileSystemSuggestionWriterOptions {
|
|
21
|
+
outputDir?: string;
|
|
22
|
+
filenameTemplate?: (suggestion: SpecSuggestion) => string;
|
|
23
|
+
}
|
|
24
|
+
declare class FileSystemSuggestionWriter implements SpecSuggestionWriter {
|
|
25
|
+
private readonly outputDir;
|
|
26
|
+
private readonly filenameTemplate;
|
|
27
|
+
constructor(options?: FileSystemSuggestionWriterOptions);
|
|
28
|
+
write(suggestion: SpecSuggestion): Promise<string>;
|
|
29
|
+
}
|
|
30
|
+
declare class InMemorySpecSuggestionRepository implements SpecSuggestionRepository {
|
|
31
|
+
private readonly items;
|
|
32
|
+
create(suggestion: SpecSuggestion): Promise<void>;
|
|
33
|
+
getById(id: string): Promise<SpecSuggestion | undefined>;
|
|
34
|
+
updateStatus(id: string, status: SuggestionStatus, metadata?: {
|
|
35
|
+
reviewer?: string;
|
|
36
|
+
notes?: string;
|
|
37
|
+
decidedAt?: Date;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
list(filters?: SpecSuggestionFilters): Promise<SpecSuggestion[]>;
|
|
40
|
+
}
|
|
41
|
+
//#endregion
|
|
42
|
+
export { FileSystemSuggestionWriter, FileSystemSuggestionWriterOptions, InMemorySpecSuggestionRepository, SpecSuggestionOrchestrator, SpecSuggestionOrchestratorOptions };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{mkdir as e,writeFile as t}from"node:fs/promises";import{join as n}from"node:path";import"@lssm/lib.ai-agent/approval";var
|
|
1
|
+
import{mkdir as e,writeFile as t}from"node:fs/promises";import{join as n}from"node:path";import{ApprovalWorkflow as r}from"@lssm/lib.ai-agent/approval";var i=class{constructor(e){this.options=e}async submit(e,t,n){return await this.options.repository.create(e),t&&this.options.approval&&await this.options.approval.requestApproval({sessionId:t.sessionId,agentId:t.agentId,tenantId:t.tenantId,toolName:`evolution.apply_suggestion`,toolCallId:e.id,toolArgs:{suggestionId:e.id},reason:n??e.proposal.summary,payload:{suggestionId:e.id}}),e}async approve(e,t,n){let r=await this.ensureSuggestion(e);await this.options.repository.updateStatus(e,`approved`,{reviewer:t,notes:n,decidedAt:new Date}),this.options.writer&&await this.options.writer.write({...r,status:`approved`,approvals:{reviewer:t,notes:n,decidedAt:new Date,status:`approved`}})}async reject(e,t,n){await this.options.repository.updateStatus(e,`rejected`,{reviewer:t,notes:n,decidedAt:new Date})}list(e){return this.options.repository.list(e)}async ensureSuggestion(e){let t=await this.options.repository.getById(e);if(!t)throw Error(`Spec suggestion ${e} not found`);return t}},a=class{outputDir;filenameTemplate;constructor(e={}){this.outputDir=e.outputDir??n(process.cwd(),`packages/libs/contracts/src/generated`),this.filenameTemplate=e.filenameTemplate??(e=>`${e.target?.name??e.intent.id}.v${e.target?.version??`next`}.suggestion.json`)}async write(r){await e(this.outputDir,{recursive:!0});let i=this.filenameTemplate(r),a=n(this.outputDir,i),o=s(r);return await t(a,JSON.stringify(o,null,2)),a}},o=class{items=new Map;async create(e){this.items.set(e.id,e)}async getById(e){return this.items.get(e)}async updateStatus(e,t,n){let r=await this.getById(e);r&&this.items.set(e,{...r,status:t,approvals:{reviewer:n?.reviewer,notes:n?.notes,decidedAt:n?.decidedAt,status:t}})}async list(e){let t=[...this.items.values()];return e?t.filter(t=>!(e.status&&t.status!==e.status||e.operationName&&t.target?.name!==e.operationName)):t}};function s(e){let{proposal:t,...n}=e,{spec:r,...i}=t;return{...n,proposal:{...i,specMeta:r?.meta},createdAt:e.createdAt.toISOString(),intent:{...e.intent,confidence:{...e.intent.confidence},evidence:e.intent.evidence}}}export{a as FileSystemSuggestionWriter,o as InMemorySpecSuggestionRepository,i as SpecSuggestionOrchestrator};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { EvolutionConfig, IntentPattern, SpecSuggestion } from "../types.js";
|
|
2
|
+
import { LanguageModel } from "ai";
|
|
3
|
+
|
|
4
|
+
//#region src/generator/ai-spec-generator.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Configuration for the AI-powered spec generator.
|
|
8
|
+
*/
|
|
9
|
+
interface AISpecGeneratorConfig {
|
|
10
|
+
/** AI SDK language model */
|
|
11
|
+
model: LanguageModel;
|
|
12
|
+
/** Evolution configuration */
|
|
13
|
+
evolutionConfig?: EvolutionConfig;
|
|
14
|
+
/** Custom system prompt */
|
|
15
|
+
systemPrompt?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* AI-powered spec generator using AI SDK v6.
|
|
19
|
+
*
|
|
20
|
+
* Uses structured output (Output.object) to generate
|
|
21
|
+
* well-formed spec suggestions from intent patterns.
|
|
22
|
+
*/
|
|
23
|
+
declare class AISpecGenerator {
|
|
24
|
+
private readonly model;
|
|
25
|
+
private readonly config;
|
|
26
|
+
private readonly systemPrompt;
|
|
27
|
+
constructor(options: AISpecGeneratorConfig);
|
|
28
|
+
/**
|
|
29
|
+
* Generate a spec suggestion from an intent pattern using AI.
|
|
30
|
+
*/
|
|
31
|
+
generateFromIntent(intent: IntentPattern, options?: {
|
|
32
|
+
additionalContext?: string;
|
|
33
|
+
existingSpec?: Record<string, unknown>;
|
|
34
|
+
}): Promise<SpecSuggestion>;
|
|
35
|
+
/**
|
|
36
|
+
* Generate multiple suggestions for a batch of intents.
|
|
37
|
+
*/
|
|
38
|
+
generateBatch(intents: IntentPattern[], options?: {
|
|
39
|
+
maxConcurrent?: number;
|
|
40
|
+
}): Promise<SpecSuggestion[]>;
|
|
41
|
+
/**
|
|
42
|
+
* Validate and enhance an existing suggestion using AI.
|
|
43
|
+
*/
|
|
44
|
+
enhanceSuggestion(suggestion: SpecSuggestion): Promise<SpecSuggestion>;
|
|
45
|
+
private buildPrompt;
|
|
46
|
+
private buildSuggestion;
|
|
47
|
+
private calculatePriority;
|
|
48
|
+
private determineInitialStatus;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create an AI-powered spec generator.
|
|
52
|
+
*/
|
|
53
|
+
declare function createAISpecGenerator(config: AISpecGeneratorConfig): AISpecGenerator;
|
|
54
|
+
//#endregion
|
|
55
|
+
export { AISpecGenerator, AISpecGeneratorConfig, createAISpecGenerator };
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { EvolutionConfig, IntentPattern, OperationCoordinate, SpecSuggestion, SpecSuggestionProposal, SuggestionStatus } from "../types.js";
|
|
2
|
+
import { Logger } from "@lssm/lib.observability";
|
|
3
|
+
import { ContractSpec, ResourceRefDescriptor } from "@lssm/lib.contracts";
|
|
4
|
+
import { AnySchemaModel } from "@lssm/lib.schema";
|
|
5
|
+
|
|
6
|
+
//#region src/generator/spec-generator.d.ts
|
|
7
|
+
type AnyContract = ContractSpec<AnySchemaModel, AnySchemaModel | ResourceRefDescriptor<boolean>>;
|
|
8
|
+
interface SpecGeneratorOptions {
|
|
9
|
+
config?: EvolutionConfig;
|
|
10
|
+
logger?: Logger;
|
|
11
|
+
clock?: () => Date;
|
|
12
|
+
getSpec?: (name: string, version?: number) => AnyContract | undefined;
|
|
13
|
+
}
|
|
14
|
+
interface GenerateSpecOptions {
|
|
15
|
+
summary?: string;
|
|
16
|
+
rationale?: string;
|
|
17
|
+
changeType?: SpecSuggestionProposal['changeType'];
|
|
18
|
+
kind?: SpecSuggestionProposal['kind'];
|
|
19
|
+
spec?: AnyContract;
|
|
20
|
+
diff?: string;
|
|
21
|
+
metadata?: Record<string, unknown>;
|
|
22
|
+
status?: SuggestionStatus;
|
|
23
|
+
tags?: string[];
|
|
24
|
+
createdBy?: string;
|
|
25
|
+
}
|
|
26
|
+
type SpecPatch = Partial<ContractSpec<AnySchemaModel, AnySchemaModel | ResourceRefDescriptor<boolean>>> & {
|
|
27
|
+
meta?: Partial<AnyContract['meta']>;
|
|
28
|
+
};
|
|
29
|
+
declare class SpecGenerator {
|
|
30
|
+
private readonly config;
|
|
31
|
+
private readonly logger?;
|
|
32
|
+
private readonly clock;
|
|
33
|
+
private readonly getSpec?;
|
|
34
|
+
constructor(options?: SpecGeneratorOptions);
|
|
35
|
+
generateFromIntent(intent: IntentPattern, options?: GenerateSpecOptions): SpecSuggestion;
|
|
36
|
+
generateVariant(operation: OperationCoordinate, patch: SpecPatch, intent: IntentPattern, options?: Omit<GenerateSpecOptions, 'spec'>): SpecSuggestion;
|
|
37
|
+
validateSuggestion(suggestion: SpecSuggestion, config?: EvolutionConfig): {
|
|
38
|
+
ok: boolean;
|
|
39
|
+
reasons: string[];
|
|
40
|
+
};
|
|
41
|
+
private intentToVerb;
|
|
42
|
+
private intentToPriority;
|
|
43
|
+
private inferChangeType;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { GenerateSpecOptions, SpecGenerator, SpecGeneratorOptions, SpecPatch };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import"@lssm/lib.observability";import{randomUUID as
|
|
1
|
+
import{Logger as e}from"@lssm/lib.observability";import{randomUUID as t}from"node:crypto";var n=class{config;logger;clock;getSpec;constructor(e={}){this.config=e.config??{},this.logger=e.logger,this.clock=e.clock??(()=>new Date),this.getSpec=e.getSpec}generateFromIntent(e,n={}){let r=this.clock(),i=n.summary??`${this.intentToVerb(e.type)} ${e.operation?.name??`operation`}`,a=n.rationale??[e.description,e.metadata?.observedValue?`Observed ${e.metadata.observedValue}`:void 0].filter(Boolean).join(` — `);return{id:t(),intent:e,target:e.operation,proposal:{summary:i,rationale:a,changeType:n.changeType??this.inferChangeType(e),kind:n.kind,spec:n.spec,diff:n.diff,metadata:n.metadata},confidence:e.confidence.score,priority:this.intentToPriority(e),createdAt:r,createdBy:n.createdBy??`auto-evolution`,status:n.status??`pending`,evidence:e.evidence,tags:n.tags}}generateVariant(e,t,n,i={}){if(!this.getSpec)throw Error(`SpecGenerator requires getSpec() to generate variants`);let a=this.getSpec(e.name,e.version);if(!a)throw Error(`Cannot generate variant; spec ${e.name}.v${e.version} not found`);let o=r(a,t);return this.generateFromIntent(n,{...i,spec:o})}validateSuggestion(e,t=this.config){let n=[];t.minConfidence!=null&&e.confidence<t.minConfidence&&n.push(`Confidence ${e.confidence.toFixed(2)} below minimum ${t.minConfidence}`),t.requireApproval&&e.status===`approved`&&n.push(`Suggestion cannot be auto-approved when approval is required`),e.proposal.spec&&!e.proposal.spec.meta?.name&&n.push(`Proposal spec must include meta.name`),e.proposal.summary||n.push(`Proposal summary is required`);let r=n.length===0;return r||this.logger?.warn(`SpecGenerator.validateSuggestion.failed`,{suggestionId:e.id,reasons:n}),{ok:r,reasons:n}}intentToVerb(e){switch(e){case`error-spike`:return`Stabilize`;case`latency-regression`:return`Optimize`;case`missing-operation`:return`Introduce`;case`throughput-drop`:return`Rebalance`;default:return`Adjust`}}intentToPriority(e){let t=e.confidence.score;return e.type===`error-spike`||t>=.8?`high`:t>=.5?`medium`:`low`}inferChangeType(e){switch(e.type){case`missing-operation`:return`new-spec`;case`schema-mismatch`:return`schema-update`;case`error-spike`:return`policy-update`;default:return`revision`}}};function r(e,t){return{...e,...t,meta:{...e.meta,...t.meta},io:{...e.io,...t.io},policy:{...e.policy,...t.policy},telemetry:{...e.telemetry,...t.telemetry},sideEffects:{...e.sideEffects,...t.sideEffects}}}export{n as SpecGenerator};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { AnomalySeverity, EvolutionConfig, IntentPattern, OperationCoordinate, OperationMetricSample, OptimizationHint, PatternConfidence, SpecAnomaly, SpecSuggestion, SpecSuggestionFilters, SpecSuggestionProposal, SpecSuggestionRepository, SpecSuggestionWriter, SpecUsageStats, SuggestionEvidence, SuggestionStatus } from "./types.js";
|
|
2
|
+
import { SpecAnalyzer, SpecAnalyzerOptions } from "./analyzer/spec-analyzer.js";
|
|
3
|
+
import { GenerateSpecOptions, SpecGenerator, SpecGeneratorOptions, SpecPatch } from "./generator/spec-generator.js";
|
|
4
|
+
import { AISpecGenerator, AISpecGeneratorConfig, createAISpecGenerator } from "./generator/ai-spec-generator.js";
|
|
5
|
+
import { FileSystemSuggestionWriter, FileSystemSuggestionWriterOptions, InMemorySpecSuggestionRepository, SpecSuggestionOrchestrator, SpecSuggestionOrchestratorOptions } from "./approval/integration.js";
|
|
6
|
+
export { AISpecGenerator, AISpecGeneratorConfig, AnomalySeverity, EvolutionConfig, FileSystemSuggestionWriter, FileSystemSuggestionWriterOptions, GenerateSpecOptions, InMemorySpecSuggestionRepository, IntentPattern, OperationCoordinate, OperationMetricSample, OptimizationHint, PatternConfidence, SpecAnalyzer, SpecAnalyzerOptions, SpecAnomaly, SpecGenerator, SpecGeneratorOptions, SpecPatch, SpecSuggestion, SpecSuggestionFilters, SpecSuggestionOrchestrator, SpecSuggestionOrchestratorOptions, SpecSuggestionProposal, SpecSuggestionRepository, SpecSuggestionWriter, SpecUsageStats, SuggestionEvidence, SuggestionStatus, createAISpecGenerator };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { LifecycleStage } from "@lssm/lib.lifecycle";
|
|
2
|
+
import { ContractSpec, OpKind, ResourceRefDescriptor } from "@lssm/lib.contracts";
|
|
3
|
+
import { AnySchemaModel } from "@lssm/lib.schema";
|
|
4
|
+
|
|
5
|
+
//#region src/types.d.ts
|
|
6
|
+
type AnomalySeverity = 'low' | 'medium' | 'high';
|
|
7
|
+
type SuggestionStatus = 'pending' | 'approved' | 'rejected';
|
|
8
|
+
interface OperationCoordinate {
|
|
9
|
+
name: string;
|
|
10
|
+
version: number;
|
|
11
|
+
tenantId?: string;
|
|
12
|
+
}
|
|
13
|
+
interface OperationMetricSample {
|
|
14
|
+
operation: OperationCoordinate;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
success: boolean;
|
|
17
|
+
timestamp: Date;
|
|
18
|
+
payloadSizeBytes?: number;
|
|
19
|
+
errorCode?: string;
|
|
20
|
+
errorMessage?: string;
|
|
21
|
+
actor?: string;
|
|
22
|
+
channel?: string;
|
|
23
|
+
traceId?: string;
|
|
24
|
+
metadata?: Record<string, unknown>;
|
|
25
|
+
}
|
|
26
|
+
interface SpecUsageStats {
|
|
27
|
+
operation: OperationCoordinate;
|
|
28
|
+
totalCalls: number;
|
|
29
|
+
successRate: number;
|
|
30
|
+
errorRate: number;
|
|
31
|
+
averageLatencyMs: number;
|
|
32
|
+
p95LatencyMs: number;
|
|
33
|
+
p99LatencyMs: number;
|
|
34
|
+
maxLatencyMs: number;
|
|
35
|
+
lastSeenAt: Date;
|
|
36
|
+
windowStart: Date;
|
|
37
|
+
windowEnd: Date;
|
|
38
|
+
topErrors: Record<string, number>;
|
|
39
|
+
}
|
|
40
|
+
interface SuggestionEvidence {
|
|
41
|
+
type: 'telemetry' | 'user-feedback' | 'simulation' | 'test';
|
|
42
|
+
description: string;
|
|
43
|
+
data?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
interface SpecAnomaly {
|
|
46
|
+
operation: OperationCoordinate;
|
|
47
|
+
severity: AnomalySeverity;
|
|
48
|
+
metric: 'latency' | 'error-rate' | 'throughput' | 'policy' | 'schema';
|
|
49
|
+
description: string;
|
|
50
|
+
detectedAt: Date;
|
|
51
|
+
threshold?: number;
|
|
52
|
+
observedValue?: number;
|
|
53
|
+
evidence: SuggestionEvidence[];
|
|
54
|
+
}
|
|
55
|
+
interface PatternConfidence {
|
|
56
|
+
score: number;
|
|
57
|
+
sampleSize: number;
|
|
58
|
+
pValue?: number;
|
|
59
|
+
}
|
|
60
|
+
interface IntentPattern {
|
|
61
|
+
id: string;
|
|
62
|
+
type: 'latency-regression' | 'error-spike' | 'missing-operation' | 'chained-intent' | 'throughput-drop' | 'schema-mismatch';
|
|
63
|
+
description: string;
|
|
64
|
+
operation?: OperationCoordinate;
|
|
65
|
+
confidence: PatternConfidence;
|
|
66
|
+
metadata?: Record<string, unknown>;
|
|
67
|
+
evidence: SuggestionEvidence[];
|
|
68
|
+
}
|
|
69
|
+
interface SpecSuggestionProposal {
|
|
70
|
+
summary: string;
|
|
71
|
+
rationale: string;
|
|
72
|
+
changeType: 'new-spec' | 'revision' | 'policy-update' | 'schema-update';
|
|
73
|
+
kind?: OpKind;
|
|
74
|
+
spec?: ContractSpec<AnySchemaModel, AnySchemaModel | ResourceRefDescriptor<boolean>>;
|
|
75
|
+
diff?: string;
|
|
76
|
+
metadata?: Record<string, unknown>;
|
|
77
|
+
}
|
|
78
|
+
interface SpecSuggestion {
|
|
79
|
+
id: string;
|
|
80
|
+
intent: IntentPattern;
|
|
81
|
+
target?: OperationCoordinate;
|
|
82
|
+
proposal: SpecSuggestionProposal;
|
|
83
|
+
confidence: number;
|
|
84
|
+
createdAt: Date;
|
|
85
|
+
createdBy: string;
|
|
86
|
+
status: SuggestionStatus;
|
|
87
|
+
evidence: SuggestionEvidence[];
|
|
88
|
+
priority: 'low' | 'medium' | 'high';
|
|
89
|
+
tags?: string[];
|
|
90
|
+
approvals?: {
|
|
91
|
+
reviewer?: string;
|
|
92
|
+
notes?: string;
|
|
93
|
+
decidedAt?: Date;
|
|
94
|
+
status?: SuggestionStatus;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
interface EvolutionConfig {
|
|
98
|
+
minConfidence?: number;
|
|
99
|
+
autoApproveThreshold?: number;
|
|
100
|
+
maxSuggestionsPerOperation?: number;
|
|
101
|
+
requireApproval?: boolean;
|
|
102
|
+
maxConcurrentExperiments?: number;
|
|
103
|
+
}
|
|
104
|
+
interface SpecSuggestionFilters {
|
|
105
|
+
status?: SuggestionStatus;
|
|
106
|
+
operationName?: string;
|
|
107
|
+
}
|
|
108
|
+
interface SpecSuggestionRepository {
|
|
109
|
+
create(suggestion: SpecSuggestion): Promise<void>;
|
|
110
|
+
getById(id: string): Promise<SpecSuggestion | undefined>;
|
|
111
|
+
updateStatus(id: string, status: SuggestionStatus, metadata?: {
|
|
112
|
+
reviewer?: string;
|
|
113
|
+
notes?: string;
|
|
114
|
+
decidedAt?: Date;
|
|
115
|
+
}): Promise<void>;
|
|
116
|
+
list(filters?: SpecSuggestionFilters): Promise<SpecSuggestion[]>;
|
|
117
|
+
}
|
|
118
|
+
interface SpecSuggestionWriter {
|
|
119
|
+
write(suggestion: SpecSuggestion): Promise<string>;
|
|
120
|
+
}
|
|
121
|
+
interface OptimizationHint {
|
|
122
|
+
operation: OperationCoordinate;
|
|
123
|
+
category: 'schema' | 'policy' | 'performance' | 'error-handling';
|
|
124
|
+
summary: string;
|
|
125
|
+
justification: string;
|
|
126
|
+
recommendedActions: string[];
|
|
127
|
+
lifecycleStage?: LifecycleStage;
|
|
128
|
+
lifecycleNotes?: string;
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
export { AnomalySeverity, EvolutionConfig, IntentPattern, OperationCoordinate, OperationMetricSample, OptimizationHint, PatternConfidence, SpecAnomaly, SpecSuggestion, SpecSuggestionFilters, SpecSuggestionProposal, SpecSuggestionRepository, SpecSuggestionWriter, SpecUsageStats, SuggestionEvidence, SuggestionStatus };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lssm/lib.evolution",
|
|
3
|
-
"version": "0.0.0-canary-
|
|
3
|
+
"version": "0.0.0-canary-20251217060433",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -25,23 +25,23 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"ai": "beta",
|
|
27
27
|
"zod": "^4.1.13",
|
|
28
|
-
"@lssm/lib.ai-agent": "0.0.0-canary-
|
|
29
|
-
"@lssm/lib.contracts": "0.0.0-canary-
|
|
30
|
-
"@lssm/lib.lifecycle": "0.0.0-canary-
|
|
31
|
-
"@lssm/lib.observability": "0.0.0-canary-
|
|
32
|
-
"@lssm/lib.schema": "0.0.0-canary-
|
|
28
|
+
"@lssm/lib.ai-agent": "0.0.0-canary-20251217060433",
|
|
29
|
+
"@lssm/lib.contracts": "0.0.0-canary-20251217060433",
|
|
30
|
+
"@lssm/lib.lifecycle": "0.0.0-canary-20251217060433",
|
|
31
|
+
"@lssm/lib.observability": "0.0.0-canary-20251217060433",
|
|
32
|
+
"@lssm/lib.schema": "0.0.0-canary-20251217060433"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@prisma/client": "7.1.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@lssm/tool.tsdown": "0.0.0-canary-
|
|
39
|
-
"@lssm/tool.typescript": "0.0.0-canary-
|
|
38
|
+
"@lssm/tool.tsdown": "0.0.0-canary-20251217060433",
|
|
39
|
+
"@lssm/tool.typescript": "0.0.0-canary-20251217060433",
|
|
40
40
|
"tsdown": "^0.17.4",
|
|
41
41
|
"typescript": "^5.9.3"
|
|
42
42
|
},
|
|
43
43
|
"exports": {
|
|
44
|
-
".": "./
|
|
44
|
+
".": "./dist/index.js",
|
|
45
45
|
"./*": "./*"
|
|
46
46
|
},
|
|
47
47
|
"publishConfig": {
|