feat: Mode system with inheritance and multilingual support (#412)
* feat: add domain management system with support for multiple domain profiles
- Introduced DomainManager class for loading and managing domain profiles.
- Added support for a default domain ('code') and fallback mechanisms.
- Implemented domain configuration validation and error handling.
- Created types for domain configuration, observation types, and concepts.
- Added new directory for domain profiles and ensured its existence.
- Updated SettingsDefaultsManager to include CLAUDE_MEM_DOMAIN setting.
* Refactor domain management to mode management
- Removed DomainManager class and replaced it with ModeManager for better clarity and functionality.
- Updated types from DomainConfig to ModeConfig and DomainPrompts to ModePrompts.
- Changed references from domains to modes in the settings and paths.
- Ensured backward compatibility by maintaining the fallback mechanism to the 'code' mode.
* feat: add migration 008 to support mode-agnostic observations and refactor service layer references in documentation
* feat: add new modes for code development and email investigation with detailed observation types and concepts
* Refactor observation parsing and prompt generation to incorporate mode-specific configurations
- Updated `parseObservations` function to use 'observation' as a universal fallback type instead of 'change', utilizing active mode's valid observation types.
- Modified `buildInitPrompt` and `buildContinuationPrompt` functions to accept a `ModeConfig` parameter, allowing for dynamic prompt content based on the active mode.
- Enhanced `ModePrompts` interface to include additional guidance for observers, such as recording focus and skip guidance.
- Adjusted the SDKAgent to load the active mode and pass it to prompt generation functions, ensuring prompts are tailored to the current mode's context.
* fix: correct mode prompt injection to preserve exact wording and type list visibility
- Add script to extract prompts from main branch prompts.ts into code.yaml
- Fix prompts.ts to show type list in XML template (e.g., "[ bugfix | feature | ... ]")
- Keep 'change' as fallback type in parser.ts (maintain backwards compatibility)
- Regenerate code.yaml with exact wording from original hardcoded prompts
- Build succeeds with no TypeScript errors
* fix: update ModeManager to load JSON mode files and improve validation
- Changed ModeManager to load mode configurations from JSON files instead of YAML.
- Removed the requirement for an "observation" type and updated validation to require at least one observation type.
- Updated fallback behavior in the parser to use the first type from the active mode's type list.
- Added comprehensive tests for mode loading, prompt injection, and parser integration, ensuring correct behavior across different modes.
- Introduced new mode JSON files for "Code Development" and "Email Investigation" with detailed observation types and prompts.
* Add mode configuration loading and update licensing information for Ragtime
- Implemented loading of mode configuration in WorkerService before database initialization.
- Added PolyForm Noncommercial License 1.0.0 to Ragtime directory.
- Created README.md for Ragtime with licensing details and usage guidelines.
* fix: add datasets directory to .gitignore to prevent accidental commits
* refactor: remove unused plugin package.json file
* chore: add package.json for claude-mem plugin with version 7.4.5
* refactor: remove outdated tests and improve error handling
- Deleted tests for ChromaSync error handling, smart install, strip memory tags, and user prompt tag stripping due to redundancy or outdated logic.
- Removed vitest configuration as it is no longer needed.
- Added a comprehensive implementation plan for fixing the modes system, addressing critical issues and improving functionality.
- Created a detailed test analysis report highlighting the quality and effectiveness of the current test suite, identifying areas for improvement.
- Introduced a new plugin package.json for runtime dependencies related to claude-mem hooks.
* refactor: remove parser regression tests to streamline codebase
* docs: update CLAUDE.md to clarify test management and changelog generation
* refactor: remove migration008 for mode-agnostic observations
* Refactor observation type handling to use ModeManager for icons and emojis
- Removed direct mappings of observation types to icons and work emojis in context-generator, FormattingService, SearchManager, and TimelineService.
- Integrated ModeManager to dynamically retrieve icons and emojis based on the active mode.
- Improved maintainability by centralizing the logic for observation type representation.
* Refactor observation metadata constants and update context generator
- Removed the explicit declaration of OBSERVATION_TYPES and OBSERVATION_CONCEPTS from observation-metadata.ts.
- Introduced fallback default strings for DEFAULT_OBSERVATION_TYPES_STRING and DEFAULT_OBSERVATION_CONCEPTS_STRING.
- Updated context-generator.ts to utilize observation types and concepts from ModeManager instead of constants.
* refactor: remove intermediate error handling from hooks (Phase 1)
Apply "fail fast" error handling strategy - errors propagate and crash loud
instead of being caught, wrapped, and re-thrown at intermediate layers.
Changes:
- Remove try/catch around fetch calls in all hooks - let errors throw
- Add try/catch ONLY around JSON.parse at entry points
- Delete error-handler.ts and hook-error-handler.ts (no longer needed)
- Update worker-utils.ts: functions now throw instead of returning null
- Update transcript-parser.ts: throw on missing path, empty file, malformed JSON
- Remove all handleWorkerError, handleFetchError imports
Philosophy: If something breaks, we KNOW it broke. No silent failures.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: remove intermediate error handling from worker service (Phase 2)
Apply "fail fast" error handling strategy to worker service layer.
Changes:
- worker-service.ts: Remove try/catch from version endpoint, cleanup,
MCP close, process enumeration, force kill, and isAlive check
- SessionRoutes.ts: Remove try/catch from JSON.stringify calls, remove
.catch() from Chroma sync and SDK agent calls
- SettingsRoutes.ts: Remove try/catch from toggleMcp()
- DatabaseManager.ts: Remove .catch() from backfill and close operations
- SDKAgent.ts: Keep outer try/catch (top-level), remove .catch() from
Chroma sync operations
- SSEBroadcaster.ts: Remove try/catch from broadcast and sendToClient
Philosophy: Errors propagate and crash loud. BaseRouteHandler.wrapHandler
provides top-level catching for HTTP routes.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: remove error swallowing from SQLite services (Phase 3)
Apply "fail fast" error handling strategy to database layer.
SessionStore.ts migrations:
- ensureWorkerPortColumn(): Remove outer try/catch, let it throw
- ensurePromptTrackingColumns(): Remove outer try/catch, let it throw
- removeSessionSummariesUniqueConstraint(): Keep inner transaction
rollback, remove outer catch
- addObservationHierarchicalFields(): Remove outer try/catch
- makeObservationsTextNullable(): Keep inner transaction rollback,
remove outer catch
- createUserPromptsTable(): Keep inner transaction rollback, remove
outer catch
- getFilesForSession(): Remove try/catch around JSON.parse
SessionSearch.ts:
- ensureFTSTables(): Remove try/catch, let it throw
Philosophy: Migration errors that are swallowed mean we think the
database is fine when it's not. Keep only inner transaction rollback
try/catch blocks.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* refactor: remove error hiding from utilities (Phase 4)
Apply "fail fast" error handling strategy to utility layer.
logger.ts:
- formatTool(): Remove try/catch, let JSON.parse throw on malformed input
context-generator.ts:
- loadContextConfig(): Remove try/catch, let parseInt throw on invalid settings
- Transcript extraction: Remove try/catch, let file read errors propagate
ChromaSync.ts:
- close(): Remove nested try/catch blocks, let close errors propagate
Philosophy: No silent fallbacks or hidden defaults. If something breaks,
we know it broke immediately.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: serve static UI assets and update package root path
- Added middleware to serve static UI assets (JS, CSS, fonts, etc.) in ViewerRoutes.
- Updated getPackageRoot function to correctly return the package root directory as one level up from the current directory.
* feat: Enhance mode loading with inheritance support
- Introduced parseInheritance method to handle parent--override mode IDs.
- Added deepMerge method for recursively merging mode configurations.
- Updated loadMode method to support inheritance, loading parent modes and applying overrides.
- Improved error handling for missing mode files and logging for better traceability.
* fix(modes): correct inheritance file resolution and path handling
* Refactor code structure for improved readability and maintainability
* feat: Add mode configuration documentation and examples
* fix: Improve concurrency handling in translateReadme function
* Refactor SDK prompts to enhance clarity and structure
- Updated the `buildInitPrompt` and `buildContinuationPrompt` functions in `prompts.ts` to improve the organization of prompt components, including the addition of language instructions and footer messages.
- Removed redundant instructions and emphasized the importance of recording observations.
- Modified the `ModePrompts` interface in `types.ts` to include new properties for system identity, language instructions, and output format header, ensuring better flexibility and clarity in prompt generation.
* Enhance prompts with language instructions and XML formatting
- Updated `buildInitPrompt`, `buildSummaryPrompt`, and `buildContinuationPrompt` functions to include detailed language instructions in XML comments.
- Ensured that language instructions guide users to keep XML tags in English while writing content in the specified language.
- Modified the `buildSummaryPrompt` function to accept `mode` as a parameter for consistency.
- Adjusted the call to `buildSummaryPrompt` in `SDKAgent` to pass the `mode` argument.
* Refactor XML prompt generation in SDK
- Updated the buildInitPrompt, buildSummaryPrompt, and buildContinuationPrompt functions to use new placeholders for XML elements, improving maintainability and readability.
- Removed redundant language instructions in comments for clarity.
- Added new properties to ModePrompts interface for better structure and organization of XML placeholders and section headers.
* feat: Update observation prompts and structure across multiple languages
* chore: Remove planning docs and update Ragtime README
Remove ephemeral development artifacts:
- .claude/plans/modes-system-fixes.md
- .claude/test-analysis-report.md
- PROMPT_INJECTION_ANALYSIS.md
Update ragtime/README.md to explain:
- Feature is not yet implemented
- Dependency on modes system (now complete in PR #412)
- Ready to be scripted out in future release
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* fix: Move summary prompts to mode files for multilingual support
Summary prompts were hardcoded in English in prompts.ts, breaking
multilingual support. Now properly mode-based:
- Added summary_instruction, summary_context_label,
summary_format_instruction, summary_footer to code.json
- Updated buildSummaryPrompt() to use mode fields instead of hardcoded text
- Added summary_footer with language instructions to all 10 language modes
- Language modes keep English prompts + language requirement footer
This fixes the gaslighting where we claimed full multilingual support
but summaries were still generated in English.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* chore: Clean up README by removing local preview instructions and streamlining beta features section
* Add translated README files for Ukrainian, Vietnamese, and Chinese languages
* Add new language modes for code development in multiple languages
- Introduced JSON configurations for Code Development in Greek, Finnish, Hebrew, Hindi, Hungarian, Indonesian, Italian, Dutch, Norwegian, Polish, Brazilian Portuguese, Romanian, Swedish, Turkish, and Ukrainian.
- Each configuration includes prompts for observations, summaries, and instructions tailored to the respective language.
- Ensured that all prompts emphasize the importance of generating observations without referencing the agent's actions.
* Add multilingual support links to README files in various languages
- Updated README.id.md, README.it.md, README.ja.md, README.ko.md, README.nl.md, README.no.md, README.pl.md, README.pt-br.md, README.ro.md, README.ru.md, README.sv.md, README.th.md, README.tr.md, README.uk.md, README.vi.md, and README.zh.md to include links to other language versions.
- Each README now features a centered paragraph with flags and links for easy navigation between different language documents.
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,403 +0,0 @@
|
||||
/**
|
||||
* Parser Regression Tests
|
||||
* Ensures v4.2.5 and v4.2.6 bugfixes remain stable
|
||||
*/
|
||||
|
||||
import { parseObservations, parseSummary } from './parser.js';
|
||||
|
||||
// ANSI color codes for output
|
||||
const GREEN = '\x1b[32m';
|
||||
const RED = '\x1b[31m';
|
||||
const YELLOW = '\x1b[33m';
|
||||
const RESET = '\x1b[0m';
|
||||
|
||||
let testsRun = 0;
|
||||
let testsPassed = 0;
|
||||
let testsFailed = 0;
|
||||
|
||||
function assert(condition: boolean, testName: string, errorMsg?: string): void {
|
||||
testsRun++;
|
||||
if (condition) {
|
||||
testsPassed++;
|
||||
console.log(`${GREEN}✓${RESET} ${testName}`);
|
||||
} else {
|
||||
testsFailed++;
|
||||
console.log(`${RED}✗${RESET} ${testName}`);
|
||||
if (errorMsg) {
|
||||
console.log(` ${RED}${errorMsg}${RESET}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertEqual<T>(actual: T, expected: T, testName: string): void {
|
||||
const isEqual = JSON.stringify(actual) === JSON.stringify(expected);
|
||||
if (!isEqual) {
|
||||
assert(false, testName, `Expected: ${JSON.stringify(expected)}, Got: ${JSON.stringify(actual)}`);
|
||||
} else {
|
||||
assert(true, testName);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('\n' + YELLOW + '='.repeat(60) + RESET);
|
||||
console.log(YELLOW + 'Parser Regression Tests (v4.2.5 & v4.2.6)' + RESET);
|
||||
console.log(YELLOW + '='.repeat(60) + RESET + '\n');
|
||||
|
||||
// ============================================================================
|
||||
// v4.2.6: Observation Parsing - NEVER Skip Observations
|
||||
// ============================================================================
|
||||
|
||||
console.log(YELLOW + '\nv4.2.6: Observation Validation Fixes' + RESET);
|
||||
console.log('─'.repeat(60) + '\n');
|
||||
|
||||
// Test 1: Observation with missing title should be saved
|
||||
const missingTitleXml = `
|
||||
<observation>
|
||||
<type>feature</type>
|
||||
<subtitle>Added new feature</subtitle>
|
||||
<narrative>Implemented the feature successfully</narrative>
|
||||
<facts>
|
||||
<fact>Created new file</fact>
|
||||
</facts>
|
||||
<concepts>
|
||||
<concept>authentication</concept>
|
||||
</concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified>
|
||||
<file>src/app.ts</file>
|
||||
</files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const missingTitleResult = parseObservations(missingTitleXml);
|
||||
assert(missingTitleResult.length === 1, 'Should parse observation with missing title');
|
||||
assert(missingTitleResult[0].title === null, 'Missing title should be null');
|
||||
assertEqual(missingTitleResult[0].type, 'feature', 'Should preserve type when title missing');
|
||||
|
||||
// Test 2: Observation with missing subtitle should be saved
|
||||
const missingSubtitleXml = `
|
||||
<observation>
|
||||
<type>bugfix</type>
|
||||
<title>Fixed critical bug</title>
|
||||
<narrative>Resolved the issue</narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const missingSubtitleResult = parseObservations(missingSubtitleXml);
|
||||
assert(missingSubtitleResult.length === 1, 'Should parse observation with missing subtitle');
|
||||
assert(missingSubtitleResult[0].subtitle === null, 'Missing subtitle should be null');
|
||||
assertEqual(missingSubtitleResult[0].title, 'Fixed critical bug', 'Should preserve title when subtitle missing');
|
||||
|
||||
// Test 3: Observation with missing narrative should be saved
|
||||
const missingNarrativeXml = `
|
||||
<observation>
|
||||
<type>refactor</type>
|
||||
<title>Code cleanup</title>
|
||||
<subtitle>Improved structure</subtitle>
|
||||
<facts>
|
||||
<fact>Removed dead code</fact>
|
||||
</facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const missingNarrativeResult = parseObservations(missingNarrativeXml);
|
||||
assert(missingNarrativeResult.length === 1, 'Should parse observation with missing narrative');
|
||||
assert(missingNarrativeResult[0].narrative === null, 'Missing narrative should be null');
|
||||
assertEqual(missingNarrativeResult[0].facts, ['Removed dead code'], 'Should preserve facts when narrative missing');
|
||||
|
||||
// Test 4: Observation with ALL fields missing (except type) should be saved
|
||||
const minimalObservationXml = `
|
||||
<observation>
|
||||
<type>change</type>
|
||||
<title></title>
|
||||
<subtitle></subtitle>
|
||||
<narrative></narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const minimalResult = parseObservations(minimalObservationXml);
|
||||
assert(minimalResult.length === 1, 'Should parse minimal observation with only type');
|
||||
assertEqual(minimalResult[0].type, 'change', 'Should preserve type for minimal observation');
|
||||
assert(minimalResult[0].title === null, 'Empty title should be null');
|
||||
assert(minimalResult[0].subtitle === null, 'Empty subtitle should be null');
|
||||
assert(minimalResult[0].narrative === null, 'Empty narrative should be null');
|
||||
|
||||
// Test 5: Observation with missing type should use "change" as fallback
|
||||
const missingTypeXml = `
|
||||
<observation>
|
||||
<title>Something happened</title>
|
||||
<subtitle>Details here</subtitle>
|
||||
<narrative>More info</narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const missingTypeResult = parseObservations(missingTypeXml);
|
||||
assert(missingTypeResult.length === 1, 'Should parse observation with missing type');
|
||||
assertEqual(missingTypeResult[0].type, 'change', 'Missing type should default to "change"');
|
||||
|
||||
// Test 6: Observation with invalid type should use "change" as fallback
|
||||
const invalidTypeXml = `
|
||||
<observation>
|
||||
<type>invalid_type_here</type>
|
||||
<title>Something happened</title>
|
||||
<subtitle>Details here</subtitle>
|
||||
<narrative>More info</narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const invalidTypeResult = parseObservations(invalidTypeXml);
|
||||
assert(invalidTypeResult.length === 1, 'Should parse observation with invalid type');
|
||||
assertEqual(invalidTypeResult[0].type, 'change', 'Invalid type should default to "change"');
|
||||
|
||||
// Test 7: Multiple observations with mixed completeness should all be saved
|
||||
const mixedObservationsXml = `
|
||||
<observation>
|
||||
<type>feature</type>
|
||||
<title>Full observation</title>
|
||||
<subtitle>Complete</subtitle>
|
||||
<narrative>All fields present</narrative>
|
||||
<facts><fact>Fact 1</fact></facts>
|
||||
<concepts><concept>concept1</concept></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
<observation>
|
||||
<type>bugfix</type>
|
||||
<subtitle>Only subtitle and type</subtitle>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
<observation>
|
||||
<title>Only title, no type</title>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const mixedResult = parseObservations(mixedObservationsXml);
|
||||
assertEqual(mixedResult.length, 3, 'Should parse all three observations regardless of completeness');
|
||||
assertEqual(mixedResult[0].type, 'feature', 'First observation should have correct type');
|
||||
assertEqual(mixedResult[1].type, 'bugfix', 'Second observation should have correct type');
|
||||
assertEqual(mixedResult[2].type, 'change', 'Third observation should default to "change"');
|
||||
|
||||
// ============================================================================
|
||||
// v4.2.5: Summary Parsing - NEVER Skip Summaries
|
||||
// ============================================================================
|
||||
|
||||
console.log(YELLOW + '\nv4.2.5: Summary Validation Fixes' + RESET);
|
||||
console.log('─'.repeat(60) + '\n');
|
||||
|
||||
// Test 8: Summary with missing request field should be saved
|
||||
const missingRequestXml = `
|
||||
<summary>
|
||||
<investigated>Looked into the codebase</investigated>
|
||||
<learned>Found the issue</learned>
|
||||
<completed>Fixed the bug</completed>
|
||||
<next_steps>Deploy to production</next_steps>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const missingRequestResult = parseSummary(missingRequestXml);
|
||||
assert(missingRequestResult !== null, 'Should parse summary with missing request');
|
||||
assert(missingRequestResult!.request === null, 'Missing request should be null');
|
||||
assertEqual(missingRequestResult!.investigated, 'Looked into the codebase', 'Should preserve other fields');
|
||||
|
||||
// Test 9: Summary with missing investigated field should be saved
|
||||
const missingInvestigatedXml = `
|
||||
<summary>
|
||||
<request>Fix the bug</request>
|
||||
<learned>Root cause identified</learned>
|
||||
<completed>Applied the fix</completed>
|
||||
<next_steps>Monitor production</next_steps>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const missingInvestigatedResult = parseSummary(missingInvestigatedXml);
|
||||
assert(missingInvestigatedResult !== null, 'Should parse summary with missing investigated');
|
||||
assert(missingInvestigatedResult!.investigated === null, 'Missing investigated should be null');
|
||||
|
||||
// Test 10: Summary with missing learned field should be saved
|
||||
const missingLearnedXml = `
|
||||
<summary>
|
||||
<request>Add new feature</request>
|
||||
<investigated>Reviewed the requirements</investigated>
|
||||
<completed>Implemented the feature</completed>
|
||||
<next_steps>Write tests</next_steps>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const missingLearnedResult = parseSummary(missingLearnedXml);
|
||||
assert(missingLearnedResult !== null, 'Should parse summary with missing learned');
|
||||
assert(missingLearnedResult!.learned === null, 'Missing learned should be null');
|
||||
|
||||
// Test 11: Summary with missing completed field should be saved
|
||||
const missingCompletedXml = `
|
||||
<summary>
|
||||
<request>Refactor code</request>
|
||||
<investigated>Analyzed the structure</investigated>
|
||||
<learned>Found improvement opportunities</learned>
|
||||
<next_steps>Continue refactoring</next_steps>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const missingCompletedResult = parseSummary(missingCompletedXml);
|
||||
assert(missingCompletedResult !== null, 'Should parse summary with missing completed');
|
||||
assert(missingCompletedResult!.completed === null, 'Missing completed should be null');
|
||||
|
||||
// Test 12: Summary with missing next_steps field should be saved
|
||||
const missingNextStepsXml = `
|
||||
<summary>
|
||||
<request>Review code</request>
|
||||
<investigated>Examined all files</investigated>
|
||||
<learned>Code quality is good</learned>
|
||||
<completed>Review complete</completed>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const missingNextStepsResult = parseSummary(missingNextStepsXml);
|
||||
assert(missingNextStepsResult !== null, 'Should parse summary with missing next_steps');
|
||||
assert(missingNextStepsResult!.next_steps === null, 'Missing next_steps should be null');
|
||||
|
||||
// Test 13: Summary with only notes field should be saved
|
||||
const onlyNotesXml = `
|
||||
<summary>
|
||||
<notes>Some random notes</notes>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const onlyNotesResult = parseSummary(onlyNotesXml);
|
||||
assert(onlyNotesResult !== null, 'Should parse summary with only notes field');
|
||||
assertEqual(onlyNotesResult!.notes, 'Some random notes', 'Should preserve notes field');
|
||||
|
||||
// Test 14: Completely empty summary should be saved
|
||||
const emptySummaryXml = `
|
||||
<summary>
|
||||
<request></request>
|
||||
<investigated></investigated>
|
||||
<learned></learned>
|
||||
<completed></completed>
|
||||
<next_steps></next_steps>
|
||||
</summary>
|
||||
`;
|
||||
|
||||
const emptySummaryResult = parseSummary(emptySummaryXml);
|
||||
assert(emptySummaryResult !== null, 'Should parse completely empty summary');
|
||||
assert(emptySummaryResult!.request === null, 'Empty request should be null');
|
||||
assert(emptySummaryResult!.investigated === null, 'Empty investigated should be null');
|
||||
|
||||
// Test 15: Summary with skip_summary should return null (valid use case)
|
||||
const skipSummaryXml = `
|
||||
<skip_summary reason="Not enough context yet" />
|
||||
`;
|
||||
|
||||
const skipSummaryResult = parseSummary(skipSummaryXml);
|
||||
assert(skipSummaryResult === null, 'Should return null for skip_summary directive');
|
||||
|
||||
// ============================================================================
|
||||
// Edge Cases & Data Integrity
|
||||
// ============================================================================
|
||||
|
||||
console.log(YELLOW + '\nEdge Cases & Data Integrity' + RESET);
|
||||
console.log('─'.repeat(60) + '\n');
|
||||
|
||||
// Test 16: Observation with whitespace-only fields should be null
|
||||
const whitespaceObservationXml = `
|
||||
<observation>
|
||||
<type>change</type>
|
||||
<title> </title>
|
||||
<subtitle>
|
||||
|
||||
</subtitle>
|
||||
<narrative></narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const whitespaceResult = parseObservations(whitespaceObservationXml);
|
||||
assert(whitespaceResult.length === 1, 'Should parse observation with whitespace fields');
|
||||
assert(whitespaceResult[0].title === null || whitespaceResult[0].title!.trim() === '', 'Whitespace title should be null or empty');
|
||||
|
||||
// Test 17: Observation with concepts including type should filter out type
|
||||
const conceptsWithTypeXml = `
|
||||
<observation>
|
||||
<type>feature</type>
|
||||
<title>New feature</title>
|
||||
<subtitle>Details</subtitle>
|
||||
<narrative>Description</narrative>
|
||||
<facts></facts>
|
||||
<concepts>
|
||||
<concept>feature</concept>
|
||||
<concept>authentication</concept>
|
||||
</concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
|
||||
const conceptsWithTypeResult = parseObservations(conceptsWithTypeXml);
|
||||
assert(conceptsWithTypeResult.length === 1, 'Should parse observation with type in concepts');
|
||||
assertEqual(conceptsWithTypeResult[0].concepts, ['authentication'], 'Should filter out type from concepts');
|
||||
|
||||
// Test 18: Observation with all valid types
|
||||
const validTypes = ['decision', 'bugfix', 'feature', 'refactor', 'discovery', 'change'];
|
||||
validTypes.forEach(type => {
|
||||
const typeXml = `
|
||||
<observation>
|
||||
<type>${type}</type>
|
||||
<title>Test</title>
|
||||
<subtitle>Test</subtitle>
|
||||
<narrative>Test</narrative>
|
||||
<facts></facts>
|
||||
<concepts></concepts>
|
||||
<files_read></files_read>
|
||||
<files_modified></files_modified>
|
||||
</observation>
|
||||
`;
|
||||
const result = parseObservations(typeXml);
|
||||
assertEqual(result[0].type, type, `Should accept valid type: ${type}`);
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Results Summary
|
||||
// ============================================================================
|
||||
|
||||
console.log('\n' + YELLOW + '='.repeat(60) + RESET);
|
||||
console.log(YELLOW + 'Test Results Summary' + RESET);
|
||||
console.log(YELLOW + '='.repeat(60) + RESET + '\n');
|
||||
|
||||
console.log(`Total Tests: ${testsRun}`);
|
||||
console.log(`${GREEN}Passed: ${testsPassed}${RESET}`);
|
||||
console.log(`${RED}Failed: ${testsFailed}${RESET}`);
|
||||
|
||||
if (testsFailed > 0) {
|
||||
console.log(`\n${RED}❌ TESTS FAILED${RESET}\n`);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log(`\n${GREEN}✅ ALL TESTS PASSED${RESET}\n`);
|
||||
process.exit(0);
|
||||
}
|
||||
+9
-6
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { logger } from '../utils/logger.js';
|
||||
import { ModeManager } from '../services/domain/ModeManager.js';
|
||||
|
||||
export interface ParsedObservation {
|
||||
type: string;
|
||||
@@ -51,19 +52,21 @@ export function parseObservations(text: string, correlationId?: string): ParsedO
|
||||
|
||||
// NOTE FROM THEDOTMACK: ALWAYS save observations - never skip. 10/24/2025
|
||||
// All fields except type are nullable in schema
|
||||
// If type is missing or invalid, use "change" as catch-all fallback
|
||||
// If type is missing or invalid, use first type from mode as fallback
|
||||
|
||||
// Determine final type
|
||||
let finalType = 'change'; // Default catch-all
|
||||
// Determine final type using active mode's valid types
|
||||
const mode = ModeManager.getInstance().getActiveMode();
|
||||
const validTypes = mode.observation_types.map(t => t.id);
|
||||
const fallbackType = validTypes[0]; // First type in mode's list is the fallback
|
||||
let finalType = fallbackType;
|
||||
if (type) {
|
||||
const validTypes = ['bugfix', 'feature', 'refactor', 'change', 'discovery', 'decision'];
|
||||
if (validTypes.includes(type.trim())) {
|
||||
finalType = type.trim();
|
||||
} else {
|
||||
logger.warn('PARSER', `Invalid observation type: ${type}, using "change"`, { correlationId });
|
||||
logger.warn('PARSER', `Invalid observation type: ${type}, using "${fallbackType}"`, { correlationId });
|
||||
}
|
||||
} else {
|
||||
logger.warn('PARSER', 'Observation missing type field, using "change"', { correlationId });
|
||||
logger.warn('PARSER', `Observation missing type field, using "${fallbackType}"`, { correlationId });
|
||||
}
|
||||
|
||||
// All other fields are optional - save whatever we have
|
||||
|
||||
+69
-164
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import { logger } from '../utils/logger.js';
|
||||
import type { ModeConfig } from '../services/domain/types.js';
|
||||
|
||||
export interface Observation {
|
||||
id: number;
|
||||
@@ -26,123 +27,63 @@ export interface SDKSession {
|
||||
/**
|
||||
* Build initial prompt to initialize the SDK agent
|
||||
*/
|
||||
export function buildInitPrompt(project: string, sessionId: string, userPrompt: string): string {
|
||||
return `You are a Claude-Mem, a specialized observer tool for creating searchable memory FOR FUTURE SESSIONS.
|
||||
|
||||
CRITICAL: Record what was LEARNED/BUILT/FIXED/DEPLOYED/CONFIGURED, not what you (the observer) are doing.
|
||||
|
||||
You do not have access to tools. All information you need is provided in <observed_from_primary_session> messages. Create observations from what you observe - no investigation needed.
|
||||
export function buildInitPrompt(project: string, sessionId: string, userPrompt: string, mode: ModeConfig): string {
|
||||
return `${mode.prompts.system_identity}
|
||||
|
||||
<observed_from_primary_session>
|
||||
<user_request>${userPrompt}</user_request>
|
||||
<requested_at>${new Date().toISOString().split('T')[0]}</requested_at>
|
||||
</observed_from_primary_session>
|
||||
|
||||
Your job is to monitor a different Claude Code session happening RIGHT NOW, with the goal of creating observations and progress summaries as the work is being done LIVE by the user. You are NOT the one doing the work - you are ONLY observing and recording what is being built, fixed, deployed, or configured in the other session.
|
||||
${mode.prompts.observer_role}
|
||||
|
||||
SPATIAL AWARENESS: Tool executions include the working directory (tool_cwd) to help you understand:
|
||||
- Which repository/project is being worked on
|
||||
- Where files are located relative to the project root
|
||||
- How to match requested paths to actual execution paths
|
||||
${mode.prompts.spatial_awareness}
|
||||
|
||||
WHAT TO RECORD
|
||||
--------------
|
||||
Focus on deliverables and capabilities:
|
||||
- What the system NOW DOES differently (new capabilities)
|
||||
- What shipped to users/production (features, fixes, configs, docs)
|
||||
- Changes in technical domains (auth, data, UI, infra, DevOps, docs)
|
||||
${mode.prompts.recording_focus}
|
||||
|
||||
Use verbs like: implemented, fixed, deployed, configured, migrated, optimized, added, refactored
|
||||
${mode.prompts.skip_guidance}
|
||||
|
||||
✅ GOOD EXAMPLES (describes what was built):
|
||||
- "Authentication now supports OAuth2 with PKCE flow"
|
||||
- "Deployment pipeline runs canary releases with auto-rollback"
|
||||
- "Database indexes optimized for common query patterns"
|
||||
|
||||
❌ BAD EXAMPLES (describes observation process - DO NOT DO THIS):
|
||||
- "Analyzed authentication implementation and stored findings"
|
||||
- "Tracked deployment steps and logged outcomes"
|
||||
- "Monitored database performance and recorded metrics"
|
||||
|
||||
WHEN TO SKIP
|
||||
------------
|
||||
Skip routine operations:
|
||||
- Empty status checks
|
||||
- Package installations with no errors
|
||||
- Simple file listings
|
||||
- Repetitive operations you've already documented
|
||||
- If file related research comes back as empty or not found
|
||||
- **No output necessary if skipping.**
|
||||
|
||||
OUTPUT FORMAT
|
||||
-------------
|
||||
Output observations using this XML structure:
|
||||
${mode.prompts.output_format_header}
|
||||
|
||||
\`\`\`xml
|
||||
<observation>
|
||||
<type>[ bugfix | feature | refactor | change | discovery | decision ]</type>
|
||||
<type>[ ${mode.observation_types.map(t => t.id).join(' | ')} ]</type>
|
||||
<!--
|
||||
**type**: MUST be EXACTLY one of these 6 options (no other values allowed):
|
||||
- bugfix: something was broken, now fixed
|
||||
- feature: new capability or functionality added
|
||||
- refactor: code restructured, behavior unchanged
|
||||
- change: generic modification (docs, config, misc)
|
||||
- discovery: learning about existing system
|
||||
- decision: architectural/design choice with rationale
|
||||
${mode.prompts.type_guidance}
|
||||
-->
|
||||
<title>[**title**: Short title capturing the core action or topic]</title>
|
||||
<subtitle>[**subtitle**: One sentence explanation (max 24 words)]</subtitle>
|
||||
<title>${mode.prompts.xml_title_placeholder}</title>
|
||||
<subtitle>${mode.prompts.xml_subtitle_placeholder}</subtitle>
|
||||
<facts>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
</facts>
|
||||
<!--
|
||||
**facts**: Concise, self-contained statements
|
||||
Each fact is ONE piece of information
|
||||
No pronouns - each fact must stand alone
|
||||
Include specific details: filenames, functions, values
|
||||
${mode.prompts.field_guidance}
|
||||
-->
|
||||
<narrative>[**narrative**: Full context: What was done, how it works, why it matters]</narrative>
|
||||
<narrative>${mode.prompts.xml_narrative_placeholder}</narrative>
|
||||
<concepts>
|
||||
<concept>[knowledge-type-category]</concept>
|
||||
<concept>[knowledge-type-category]</concept>
|
||||
<concept>${mode.prompts.xml_concept_placeholder}</concept>
|
||||
<concept>${mode.prompts.xml_concept_placeholder}</concept>
|
||||
</concepts>
|
||||
<!--
|
||||
**concepts**: 2-5 knowledge-type categories. MUST use ONLY these exact keywords:
|
||||
- how-it-works: understanding mechanisms
|
||||
- why-it-exists: purpose or rationale
|
||||
- what-changed: modifications made
|
||||
- problem-solution: issues and their fixes
|
||||
- gotcha: traps or edge cases
|
||||
- pattern: reusable approach
|
||||
- trade-off: pros/cons of a decision
|
||||
|
||||
IMPORTANT: Do NOT include the observation type (change/discovery/decision) as a concept.
|
||||
Types and concepts are separate dimensions.
|
||||
${mode.prompts.concept_guidance}
|
||||
-->
|
||||
<files_read>
|
||||
<file>[path/to/file]</file>
|
||||
<file>[path/to/file]</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
</files_read>
|
||||
<files_modified>
|
||||
<file>[path/to/file]</file>
|
||||
<file>[path/to/file]</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
</files_modified>
|
||||
<!--
|
||||
**files**: All files touched (full paths from project root)
|
||||
-->
|
||||
</observation>
|
||||
\`\`\`
|
||||
${mode.prompts.format_examples}
|
||||
|
||||
IMPORTANT! DO NOT do any work right now other than generating this OBSERVATIONS from tool use messages - and remember that you are a memory agent designed to summarize a DIFFERENT claude code session, not this one.
|
||||
${mode.prompts.footer}
|
||||
|
||||
Never reference yourself or your own actions. Do not output anything other than the observation content formatted in the XML structure above. All other output is ignored by the system, and the system has been designed to be smart about token usage. Please spend your tokens wisely on useful observations.
|
||||
|
||||
Remember that we record these observations as a way of helping us stay on track with our progress, and to help us keep important decisions and changes at the forefront of our minds! :) Thank you so much for your help!
|
||||
|
||||
MEMORY PROCESSING START
|
||||
=======================`;
|
||||
${mode.prompts.header_memory_start}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +117,7 @@ export function buildObservationPrompt(obs: Observation): string {
|
||||
/**
|
||||
* Build prompt to generate progress summary
|
||||
*/
|
||||
export function buildSummaryPrompt(session: SDKSession): string {
|
||||
export function buildSummaryPrompt(session: SDKSession, mode: ModeConfig): string {
|
||||
const lastAssistantMessage = session.last_assistant_message || logger.happyPathError(
|
||||
'SDK',
|
||||
'Missing last_assistant_message in session for summary prompt',
|
||||
@@ -185,28 +126,23 @@ export function buildSummaryPrompt(session: SDKSession): string {
|
||||
''
|
||||
);
|
||||
|
||||
return `PROGRESS SUMMARY CHECKPOINT
|
||||
===========================
|
||||
Write progress notes of what was done, what was learned, and what's next. This is a checkpoint to capture progress so far. The session is ongoing - you may receive more requests and tool executions after this summary. Write "next_steps" as the current trajectory of work (what's actively being worked on or coming up next), not as post-session future work. Always write at least a minimal summary explaining current progress, even if work is still in early stages, so that users see a summary output tied to each request.
|
||||
return `${mode.prompts.header_summary_checkpoint}
|
||||
${mode.prompts.summary_instruction}
|
||||
|
||||
Claude's Full Response to User:
|
||||
${mode.prompts.summary_context_label}
|
||||
${lastAssistantMessage}
|
||||
|
||||
Respond in this XML format:
|
||||
${mode.prompts.summary_format_instruction}
|
||||
<summary>
|
||||
<request>[Short title capturing the user's request AND the substance of what was discussed/done]</request>
|
||||
<investigated>[What has been explored so far? What was examined?]</investigated>
|
||||
<learned>[What have you learned about how things work?]</learned>
|
||||
<completed>[What work has been completed so far? What has shipped or changed?]</completed>
|
||||
<next_steps>[What are you actively working on or planning to work on next in this session?]</next_steps>
|
||||
<notes>[Additional insights or observations about the current progress]</notes>
|
||||
<request>${mode.prompts.xml_summary_request_placeholder}</request>
|
||||
<investigated>${mode.prompts.xml_summary_investigated_placeholder}</investigated>
|
||||
<learned>${mode.prompts.xml_summary_learned_placeholder}</learned>
|
||||
<completed>${mode.prompts.xml_summary_completed_placeholder}</completed>
|
||||
<next_steps>${mode.prompts.xml_summary_next_steps_placeholder}</next_steps>
|
||||
<notes>${mode.prompts.xml_summary_notes_placeholder}</notes>
|
||||
</summary>
|
||||
|
||||
IMPORTANT! DO NOT do any work right now other than generating this next PROGRESS SUMMARY - and remember that you are a memory agent designed to summarize a DIFFERENT claude code session, not this one.
|
||||
|
||||
Never reference yourself or your own actions. Do not output anything other than the summary content formatted in the XML structure above. All other output is ignored by the system, and the system has been designed to be smart about token usage. Please spend your tokens wisely on useful summary content.
|
||||
|
||||
Thank you, this summary will be very useful for keeping track of our progress!`;
|
||||
${mode.prompts.summary_footer}`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,96 +166,65 @@ Thank you, this summary will be very useful for keeping track of our progress!`;
|
||||
* Called when: promptNumber > 1 (see SDKAgent.ts line 150)
|
||||
* First prompt: Uses buildInitPrompt instead (promptNumber === 1)
|
||||
*/
|
||||
export function buildContinuationPrompt(userPrompt: string, promptNumber: number, claudeSessionId: string): string {
|
||||
return `
|
||||
Hello memory agent, you are continuing to observe the primary Claude session.
|
||||
export function buildContinuationPrompt(userPrompt: string, promptNumber: number, claudeSessionId: string, mode: ModeConfig): string {
|
||||
return `${mode.prompts.continuation_greeting}
|
||||
|
||||
<observed_from_primary_session>
|
||||
<user_request>${userPrompt}</user_request>
|
||||
<requested_at>${new Date().toISOString().split('T')[0]}</requested_at>
|
||||
</observed_from_primary_session>
|
||||
|
||||
You do not have access to tools. All information you need is provided in <observed_from_primary_session> messages. Create observations from what you observe - no investigation needed.
|
||||
${mode.prompts.system_identity}
|
||||
|
||||
CRITICAL: Record what was LEARNED/BUILT/FIXED/DEPLOYED/CONFIGURED, not what you (the observer) are doing. Focus on deliverables and capabilities - what the system NOW DOES differently.
|
||||
${mode.prompts.observer_role}
|
||||
|
||||
WHEN TO SKIP
|
||||
------------
|
||||
Skip routine operations:
|
||||
- Empty status checks
|
||||
- Package installations with no errors
|
||||
- Simple file listings
|
||||
- Repetitive operations you've already documented
|
||||
- If file related research comes back as empty or not found
|
||||
- **No output necessary if skipping.**
|
||||
${mode.prompts.spatial_awareness}
|
||||
|
||||
IMPORTANT: Continue generating observations from tool use messages using the XML structure below.
|
||||
${mode.prompts.recording_focus}
|
||||
|
||||
OUTPUT FORMAT
|
||||
-------------
|
||||
Output observations using this XML structure:
|
||||
${mode.prompts.skip_guidance}
|
||||
|
||||
${mode.prompts.continuation_instruction}
|
||||
|
||||
${mode.prompts.output_format_header}
|
||||
|
||||
\`\`\`xml
|
||||
<observation>
|
||||
<type>[ bugfix | feature | refactor | change | discovery | decision ]</type>
|
||||
<type>[ ${mode.observation_types.map(t => t.id).join(' | ')} ]</type>
|
||||
<!--
|
||||
**type**: MUST be EXACTLY one of these 6 options (no other values allowed):
|
||||
- bugfix: something was broken, now fixed
|
||||
- feature: new capability or functionality added
|
||||
- refactor: code restructured, behavior unchanged
|
||||
- change: generic modification (docs, config, misc)
|
||||
- discovery: learning about existing system
|
||||
- decision: architectural/design choice with rationale
|
||||
${mode.prompts.type_guidance}
|
||||
-->
|
||||
<title>[**title**: Short title capturing the core action or topic]</title>
|
||||
<subtitle>[**subtitle**: One sentence explanation (max 24 words)]</subtitle>
|
||||
<title>${mode.prompts.xml_title_placeholder}</title>
|
||||
<subtitle>${mode.prompts.xml_subtitle_placeholder}</subtitle>
|
||||
<facts>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>[Concise, self-contained statement]</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
<fact>${mode.prompts.xml_fact_placeholder}</fact>
|
||||
</facts>
|
||||
<!--
|
||||
**facts**: Concise, self-contained statements
|
||||
Each fact is ONE piece of information
|
||||
No pronouns - each fact must stand alone
|
||||
Include specific details: filenames, functions, values
|
||||
${mode.prompts.field_guidance}
|
||||
-->
|
||||
<narrative>[**narrative**: Full context: What was done, how it works, why it matters]</narrative>
|
||||
<narrative>${mode.prompts.xml_narrative_placeholder}</narrative>
|
||||
<concepts>
|
||||
<concept>[knowledge-type-category]</concept>
|
||||
<concept>[knowledge-type-category]</concept>
|
||||
<concept>${mode.prompts.xml_concept_placeholder}</concept>
|
||||
<concept>${mode.prompts.xml_concept_placeholder}</concept>
|
||||
</concepts>
|
||||
<!--
|
||||
**concepts**: 2-5 knowledge-type categories. MUST use ONLY these exact keywords:
|
||||
- how-it-works: understanding mechanisms
|
||||
- why-it-exists: purpose or rationale
|
||||
- what-changed: modifications made
|
||||
- problem-solution: issues and their fixes
|
||||
- gotcha: traps or edge cases
|
||||
- pattern: reusable approach
|
||||
- trade-off: pros/cons of a decision
|
||||
|
||||
IMPORTANT: Do NOT include the observation type (change/discovery/decision) as a concept.
|
||||
Types and concepts are separate dimensions.
|
||||
${mode.prompts.concept_guidance}
|
||||
-->
|
||||
<files_read>
|
||||
<file>[path/to/file]</file>
|
||||
<file>[path/to/file]</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
</files_read>
|
||||
<files_modified>
|
||||
<file>[path/to/file]</file>
|
||||
<file>[path/to/file]</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
<file>${mode.prompts.xml_file_placeholder}</file>
|
||||
</files_modified>
|
||||
<!--
|
||||
**files**: All files touched (full paths from project root)
|
||||
-->
|
||||
</observation>
|
||||
\`\`\`
|
||||
${mode.prompts.format_examples}
|
||||
|
||||
Never reference yourself or your own actions. Do not output anything other than the observation content formatted in the XML structure above. All other output is ignored by the system, and the system has been designed to be smart about token usage. Please spend your tokens wisely on useful observations.
|
||||
${mode.prompts.footer}
|
||||
|
||||
Remember that we record these observations as a way of helping us stay on track with our progress, and to help us keep important decisions and changes at the forefront of our minds! :) Thank you so much for your continued help!
|
||||
|
||||
MEMORY PROCESSING CONTINUED
|
||||
===========================`;
|
||||
${mode.prompts.header_memory_continued}`;
|
||||
}
|
||||
Reference in New Issue
Block a user