@yamo/memory-mesh 2.3.2 → 3.0.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.
- package/bin/memory_mesh.js +1 -1
- package/lib/llm/client.d.ts +111 -0
- package/lib/llm/client.js +299 -357
- package/lib/llm/client.ts +413 -0
- package/lib/llm/index.d.ts +17 -0
- package/lib/llm/index.js +15 -8
- package/lib/llm/index.ts +19 -0
- package/lib/memory/adapters/client.d.ts +183 -0
- package/lib/memory/adapters/client.js +518 -0
- package/lib/memory/adapters/client.ts +678 -0
- package/lib/memory/adapters/config.d.ts +137 -0
- package/lib/memory/adapters/config.js +189 -0
- package/lib/memory/adapters/config.ts +259 -0
- package/lib/memory/adapters/errors.d.ts +76 -0
- package/lib/memory/adapters/errors.js +128 -0
- package/lib/memory/adapters/errors.ts +166 -0
- package/lib/memory/context-manager.d.ts +44 -0
- package/lib/memory/context-manager.js +344 -0
- package/lib/memory/context-manager.ts +432 -0
- package/lib/memory/embeddings/factory.d.ts +59 -0
- package/lib/memory/embeddings/factory.js +148 -0
- package/lib/{embeddings/factory.js → memory/embeddings/factory.ts} +69 -28
- package/lib/memory/embeddings/index.d.ts +2 -0
- package/lib/memory/embeddings/index.js +2 -0
- package/lib/memory/embeddings/index.ts +2 -0
- package/lib/memory/embeddings/service.d.ts +164 -0
- package/lib/memory/embeddings/service.js +515 -0
- package/lib/{embeddings/service.js → memory/embeddings/service.ts} +223 -156
- package/lib/memory/index.d.ts +9 -0
- package/lib/memory/index.js +9 -1
- package/lib/memory/index.ts +20 -0
- package/lib/memory/memory-mesh.d.ts +274 -0
- package/lib/memory/memory-mesh.js +1469 -678
- package/lib/memory/memory-mesh.ts +1803 -0
- package/lib/memory/memory-translator.d.ts +19 -0
- package/lib/memory/memory-translator.js +125 -0
- package/lib/memory/memory-translator.ts +158 -0
- package/lib/memory/schema.d.ts +111 -0
- package/lib/memory/schema.js +183 -0
- package/lib/memory/schema.ts +267 -0
- package/lib/memory/scorer.d.ts +26 -0
- package/lib/memory/scorer.js +77 -0
- package/lib/memory/scorer.ts +95 -0
- package/lib/memory/search/index.d.ts +1 -0
- package/lib/memory/search/index.js +1 -0
- package/lib/memory/search/index.ts +1 -0
- package/lib/memory/search/keyword-search.d.ts +62 -0
- package/lib/memory/search/keyword-search.js +135 -0
- package/lib/{search/keyword-search.js → memory/search/keyword-search.ts} +66 -36
- package/lib/scrubber/config/defaults.d.ts +53 -0
- package/lib/scrubber/config/defaults.js +49 -57
- package/lib/scrubber/config/defaults.ts +117 -0
- package/lib/scrubber/index.d.ts +6 -0
- package/lib/scrubber/index.js +3 -23
- package/lib/scrubber/index.ts +7 -0
- package/lib/scrubber/scrubber.d.ts +61 -0
- package/lib/scrubber/scrubber.js +99 -121
- package/lib/scrubber/scrubber.ts +168 -0
- package/lib/scrubber/stages/chunker.d.ts +13 -0
- package/lib/scrubber/stages/metadata-annotator.d.ts +18 -0
- package/lib/scrubber/stages/normalizer.d.ts +13 -0
- package/lib/scrubber/stages/semantic-filter.d.ts +13 -0
- package/lib/scrubber/stages/structural-cleaner.d.ts +13 -0
- package/lib/scrubber/stages/validator.d.ts +18 -0
- package/lib/scrubber/telemetry.d.ts +36 -0
- package/lib/scrubber/telemetry.js +53 -58
- package/lib/scrubber/telemetry.ts +99 -0
- package/lib/utils/logger.d.ts +29 -0
- package/lib/utils/logger.js +64 -0
- package/lib/utils/logger.ts +85 -0
- package/lib/utils/skill-metadata.d.ts +32 -0
- package/lib/utils/skill-metadata.js +132 -0
- package/lib/utils/skill-metadata.ts +147 -0
- package/lib/yamo/emitter.d.ts +73 -0
- package/lib/yamo/emitter.js +78 -143
- package/lib/yamo/emitter.ts +249 -0
- package/lib/yamo/schema.d.ts +58 -0
- package/lib/yamo/schema.js +81 -108
- package/lib/yamo/schema.ts +165 -0
- package/package.json +11 -8
- package/index.d.ts +0 -111
- package/lib/embeddings/index.js +0 -2
- package/lib/index.js +0 -6
- package/lib/lancedb/client.js +0 -633
- package/lib/lancedb/config.js +0 -215
- package/lib/lancedb/errors.js +0 -144
- package/lib/lancedb/index.js +0 -4
- package/lib/lancedb/schema.js +0 -217
- package/lib/scrubber/errors/scrubber-error.js +0 -43
- package/lib/scrubber/stages/chunker.js +0 -103
- package/lib/scrubber/stages/metadata-annotator.js +0 -74
- package/lib/scrubber/stages/normalizer.js +0 -59
- package/lib/scrubber/stages/semantic-filter.js +0 -61
- package/lib/scrubber/stages/structural-cleaner.js +0 -82
- package/lib/scrubber/stages/validator.js +0 -66
- package/lib/scrubber/utils/hash.js +0 -39
- package/lib/scrubber/utils/html-parser.js +0 -45
- package/lib/scrubber/utils/pattern-matcher.js +0 -63
- package/lib/scrubber/utils/token-counter.js +0 -31
- package/lib/search/index.js +0 -1
- package/lib/utils/index.js +0 -1
- package/lib/yamo/index.js +0 -15
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S-MORA Layer 0 Scrubber Telemetry Collection
|
|
3
|
+
* @module smora/scrubber/telemetry
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface StageStats {
|
|
7
|
+
count: number;
|
|
8
|
+
totalTime: number;
|
|
9
|
+
errors: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface StageSummary {
|
|
13
|
+
count: number;
|
|
14
|
+
avgTime: number;
|
|
15
|
+
totalTime: number;
|
|
16
|
+
errors: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TelemetrySummary {
|
|
20
|
+
stages: Record<string, StageStats>;
|
|
21
|
+
performance: {
|
|
22
|
+
structural: number;
|
|
23
|
+
semantic: number;
|
|
24
|
+
normalization: number;
|
|
25
|
+
chunking: number;
|
|
26
|
+
metadata: number;
|
|
27
|
+
validation: number;
|
|
28
|
+
total: number;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ScrubberTelemetry {
|
|
33
|
+
stats: Record<string, StageStats>;
|
|
34
|
+
|
|
35
|
+
constructor() {
|
|
36
|
+
this.stats = {
|
|
37
|
+
structural: { count: 0, totalTime: 0, errors: 0 },
|
|
38
|
+
semantic: { count: 0, totalTime: 0, errors: 0 },
|
|
39
|
+
normalization: { count: 0, totalTime: 0, errors: 0 },
|
|
40
|
+
chunking: { count: 0, totalTime: 0, errors: 0 },
|
|
41
|
+
metadata: { count: 0, totalTime: 0, errors: 0 },
|
|
42
|
+
validation: { count: 0, totalTime: 0, errors: 0 },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
recordStage(stage: string, duration: number, success: boolean = true): void {
|
|
47
|
+
if (!this.stats[stage]) {
|
|
48
|
+
this.stats[stage] = { count: 0, totalTime: 0, errors: 0 };
|
|
49
|
+
}
|
|
50
|
+
this.stats[stage].count++;
|
|
51
|
+
this.stats[stage].totalTime += duration;
|
|
52
|
+
if (!success) {
|
|
53
|
+
this.stats[stage].errors++;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getStageStats(stage: string): StageSummary {
|
|
58
|
+
const stats = this.stats[stage] || { count: 0, totalTime: 0, errors: 0 };
|
|
59
|
+
return {
|
|
60
|
+
count: stats.count,
|
|
61
|
+
avgTime: stats.count > 0 ? stats.totalTime / stats.count : 0,
|
|
62
|
+
totalTime: stats.totalTime,
|
|
63
|
+
errors: stats.errors,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
getSummary(): TelemetrySummary {
|
|
68
|
+
return {
|
|
69
|
+
stages: this.stats,
|
|
70
|
+
performance: {
|
|
71
|
+
structural: this.stats.structural.totalTime,
|
|
72
|
+
semantic: this.stats.semantic.totalTime,
|
|
73
|
+
normalization: this.stats.normalization.totalTime,
|
|
74
|
+
chunking: this.stats.chunking.totalTime,
|
|
75
|
+
metadata: this.stats.metadata.totalTime,
|
|
76
|
+
validation: this.stats.validation.totalTime,
|
|
77
|
+
total: Object.values(this.stats).reduce(
|
|
78
|
+
(sum, s) => sum + s.totalTime,
|
|
79
|
+
0,
|
|
80
|
+
),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
reset(): void {
|
|
86
|
+
Object.keys(this.stats).forEach((key) => {
|
|
87
|
+
this.stats[key] = { count: 0, totalTime: 0, errors: 0 };
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
assertPerformanceBudget(budget: number = 10): void {
|
|
92
|
+
const summary = this.getSummary();
|
|
93
|
+
if (summary.performance.total > budget) {
|
|
94
|
+
throw new Error(
|
|
95
|
+
`Performance budget exceeded: ${summary.performance.total}ms > ${budget}ms`,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger using Pino
|
|
3
|
+
* Provides centralized logging with metadata support, PII redaction, and environment-based formatting
|
|
4
|
+
*/
|
|
5
|
+
import pino from "pino";
|
|
6
|
+
/**
|
|
7
|
+
* Main logger instance with configuration
|
|
8
|
+
*/
|
|
9
|
+
export declare const logger: pino.Logger<never, boolean>;
|
|
10
|
+
/**
|
|
11
|
+
* Create a child logger with module-specific context
|
|
12
|
+
* @param module - Module name for logging context
|
|
13
|
+
* @returns Child logger instance
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* const logger = createLogger('kernel');
|
|
17
|
+
* logger.info({ action: 'boot' }, 'Kernel starting');
|
|
18
|
+
*/
|
|
19
|
+
export declare function createLogger(module: string): pino.Logger;
|
|
20
|
+
/**
|
|
21
|
+
* Log levels and their usage:
|
|
22
|
+
* - fatal: Application crash, immediate attention required
|
|
23
|
+
* - error: Errors that need investigation
|
|
24
|
+
* - warn: Degraded state, potential issues
|
|
25
|
+
* - info: Important operational events (default)
|
|
26
|
+
* - debug: Detailed diagnostic information
|
|
27
|
+
* - trace: Very verbose, performance metrics
|
|
28
|
+
*/
|
|
29
|
+
export type { Logger } from "pino";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger using Pino
|
|
3
|
+
* Provides centralized logging with metadata support, PII redaction, and environment-based formatting
|
|
4
|
+
*/
|
|
5
|
+
import pino from "pino";
|
|
6
|
+
// Determine if running in production
|
|
7
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
8
|
+
const logLevel = (process.env.LOG_LEVEL || "warn");
|
|
9
|
+
/**
|
|
10
|
+
* Main logger instance with configuration
|
|
11
|
+
*/
|
|
12
|
+
export const logger = pino({
|
|
13
|
+
level: logLevel,
|
|
14
|
+
// Pretty printing in development, JSON in production
|
|
15
|
+
transport: !isProduction
|
|
16
|
+
? {
|
|
17
|
+
target: "pino-pretty",
|
|
18
|
+
options: {
|
|
19
|
+
colorize: true,
|
|
20
|
+
translateTime: "HH:MM:ss.l",
|
|
21
|
+
ignore: "pid,hostname,app,version",
|
|
22
|
+
singleLine: false,
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
: undefined,
|
|
26
|
+
// Base fields included in all logs
|
|
27
|
+
base: {
|
|
28
|
+
app: "yamo-os",
|
|
29
|
+
version: process.env.npm_package_version || "1.1.0",
|
|
30
|
+
},
|
|
31
|
+
// Redact sensitive fields from logs
|
|
32
|
+
redact: {
|
|
33
|
+
paths: [
|
|
34
|
+
"apiKey",
|
|
35
|
+
"password",
|
|
36
|
+
"token",
|
|
37
|
+
"secret",
|
|
38
|
+
"key",
|
|
39
|
+
"*.apiKey",
|
|
40
|
+
"*.password",
|
|
41
|
+
"*.token",
|
|
42
|
+
"*.secret",
|
|
43
|
+
"*.key",
|
|
44
|
+
"OPENAI_API_KEY",
|
|
45
|
+
"ANTHROPIC_API_KEY",
|
|
46
|
+
"ZAI_API_KEY",
|
|
47
|
+
],
|
|
48
|
+
censor: "[REDACTED]",
|
|
49
|
+
},
|
|
50
|
+
// Timestamp in ISO format
|
|
51
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* Create a child logger with module-specific context
|
|
55
|
+
* @param module - Module name for logging context
|
|
56
|
+
* @returns Child logger instance
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* const logger = createLogger('kernel');
|
|
60
|
+
* logger.info({ action: 'boot' }, 'Kernel starting');
|
|
61
|
+
*/
|
|
62
|
+
export function createLogger(module) {
|
|
63
|
+
return logger.child({ module });
|
|
64
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Logger using Pino
|
|
3
|
+
* Provides centralized logging with metadata support, PII redaction, and environment-based formatting
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import pino from "pino";
|
|
7
|
+
|
|
8
|
+
// Determine if running in production
|
|
9
|
+
const isProduction = process.env.NODE_ENV === "production";
|
|
10
|
+
const logLevel = (process.env.LOG_LEVEL || "warn") as pino.Level;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Main logger instance with configuration
|
|
14
|
+
*/
|
|
15
|
+
export const logger = pino({
|
|
16
|
+
level: logLevel,
|
|
17
|
+
|
|
18
|
+
// Pretty printing in development, JSON in production
|
|
19
|
+
transport: !isProduction
|
|
20
|
+
? {
|
|
21
|
+
target: "pino-pretty",
|
|
22
|
+
options: {
|
|
23
|
+
colorize: true,
|
|
24
|
+
translateTime: "HH:MM:ss.l",
|
|
25
|
+
ignore: "pid,hostname,app,version",
|
|
26
|
+
singleLine: false,
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
: undefined,
|
|
30
|
+
|
|
31
|
+
// Base fields included in all logs
|
|
32
|
+
base: {
|
|
33
|
+
app: "yamo-os",
|
|
34
|
+
version: process.env.npm_package_version || "1.1.0",
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
// Redact sensitive fields from logs
|
|
38
|
+
redact: {
|
|
39
|
+
paths: [
|
|
40
|
+
"apiKey",
|
|
41
|
+
"password",
|
|
42
|
+
"token",
|
|
43
|
+
"secret",
|
|
44
|
+
"key",
|
|
45
|
+
"*.apiKey",
|
|
46
|
+
"*.password",
|
|
47
|
+
"*.token",
|
|
48
|
+
"*.secret",
|
|
49
|
+
"*.key",
|
|
50
|
+
"OPENAI_API_KEY",
|
|
51
|
+
"ANTHROPIC_API_KEY",
|
|
52
|
+
"ZAI_API_KEY",
|
|
53
|
+
],
|
|
54
|
+
censor: "[REDACTED]",
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// Timestamp in ISO format
|
|
58
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create a child logger with module-specific context
|
|
63
|
+
* @param module - Module name for logging context
|
|
64
|
+
* @returns Child logger instance
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* const logger = createLogger('kernel');
|
|
68
|
+
* logger.info({ action: 'boot' }, 'Kernel starting');
|
|
69
|
+
*/
|
|
70
|
+
export function createLogger(module: string): pino.Logger {
|
|
71
|
+
return logger.child({ module });
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Log levels and their usage:
|
|
76
|
+
* - fatal: Application crash, immediate attention required
|
|
77
|
+
* - error: Errors that need investigation
|
|
78
|
+
* - warn: Degraded state, potential issues
|
|
79
|
+
* - info: Important operational events (default)
|
|
80
|
+
* - debug: Detailed diagnostic information
|
|
81
|
+
* - trace: Very verbose, performance metrics
|
|
82
|
+
*/
|
|
83
|
+
|
|
84
|
+
// Re-export types for convenience
|
|
85
|
+
export type { Logger } from "pino";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured skill-identity extraction.
|
|
3
|
+
*
|
|
4
|
+
* Reads ONLY the YAML frontmatter block (between --- delimiters) or
|
|
5
|
+
* root-level identity declarations in legacy v0.4 compact format.
|
|
6
|
+
* The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
|
|
7
|
+
*/
|
|
8
|
+
export interface SkillIdentity {
|
|
9
|
+
name: string;
|
|
10
|
+
intent: string;
|
|
11
|
+
description: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Extract identity fields (name, intent, description) from .yamo content.
|
|
15
|
+
*
|
|
16
|
+
* Priority:
|
|
17
|
+
* 1. YAML frontmatter (--- … --- block at file start)
|
|
18
|
+
* 2. Legacy v0.4 root-level compact declarations
|
|
19
|
+
* 3. Content-hash fallback — deterministic and idempotent
|
|
20
|
+
*/
|
|
21
|
+
export declare function extractSkillIdentity(content: string): SkillIdentity;
|
|
22
|
+
/**
|
|
23
|
+
* Extract tags from YAML frontmatter.
|
|
24
|
+
* Returns an array of tag strings, or empty array if no tags found.
|
|
25
|
+
*
|
|
26
|
+
* Tags are expected in the format:
|
|
27
|
+
* tags: tag1, tag2, tag3
|
|
28
|
+
*
|
|
29
|
+
* This function ONLY reads the YAML frontmatter block and does NOT parse
|
|
30
|
+
* the skill body, following the same safety constraints as extractSkillIdentity.
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractSkillTags(content: string): string[];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured skill-identity extraction.
|
|
3
|
+
*
|
|
4
|
+
* Reads ONLY the YAML frontmatter block (between --- delimiters) or
|
|
5
|
+
* root-level identity declarations in legacy v0.4 compact format.
|
|
6
|
+
* The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
|
|
7
|
+
*/
|
|
8
|
+
import crypto from "crypto";
|
|
9
|
+
/** Fields safe to extract for indexing and display. */
|
|
10
|
+
const IDENTITY_FIELDS = new Set(["name", "intent", "description"]);
|
|
11
|
+
/** Pre-computed regexes for legacy root-level identity declarations. */
|
|
12
|
+
const LEGACY_REGEXES = {
|
|
13
|
+
name: /^name[;:]\s*([^;\n]+);?/m,
|
|
14
|
+
intent: /^intent[;:]\s*([^;\n]+);?/m,
|
|
15
|
+
description: /^description[;:]\s*([^;\n]+);?/m,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Parse flat key: value or key; value lines from a text block.
|
|
19
|
+
* Only extracts whitelisted identity fields.
|
|
20
|
+
*/
|
|
21
|
+
function parseFlatBlock(block) {
|
|
22
|
+
const result = {};
|
|
23
|
+
for (const line of block.split("\n")) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
const colonIdx = trimmed.indexOf(":");
|
|
29
|
+
const semiIdx = trimmed.indexOf(";");
|
|
30
|
+
let sepIdx;
|
|
31
|
+
if (colonIdx > 0 && semiIdx > 0) {
|
|
32
|
+
sepIdx = Math.min(colonIdx, semiIdx);
|
|
33
|
+
}
|
|
34
|
+
else if (colonIdx > 0) {
|
|
35
|
+
sepIdx = colonIdx;
|
|
36
|
+
}
|
|
37
|
+
else if (semiIdx > 0) {
|
|
38
|
+
sepIdx = semiIdx;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const key = trimmed.substring(0, sepIdx).trim();
|
|
44
|
+
let value = trimmed.substring(sepIdx + 1).trim();
|
|
45
|
+
// Strip trailing semicolon (legacy compact format)
|
|
46
|
+
if (value.endsWith(";")) {
|
|
47
|
+
value = value.slice(0, -1).trim();
|
|
48
|
+
}
|
|
49
|
+
if (IDENTITY_FIELDS.has(key) && value) {
|
|
50
|
+
result[key] = value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Extract identity fields (name, intent, description) from .yamo content.
|
|
57
|
+
*
|
|
58
|
+
* Priority:
|
|
59
|
+
* 1. YAML frontmatter (--- … --- block at file start)
|
|
60
|
+
* 2. Legacy v0.4 root-level compact declarations
|
|
61
|
+
* 3. Content-hash fallback — deterministic and idempotent
|
|
62
|
+
*/
|
|
63
|
+
export function extractSkillIdentity(content) {
|
|
64
|
+
// 1. YAML frontmatter
|
|
65
|
+
if (content.startsWith("---")) {
|
|
66
|
+
const endIdx = content.indexOf("---", 3);
|
|
67
|
+
if (endIdx !== -1) {
|
|
68
|
+
const fields = parseFlatBlock(content.substring(3, endIdx));
|
|
69
|
+
if (fields.name) {
|
|
70
|
+
return {
|
|
71
|
+
name: fields.name,
|
|
72
|
+
intent: fields.intent || "general_procedure",
|
|
73
|
+
description: fields.description || "",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// 2. Legacy v0.4 root-level identity declarations.
|
|
79
|
+
// Safe: name/intent/description do not appear as body section headers.
|
|
80
|
+
const legacyFields = {};
|
|
81
|
+
for (const field of IDENTITY_FIELDS) {
|
|
82
|
+
const match = content.match(LEGACY_REGEXES[field]);
|
|
83
|
+
if (match) {
|
|
84
|
+
legacyFields[field] = match[1].trim();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (legacyFields.name) {
|
|
88
|
+
return {
|
|
89
|
+
name: legacyFields.name,
|
|
90
|
+
intent: legacyFields.intent || "general_procedure",
|
|
91
|
+
description: legacyFields.description || "",
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// 3. Content-hash fallback
|
|
95
|
+
const shortHash = crypto
|
|
96
|
+
.createHash("sha256")
|
|
97
|
+
.update(content)
|
|
98
|
+
.digest("hex")
|
|
99
|
+
.substring(0, 12);
|
|
100
|
+
return {
|
|
101
|
+
name: `Unnamed_${shortHash}`,
|
|
102
|
+
intent: "general_procedure",
|
|
103
|
+
description: "",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Extract tags from YAML frontmatter.
|
|
108
|
+
* Returns an array of tag strings, or empty array if no tags found.
|
|
109
|
+
*
|
|
110
|
+
* Tags are expected in the format:
|
|
111
|
+
* tags: tag1, tag2, tag3
|
|
112
|
+
*
|
|
113
|
+
* This function ONLY reads the YAML frontmatter block and does NOT parse
|
|
114
|
+
* the skill body, following the same safety constraints as extractSkillIdentity.
|
|
115
|
+
*/
|
|
116
|
+
export function extractSkillTags(content) {
|
|
117
|
+
// Only parse YAML frontmatter (between --- delimiters)
|
|
118
|
+
if (content.startsWith("---")) {
|
|
119
|
+
const endIdx = content.indexOf("---", 3);
|
|
120
|
+
if (endIdx !== -1) {
|
|
121
|
+
const frontmatter = content.substring(3, endIdx);
|
|
122
|
+
const tagsMatch = frontmatter.match(/^tags:\s*(.+)$/m);
|
|
123
|
+
if (tagsMatch) {
|
|
124
|
+
return tagsMatch[1]
|
|
125
|
+
.split(",")
|
|
126
|
+
.map((t) => t.trim())
|
|
127
|
+
.filter((t) => t.length > 0);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured skill-identity extraction.
|
|
3
|
+
*
|
|
4
|
+
* Reads ONLY the YAML frontmatter block (between --- delimiters) or
|
|
5
|
+
* root-level identity declarations in legacy v0.4 compact format.
|
|
6
|
+
* The body of .yamo files is LLM-interpreted and MUST NOT be machine-parsed.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import crypto from "crypto";
|
|
10
|
+
|
|
11
|
+
export interface SkillIdentity {
|
|
12
|
+
name: string;
|
|
13
|
+
intent: string;
|
|
14
|
+
description: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Fields safe to extract for indexing and display. */
|
|
18
|
+
const IDENTITY_FIELDS = new Set(["name", "intent", "description"]);
|
|
19
|
+
|
|
20
|
+
/** Pre-computed regexes for legacy root-level identity declarations. */
|
|
21
|
+
const LEGACY_REGEXES: Record<string, RegExp> = {
|
|
22
|
+
name: /^name[;:]\s*([^;\n]+);?/m,
|
|
23
|
+
intent: /^intent[;:]\s*([^;\n]+);?/m,
|
|
24
|
+
description: /^description[;:]\s*([^;\n]+);?/m,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Parse flat key: value or key; value lines from a text block.
|
|
29
|
+
* Only extracts whitelisted identity fields.
|
|
30
|
+
*/
|
|
31
|
+
function parseFlatBlock(block: string): Record<string, string> {
|
|
32
|
+
const result: Record<string, string> = {};
|
|
33
|
+
for (const line of block.split("\n")) {
|
|
34
|
+
const trimmed = line.trim();
|
|
35
|
+
if (!trimmed || trimmed.startsWith("#")) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const colonIdx = trimmed.indexOf(":");
|
|
40
|
+
const semiIdx = trimmed.indexOf(";");
|
|
41
|
+
let sepIdx: number;
|
|
42
|
+
if (colonIdx > 0 && semiIdx > 0) {
|
|
43
|
+
sepIdx = Math.min(colonIdx, semiIdx);
|
|
44
|
+
} else if (colonIdx > 0) {
|
|
45
|
+
sepIdx = colonIdx;
|
|
46
|
+
} else if (semiIdx > 0) {
|
|
47
|
+
sepIdx = semiIdx;
|
|
48
|
+
} else {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const key = trimmed.substring(0, sepIdx).trim();
|
|
53
|
+
let value = trimmed.substring(sepIdx + 1).trim();
|
|
54
|
+
// Strip trailing semicolon (legacy compact format)
|
|
55
|
+
if (value.endsWith(";")) {
|
|
56
|
+
value = value.slice(0, -1).trim();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (IDENTITY_FIELDS.has(key) && value) {
|
|
60
|
+
result[key] = value;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Extract identity fields (name, intent, description) from .yamo content.
|
|
68
|
+
*
|
|
69
|
+
* Priority:
|
|
70
|
+
* 1. YAML frontmatter (--- … --- block at file start)
|
|
71
|
+
* 2. Legacy v0.4 root-level compact declarations
|
|
72
|
+
* 3. Content-hash fallback — deterministic and idempotent
|
|
73
|
+
*/
|
|
74
|
+
export function extractSkillIdentity(content: string): SkillIdentity {
|
|
75
|
+
// 1. YAML frontmatter
|
|
76
|
+
if (content.startsWith("---")) {
|
|
77
|
+
const endIdx = content.indexOf("---", 3);
|
|
78
|
+
if (endIdx !== -1) {
|
|
79
|
+
const fields = parseFlatBlock(content.substring(3, endIdx));
|
|
80
|
+
if (fields.name) {
|
|
81
|
+
return {
|
|
82
|
+
name: fields.name,
|
|
83
|
+
intent: fields.intent || "general_procedure",
|
|
84
|
+
description: fields.description || "",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 2. Legacy v0.4 root-level identity declarations.
|
|
91
|
+
// Safe: name/intent/description do not appear as body section headers.
|
|
92
|
+
const legacyFields: Record<string, string> = {};
|
|
93
|
+
for (const field of IDENTITY_FIELDS) {
|
|
94
|
+
const match = content.match(LEGACY_REGEXES[field]);
|
|
95
|
+
if (match) {
|
|
96
|
+
legacyFields[field] = match[1].trim();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (legacyFields.name) {
|
|
100
|
+
return {
|
|
101
|
+
name: legacyFields.name,
|
|
102
|
+
intent: legacyFields.intent || "general_procedure",
|
|
103
|
+
description: legacyFields.description || "",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 3. Content-hash fallback
|
|
108
|
+
const shortHash = crypto
|
|
109
|
+
.createHash("sha256")
|
|
110
|
+
.update(content)
|
|
111
|
+
.digest("hex")
|
|
112
|
+
.substring(0, 12);
|
|
113
|
+
return {
|
|
114
|
+
name: `Unnamed_${shortHash}`,
|
|
115
|
+
intent: "general_procedure",
|
|
116
|
+
description: "",
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract tags from YAML frontmatter.
|
|
122
|
+
* Returns an array of tag strings, or empty array if no tags found.
|
|
123
|
+
*
|
|
124
|
+
* Tags are expected in the format:
|
|
125
|
+
* tags: tag1, tag2, tag3
|
|
126
|
+
*
|
|
127
|
+
* This function ONLY reads the YAML frontmatter block and does NOT parse
|
|
128
|
+
* the skill body, following the same safety constraints as extractSkillIdentity.
|
|
129
|
+
*/
|
|
130
|
+
export function extractSkillTags(content: string): string[] {
|
|
131
|
+
// Only parse YAML frontmatter (between --- delimiters)
|
|
132
|
+
if (content.startsWith("---")) {
|
|
133
|
+
const endIdx = content.indexOf("---", 3);
|
|
134
|
+
if (endIdx !== -1) {
|
|
135
|
+
const frontmatter = content.substring(3, endIdx);
|
|
136
|
+
const tagsMatch = frontmatter.match(/^tags:\s*(.+)$/m);
|
|
137
|
+
if (tagsMatch) {
|
|
138
|
+
return tagsMatch[1]
|
|
139
|
+
.split(",")
|
|
140
|
+
.map((t) => t.trim())
|
|
141
|
+
.filter((t) => t.length > 0);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* YAMO Emitter - Constructs structured YAMO blocks for auditability
|
|
3
|
+
*
|
|
4
|
+
* Based on YAMO Protocol specification:
|
|
5
|
+
* - Semicolon-terminated key-value pairs
|
|
6
|
+
* - Agent/Intent/Context/Constraints/Meta/Output structure
|
|
7
|
+
* - Supports reflect, retain, recall operations
|
|
8
|
+
*
|
|
9
|
+
* Reference: Hindsight project's yamo_integration.py
|
|
10
|
+
*/
|
|
11
|
+
export interface ReflectBlockParams {
|
|
12
|
+
topic?: string;
|
|
13
|
+
memoryCount: number;
|
|
14
|
+
agentId?: string;
|
|
15
|
+
reflection: string;
|
|
16
|
+
confidence?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface RetainBlockParams {
|
|
19
|
+
content: string;
|
|
20
|
+
metadata?: any;
|
|
21
|
+
id: string;
|
|
22
|
+
agentId?: string;
|
|
23
|
+
memoryType?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface RecallBlockParams {
|
|
26
|
+
query: string;
|
|
27
|
+
resultCount: number;
|
|
28
|
+
limit?: number;
|
|
29
|
+
agentId?: string;
|
|
30
|
+
searchType?: string;
|
|
31
|
+
}
|
|
32
|
+
export interface DeleteBlockParams {
|
|
33
|
+
id: string;
|
|
34
|
+
agentId?: string;
|
|
35
|
+
reason?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface ValidationResult {
|
|
38
|
+
valid: boolean;
|
|
39
|
+
errors: string[];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* YamoEmitter class for building YAMO protocol blocks
|
|
43
|
+
* YAMO (Yet Another Multi-agent Orchestration) blocks provide
|
|
44
|
+
* structured reasoning traces for AI agent operations.
|
|
45
|
+
*/
|
|
46
|
+
export declare class YamoEmitter {
|
|
47
|
+
/**
|
|
48
|
+
* Build a YAMO block for reflect operation
|
|
49
|
+
* Reflect operations synthesize insights from existing memories
|
|
50
|
+
*/
|
|
51
|
+
static buildReflectBlock(params: ReflectBlockParams): string;
|
|
52
|
+
/**
|
|
53
|
+
* Build a YAMO block for retain (add) operation
|
|
54
|
+
* Retain operations store new memories into the system
|
|
55
|
+
*/
|
|
56
|
+
static buildRetainBlock(params: RetainBlockParams): string;
|
|
57
|
+
/**
|
|
58
|
+
* Build a YAMO block for recall (search) operation
|
|
59
|
+
* Recall operations retrieve memories based on semantic similarity
|
|
60
|
+
*/
|
|
61
|
+
static buildRecallBlock(params: RecallBlockParams): string;
|
|
62
|
+
/**
|
|
63
|
+
* Build a YAMO block for delete operation (optional)
|
|
64
|
+
* Delete operations remove memories from the system
|
|
65
|
+
*/
|
|
66
|
+
static buildDeleteBlock(params: DeleteBlockParams): string;
|
|
67
|
+
/**
|
|
68
|
+
* Validate a YAMO block structure
|
|
69
|
+
* Checks for required sections and proper formatting
|
|
70
|
+
*/
|
|
71
|
+
static validateBlock(yamoBlock: string): ValidationResult;
|
|
72
|
+
}
|
|
73
|
+
export default YamoEmitter;
|