Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion platform/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export {
export type { ModelCatalogProvider, PipelineModelPreset } from "./llm-model-catalog";
export { parseManifest, generateManifest } from "./manifest";
export { parseSoul, generateSoul } from "./soul";
export { parseMemory, generateMemory } from "./memory";
export { parseMemory, generateMemory, type ParsedMemory } from "./memory";
export {
NETWORK_MODES,
normalizeNetworkMode,
Expand Down
61 changes: 58 additions & 3 deletions platform/core/src/memory.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
export function parseMemory(markdown: string): Record<string, any> {
// TODO: Parse memory markdown into structured data
return { raw: markdown };
export interface ParsedMemory {
/** Content under the "## User Profile" section. */
userProfile: string;
/** Content under the "## Key Facts" section. */
keyFacts: string;
/** Content under the "## Ongoing Context" section. */
ongoingContext: string;
/** Content between MANUAL:START and MANUAL:END markers. */
manualNotes: string;
/** The full raw markdown input, preserved for round-tripping. */
raw: string;
}

/**
* Parse a Signet memory markdown file into structured sections.
*
* Extracts content from well-known `## ` headings and the
* `<!-- MANUAL:START -->` / `<!-- MANUAL:END -->` block. Any content
* outside recognized sections is ignored — the `raw` field always
* contains the original markdown for lossless round-tripping.
*/
export function parseMemory(markdown: string): ParsedMemory {
const sections: Record<string, string> = {};
let currentSection: string | null = null;
const sectionLines: string[] = [];

const lines = markdown.split("\n");
for (const line of lines) {
const headingMatch = line.match(/^##\s+(.+)/);
if (headingMatch) {
// Flush previous section
if (currentSection !== null) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This keeps collecting lines after ## Ongoing Context until another ## heading appears, but generateMemory() puts the <!-- MANUAL:START --> ... <!-- MANUAL:END --> block after Ongoing Context without a new heading. As a result, parseMemory(generateMemory()).ongoingContext includes the manual-marker comments, while manualNotes separately extracts the placeholder comment. That diverges from the PR's claim that the generated template parses into empty fields and gives consumers polluted section content.

sections[currentSection] = sectionLines.join("\n").trim();
}
currentSection = headingMatch[1].trim();
sectionLines.length = 0;
} else if (currentSection !== null) {
sectionLines.push(line);
}
}
// Flush last section
if (currentSection !== null) {
sections[currentSection] = sectionLines.join("\n").trim();
}

// Extract manual notes block
const manualMatch = markdown.match(
/<!--\s*MANUAL:START\s*-->([\s\S]*?)<!--\s*MANUAL:END\s*-->/,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parser returns the generated placeholder text (*No user profile configured yet.*, *No facts stored yet.*, *No ongoing context.*) as real structured data. The PR test plan says parseMemory(generateMemory()) should return empty-string fields when no data is stored yet, so consumers will incorrectly treat the default template as populated memory.

);
const manualNotes = manualMatch ? manualMatch[1].trim() : "";

return {
userProfile: sections["User Profile"] ?? "",
keyFacts: sections["Key Facts"] ?? "",
ongoingContext: sections["Ongoing Context"] ?? "",
manualNotes,
raw: markdown,
};
}

export function generateMemory(): string {
Expand Down