clementine-agent 1.18.8 → 1.18.9
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/agent/assistant.d.ts +4 -2
- package/dist/agent/assistant.js +59 -20
- package/dist/agent/self-improve.d.ts +34 -0
- package/dist/agent/self-improve.js +282 -42
- package/dist/gateway/router.js +1 -0
- package/dist/memory/store.d.ts +12 -0
- package/dist/memory/store.js +51 -0
- package/dist/tools/shared.d.ts +12 -0
- package/dist/types.d.ts +3 -1
- package/package.json +1 -1
- package/dist/agent/advisor-rules/context.d.ts.map +0 -1
- package/dist/agent/advisor-rules/context.js.map +0 -1
- package/dist/agent/advisor-rules/engine.d.ts.map +0 -1
- package/dist/agent/advisor-rules/engine.js.map +0 -1
- package/dist/agent/advisor-rules/loader.d.ts.map +0 -1
- package/dist/agent/advisor-rules/loader.js.map +0 -1
- package/dist/agent/advisor-rules/types.d.ts.map +0 -1
- package/dist/agent/advisor-rules/types.js.map +0 -1
- package/dist/agent/agent-manager.d.ts.map +0 -1
- package/dist/agent/agent-manager.js.map +0 -1
- package/dist/agent/assistant.d.ts.map +0 -1
- package/dist/agent/assistant.js.map +0 -1
- package/dist/agent/auto-skills.d.ts.map +0 -1
- package/dist/agent/auto-skills.js.map +0 -1
- package/dist/agent/auto-update.d.ts.map +0 -1
- package/dist/agent/auto-update.js.map +0 -1
- package/dist/agent/background-tasks.d.ts.map +0 -1
- package/dist/agent/background-tasks.js.map +0 -1
- package/dist/agent/brain-digest.d.ts.map +0 -1
- package/dist/agent/brain-digest.js.map +0 -1
- package/dist/agent/budget-enforcement.d.ts.map +0 -1
- package/dist/agent/budget-enforcement.js.map +0 -1
- package/dist/agent/complexity-classifier.d.ts.map +0 -1
- package/dist/agent/complexity-classifier.js.map +0 -1
- package/dist/agent/contradiction-validator.d.ts.map +0 -1
- package/dist/agent/contradiction-validator.js.map +0 -1
- package/dist/agent/crash-forensics.d.ts.map +0 -1
- package/dist/agent/crash-forensics.js.map +0 -1
- package/dist/agent/daily-planner.d.ts.map +0 -1
- package/dist/agent/daily-planner.js.map +0 -1
- package/dist/agent/decision-reflection.d.ts.map +0 -1
- package/dist/agent/decision-reflection.js.map +0 -1
- package/dist/agent/execution-advisor.d.ts.map +0 -1
- package/dist/agent/execution-advisor.js.map +0 -1
- package/dist/agent/hooks.d.ts.map +0 -1
- package/dist/agent/hooks.js.map +0 -1
- package/dist/agent/insight-engine.d.ts.map +0 -1
- package/dist/agent/insight-engine.js.map +0 -1
- package/dist/agent/intent-classifier.d.ts.map +0 -1
- package/dist/agent/intent-classifier.js.map +0 -1
- package/dist/agent/link-extractor.d.ts.map +0 -1
- package/dist/agent/link-extractor.js.map +0 -1
- package/dist/agent/mcp-bridge.d.ts.map +0 -1
- package/dist/agent/mcp-bridge.js.map +0 -1
- package/dist/agent/mcp-circuit-breaker.d.ts.map +0 -1
- package/dist/agent/mcp-circuit-breaker.js.map +0 -1
- package/dist/agent/mcp-schemas.d.ts.map +0 -1
- package/dist/agent/mcp-schemas.js.map +0 -1
- package/dist/agent/metacognition.d.ts.map +0 -1
- package/dist/agent/metacognition.js.map +0 -1
- package/dist/agent/orchestrator.d.ts.map +0 -1
- package/dist/agent/orchestrator.js.map +0 -1
- package/dist/agent/proactive-engine.d.ts.map +0 -1
- package/dist/agent/proactive-engine.js.map +0 -1
- package/dist/agent/proactive-ledger.d.ts.map +0 -1
- package/dist/agent/proactive-ledger.js.map +0 -1
- package/dist/agent/prompt-cache.d.ts.map +0 -1
- package/dist/agent/prompt-cache.js.map +0 -1
- package/dist/agent/prompt-evolver.d.ts.map +0 -1
- package/dist/agent/prompt-evolver.js.map +0 -1
- package/dist/agent/prompt-overrides/loader.d.ts.map +0 -1
- package/dist/agent/prompt-overrides/loader.js.map +0 -1
- package/dist/agent/prompt-overrides/types.d.ts.map +0 -1
- package/dist/agent/prompt-overrides/types.js.map +0 -1
- package/dist/agent/role-scaffolds.d.ts.map +0 -1
- package/dist/agent/role-scaffolds.js.map +0 -1
- package/dist/agent/route-classifier.d.ts.map +0 -1
- package/dist/agent/route-classifier.js.map +0 -1
- package/dist/agent/safe-restart.d.ts.map +0 -1
- package/dist/agent/safe-restart.js.map +0 -1
- package/dist/agent/self-improve-loop.d.ts.map +0 -1
- package/dist/agent/self-improve-loop.js.map +0 -1
- package/dist/agent/self-improve.d.ts.map +0 -1
- package/dist/agent/self-improve.js.map +0 -1
- package/dist/agent/session-event-log.d.ts.map +0 -1
- package/dist/agent/session-event-log.js.map +0 -1
- package/dist/agent/session-store-adapter.d.ts.map +0 -1
- package/dist/agent/session-store-adapter.js.map +0 -1
- package/dist/agent/skill-extractor.d.ts.map +0 -1
- package/dist/agent/skill-extractor.js.map +0 -1
- package/dist/agent/source-mods.d.ts.map +0 -1
- package/dist/agent/source-mods.js.map +0 -1
- package/dist/agent/source-preflight.d.ts.map +0 -1
- package/dist/agent/source-preflight.js.map +0 -1
- package/dist/agent/stall-guard.d.ts.map +0 -1
- package/dist/agent/stall-guard.js.map +0 -1
- package/dist/agent/strategic-planner.d.ts.map +0 -1
- package/dist/agent/strategic-planner.js.map +0 -1
- package/dist/agent/team-bus.d.ts.map +0 -1
- package/dist/agent/team-bus.js.map +0 -1
- package/dist/agent/team-router.d.ts.map +0 -1
- package/dist/agent/team-router.js.map +0 -1
- package/dist/agent/tool-loop-detector.d.ts.map +0 -1
- package/dist/agent/tool-loop-detector.js.map +0 -1
- package/dist/agent/tool-router.d.ts.map +0 -1
- package/dist/agent/tool-router.js.map +0 -1
- package/dist/agent/turn-policy.d.ts.map +0 -1
- package/dist/agent/turn-policy.js.map +0 -1
- package/dist/agent/webhook-actions.d.ts.map +0 -1
- package/dist/agent/webhook-actions.js.map +0 -1
- package/dist/agent/workflow-runner.d.ts.map +0 -1
- package/dist/agent/workflow-runner.js.map +0 -1
- package/dist/agent/workflow-variables.d.ts.map +0 -1
- package/dist/agent/workflow-variables.js.map +0 -1
- package/dist/analytics/tool-usage.d.ts.map +0 -1
- package/dist/analytics/tool-usage.js.map +0 -1
- package/dist/brain/adapters/common.d.ts.map +0 -1
- package/dist/brain/adapters/common.js.map +0 -1
- package/dist/brain/adapters/csv.d.ts.map +0 -1
- package/dist/brain/adapters/csv.js.map +0 -1
- package/dist/brain/adapters/docx.d.ts.map +0 -1
- package/dist/brain/adapters/docx.js.map +0 -1
- package/dist/brain/adapters/email.d.ts.map +0 -1
- package/dist/brain/adapters/email.js.map +0 -1
- package/dist/brain/adapters/index.d.ts.map +0 -1
- package/dist/brain/adapters/index.js.map +0 -1
- package/dist/brain/adapters/json.d.ts.map +0 -1
- package/dist/brain/adapters/json.js.map +0 -1
- package/dist/brain/adapters/markdown.d.ts.map +0 -1
- package/dist/brain/adapters/markdown.js.map +0 -1
- package/dist/brain/adapters/pdf.d.ts.map +0 -1
- package/dist/brain/adapters/pdf.js.map +0 -1
- package/dist/brain/adapters/rest.d.ts.map +0 -1
- package/dist/brain/adapters/rest.js.map +0 -1
- package/dist/brain/batch-summary.d.ts.map +0 -1
- package/dist/brain/batch-summary.js.map +0 -1
- package/dist/brain/connector-recipes.d.ts.map +0 -1
- package/dist/brain/connector-recipes.js.map +0 -1
- package/dist/brain/format-detector.d.ts.map +0 -1
- package/dist/brain/format-detector.js.map +0 -1
- package/dist/brain/graph-extractor.d.ts.map +0 -1
- package/dist/brain/graph-extractor.js.map +0 -1
- package/dist/brain/ingest-scheduler.d.ts.map +0 -1
- package/dist/brain/ingest-scheduler.js.map +0 -1
- package/dist/brain/ingestion-pipeline.d.ts.map +0 -1
- package/dist/brain/ingestion-pipeline.js.map +0 -1
- package/dist/brain/intelligence.d.ts.map +0 -1
- package/dist/brain/intelligence.js.map +0 -1
- package/dist/brain/llm-client.d.ts.map +0 -1
- package/dist/brain/llm-client.js.map +0 -1
- package/dist/brain/source-registry.d.ts.map +0 -1
- package/dist/brain/source-registry.js.map +0 -1
- package/dist/channels/discord-agent-bot.d.ts.map +0 -1
- package/dist/channels/discord-agent-bot.js.map +0 -1
- package/dist/channels/discord-bot-manager.d.ts.map +0 -1
- package/dist/channels/discord-bot-manager.js.map +0 -1
- package/dist/channels/discord-utils.d.ts.map +0 -1
- package/dist/channels/discord-utils.js.map +0 -1
- package/dist/channels/discord.d.ts.map +0 -1
- package/dist/channels/discord.js.map +0 -1
- package/dist/channels/slack-agent-bot.d.ts.map +0 -1
- package/dist/channels/slack-agent-bot.js.map +0 -1
- package/dist/channels/slack-bot-manager.d.ts.map +0 -1
- package/dist/channels/slack-bot-manager.js.map +0 -1
- package/dist/channels/slack-utils.d.ts.map +0 -1
- package/dist/channels/slack-utils.js.map +0 -1
- package/dist/channels/slack.d.ts.map +0 -1
- package/dist/channels/slack.js.map +0 -1
- package/dist/channels/telegram.d.ts.map +0 -1
- package/dist/channels/telegram.js.map +0 -1
- package/dist/channels/webhook.d.ts.map +0 -1
- package/dist/channels/webhook.js.map +0 -1
- package/dist/channels/whatsapp.d.ts.map +0 -1
- package/dist/channels/whatsapp.js.map +0 -1
- package/dist/cli/browser.d.ts.map +0 -1
- package/dist/cli/browser.js.map +0 -1
- package/dist/cli/chat.d.ts.map +0 -1
- package/dist/cli/chat.js.map +0 -1
- package/dist/cli/cron.d.ts.map +0 -1
- package/dist/cli/cron.js.map +0 -1
- package/dist/cli/dashboard.d.ts.map +0 -1
- package/dist/cli/dashboard.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/ingest.d.ts.map +0 -1
- package/dist/cli/ingest.js.map +0 -1
- package/dist/cli/routes/delegations.d.ts.map +0 -1
- package/dist/cli/routes/delegations.js.map +0 -1
- package/dist/cli/routes/digest.d.ts.map +0 -1
- package/dist/cli/routes/digest.js.map +0 -1
- package/dist/cli/routes/goals.d.ts.map +0 -1
- package/dist/cli/routes/goals.js.map +0 -1
- package/dist/cli/routes/workflows.d.ts.map +0 -1
- package/dist/cli/routes/workflows.js.map +0 -1
- package/dist/cli/setup.d.ts.map +0 -1
- package/dist/cli/setup.js.map +0 -1
- package/dist/cli/tunnel.d.ts.map +0 -1
- package/dist/cli/tunnel.js.map +0 -1
- package/dist/cli/version-check.d.ts.map +0 -1
- package/dist/cli/version-check.js.map +0 -1
- package/dist/config/clementine-json.d.ts.map +0 -1
- package/dist/config/clementine-json.js.map +0 -1
- package/dist/config/config-doctor.d.ts.map +0 -1
- package/dist/config/config-doctor.js.map +0 -1
- package/dist/config/effective-config.d.ts.map +0 -1
- package/dist/config/effective-config.js.map +0 -1
- package/dist/config/env-parser.d.ts.map +0 -1
- package/dist/config/env-parser.js.map +0 -1
- package/dist/config/harden-permissions.d.ts.map +0 -1
- package/dist/config/harden-permissions.js.map +0 -1
- package/dist/config/integrations-registry.d.ts.map +0 -1
- package/dist/config/integrations-registry.js.map +0 -1
- package/dist/config/keychain-first-run-wizard.d.ts.map +0 -1
- package/dist/config/keychain-first-run-wizard.js.map +0 -1
- package/dist/config/keychain-fix-acl.d.ts.map +0 -1
- package/dist/config/keychain-fix-acl.js.map +0 -1
- package/dist/config/migrate-from-keychain.d.ts.map +0 -1
- package/dist/config/migrate-from-keychain.js.map +0 -1
- package/dist/config/migrate-keychain.d.ts.map +0 -1
- package/dist/config/migrate-keychain.js.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/dashboard/builder/dry-run.d.ts.map +0 -1
- package/dist/dashboard/builder/dry-run.js.map +0 -1
- package/dist/dashboard/builder/events.d.ts.map +0 -1
- package/dist/dashboard/builder/events.js.map +0 -1
- package/dist/dashboard/builder/mcp-invoke.d.ts.map +0 -1
- package/dist/dashboard/builder/mcp-invoke.js.map +0 -1
- package/dist/dashboard/builder/runner.d.ts.map +0 -1
- package/dist/dashboard/builder/runner.js.map +0 -1
- package/dist/dashboard/builder/serializer.d.ts.map +0 -1
- package/dist/dashboard/builder/serializer.js.map +0 -1
- package/dist/dashboard/builder/snapshots.d.ts.map +0 -1
- package/dist/dashboard/builder/snapshots.js.map +0 -1
- package/dist/dashboard/builder/validation.d.ts.map +0 -1
- package/dist/dashboard/builder/validation.js.map +0 -1
- package/dist/events/bus.d.ts.map +0 -1
- package/dist/events/bus.js.map +0 -1
- package/dist/gateway/agent-heartbeat-manager.d.ts.map +0 -1
- package/dist/gateway/agent-heartbeat-manager.js.map +0 -1
- package/dist/gateway/agent-heartbeat-scheduler.d.ts.map +0 -1
- package/dist/gateway/agent-heartbeat-scheduler.js.map +0 -1
- package/dist/gateway/claim-tracker.d.ts.map +0 -1
- package/dist/gateway/claim-tracker.js.map +0 -1
- package/dist/gateway/cron-scheduler.d.ts.map +0 -1
- package/dist/gateway/cron-scheduler.js.map +0 -1
- package/dist/gateway/delivery-queue.d.ts.map +0 -1
- package/dist/gateway/delivery-queue.js.map +0 -1
- package/dist/gateway/failure-diagnostics.d.ts.map +0 -1
- package/dist/gateway/failure-diagnostics.js.map +0 -1
- package/dist/gateway/failure-monitor.d.ts.map +0 -1
- package/dist/gateway/failure-monitor.js.map +0 -1
- package/dist/gateway/fix-applier.d.ts.map +0 -1
- package/dist/gateway/fix-applier.js.map +0 -1
- package/dist/gateway/fix-verification.d.ts.map +0 -1
- package/dist/gateway/fix-verification.js.map +0 -1
- package/dist/gateway/heartbeat-scheduler.d.ts.map +0 -1
- package/dist/gateway/heartbeat-scheduler.js.map +0 -1
- package/dist/gateway/heartbeat.d.ts.map +0 -1
- package/dist/gateway/heartbeat.js.map +0 -1
- package/dist/gateway/lanes.d.ts.map +0 -1
- package/dist/gateway/lanes.js.map +0 -1
- package/dist/gateway/notifications.d.ts.map +0 -1
- package/dist/gateway/notifications.js.map +0 -1
- package/dist/gateway/outcome-grader.d.ts.map +0 -1
- package/dist/gateway/outcome-grader.js.map +0 -1
- package/dist/gateway/router.d.ts.map +0 -1
- package/dist/gateway/router.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/integrations/composio/client.d.ts.map +0 -1
- package/dist/integrations/composio/client.js.map +0 -1
- package/dist/integrations/composio/mcp-bridge.d.ts.map +0 -1
- package/dist/integrations/composio/mcp-bridge.js.map +0 -1
- package/dist/integrations/tool-preferences.d.ts.map +0 -1
- package/dist/integrations/tool-preferences.js.map +0 -1
- package/dist/memory/chunker.d.ts.map +0 -1
- package/dist/memory/chunker.js.map +0 -1
- package/dist/memory/consolidation.d.ts.map +0 -1
- package/dist/memory/consolidation.js.map +0 -1
- package/dist/memory/context-assembler.d.ts.map +0 -1
- package/dist/memory/context-assembler.js.map +0 -1
- package/dist/memory/embeddings.d.ts.map +0 -1
- package/dist/memory/embeddings.js.map +0 -1
- package/dist/memory/graph-store.d.ts.map +0 -1
- package/dist/memory/graph-store.js.map +0 -1
- package/dist/memory/hot-cache.d.ts.map +0 -1
- package/dist/memory/hot-cache.js.map +0 -1
- package/dist/memory/integrity.d.ts.map +0 -1
- package/dist/memory/integrity.js.map +0 -1
- package/dist/memory/maintenance.d.ts.map +0 -1
- package/dist/memory/maintenance.js.map +0 -1
- package/dist/memory/mmr.d.ts.map +0 -1
- package/dist/memory/mmr.js.map +0 -1
- package/dist/memory/search.d.ts.map +0 -1
- package/dist/memory/search.js.map +0 -1
- package/dist/memory/seed-user-model.d.ts.map +0 -1
- package/dist/memory/seed-user-model.js.map +0 -1
- package/dist/memory/store.d.ts.map +0 -1
- package/dist/memory/store.js.map +0 -1
- package/dist/memory/write-queue.d.ts.map +0 -1
- package/dist/memory/write-queue.js.map +0 -1
- package/dist/secrets/auth-profiles.d.ts.map +0 -1
- package/dist/secrets/auth-profiles.js.map +0 -1
- package/dist/secrets/keychain.d.ts.map +0 -1
- package/dist/secrets/keychain.js.map +0 -1
- package/dist/secrets/resolver.d.ts.map +0 -1
- package/dist/secrets/resolver.js.map +0 -1
- package/dist/secrets/sensitivity.d.ts.map +0 -1
- package/dist/secrets/sensitivity.js.map +0 -1
- package/dist/security/integrity.d.ts.map +0 -1
- package/dist/security/integrity.js.map +0 -1
- package/dist/security/patterns.d.ts.map +0 -1
- package/dist/security/patterns.js.map +0 -1
- package/dist/security/redact.d.ts.map +0 -1
- package/dist/security/redact.js.map +0 -1
- package/dist/security/scanner.d.ts.map +0 -1
- package/dist/security/scanner.js.map +0 -1
- package/dist/tools/admin-tools.d.ts.map +0 -1
- package/dist/tools/admin-tools.js.map +0 -1
- package/dist/tools/agent-heartbeat-tools.d.ts.map +0 -1
- package/dist/tools/agent-heartbeat-tools.js.map +0 -1
- package/dist/tools/artifact-tools.d.ts.map +0 -1
- package/dist/tools/artifact-tools.js.map +0 -1
- package/dist/tools/background-task-tools.d.ts.map +0 -1
- package/dist/tools/background-task-tools.js.map +0 -1
- package/dist/tools/brain-tools.d.ts.map +0 -1
- package/dist/tools/brain-tools.js.map +0 -1
- package/dist/tools/builder-tools.d.ts.map +0 -1
- package/dist/tools/builder-tools.js.map +0 -1
- package/dist/tools/decision-reflection-tools.d.ts.map +0 -1
- package/dist/tools/decision-reflection-tools.js.map +0 -1
- package/dist/tools/external-tools.d.ts.map +0 -1
- package/dist/tools/external-tools.js.map +0 -1
- package/dist/tools/goal-tools.d.ts.map +0 -1
- package/dist/tools/goal-tools.js.map +0 -1
- package/dist/tools/mcp-server.d.ts.map +0 -1
- package/dist/tools/mcp-server.js.map +0 -1
- package/dist/tools/memory-tools.d.ts.map +0 -1
- package/dist/tools/memory-tools.js.map +0 -1
- package/dist/tools/session-tools.d.ts.map +0 -1
- package/dist/tools/session-tools.js.map +0 -1
- package/dist/tools/shared.d.ts.map +0 -1
- package/dist/tools/shared.js.map +0 -1
- package/dist/tools/team-tools.d.ts.map +0 -1
- package/dist/tools/team-tools.js.map +0 -1
- package/dist/tools/tool-meta.d.ts.map +0 -1
- package/dist/tools/tool-meta.js.map +0 -1
- package/dist/tools/vault-tools.d.ts.map +0 -1
- package/dist/tools/vault-tools.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/vault-migrations/0001-add-execution-framework.d.ts.map +0 -1
- package/dist/vault-migrations/0001-add-execution-framework.js.map +0 -1
- package/dist/vault-migrations/0002-add-agentic-communication.d.ts.map +0 -1
- package/dist/vault-migrations/0002-add-agentic-communication.js.map +0 -1
- package/dist/vault-migrations/0003-update-execution-pipeline-narration.d.ts.map +0 -1
- package/dist/vault-migrations/0003-update-execution-pipeline-narration.js.map +0 -1
- package/dist/vault-migrations/0004-backfill-schema-versions.d.ts.map +0 -1
- package/dist/vault-migrations/0004-backfill-schema-versions.js.map +0 -1
- package/dist/vault-migrations/0005-create-clementine-json.d.ts.map +0 -1
- package/dist/vault-migrations/0005-create-clementine-json.js.map +0 -1
- package/dist/vault-migrations/helpers.d.ts.map +0 -1
- package/dist/vault-migrations/helpers.js.map +0 -1
- package/dist/vault-migrations/runner.d.ts.map +0 -1
- package/dist/vault-migrations/runner.js.map +0 -1
- package/dist/vault-migrations/types.d.ts.map +0 -1
- package/dist/vault-migrations/types.js.map +0 -1
|
@@ -251,8 +251,10 @@ export declare class PersonalAssistant {
|
|
|
251
251
|
/** Fire-and-forget: extract a reusable skill from a successful execution. */
|
|
252
252
|
private extractSkillFromExecution;
|
|
253
253
|
private preRotationFlush;
|
|
254
|
-
private
|
|
255
|
-
private
|
|
254
|
+
private lastExtractionTimes;
|
|
255
|
+
private memoryExtractionKey;
|
|
256
|
+
private assessMemoryExtraction;
|
|
257
|
+
private logMemoryExtractionSkip;
|
|
256
258
|
private spawnMemoryExtraction;
|
|
257
259
|
private static readonly MEMORY_TOOL_NAMES;
|
|
258
260
|
private extractMemory;
|
package/dist/agent/assistant.js
CHANGED
|
@@ -2872,12 +2872,16 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2872
2872
|
logger.warn({ err, sessionKey: key }, 'Transcript save failed');
|
|
2873
2873
|
}
|
|
2874
2874
|
}
|
|
2875
|
-
// Fire background memory extraction (non-blocking)
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2875
|
+
// Fire background memory extraction (non-blocking). Skips are logged with
|
|
2876
|
+
// structured reasons so memory gaps are diagnosable without reading chats.
|
|
2877
|
+
if (responseText && !responseText.startsWith('Error:')) {
|
|
2878
|
+
const extractionDecision = this.assessMemoryExtraction(text, responseText, key, profile);
|
|
2879
|
+
if (extractionDecision.ok) {
|
|
2880
|
+
this.spawnMemoryExtraction(text, responseText, key, profile).catch(err => logger.debug({ err }, 'Memory extraction failed'));
|
|
2881
|
+
}
|
|
2882
|
+
else {
|
|
2883
|
+
this.logMemoryExtractionSkip(extractionDecision.reason, text, responseText, key, profile);
|
|
2884
|
+
}
|
|
2881
2885
|
}
|
|
2882
2886
|
// Score outcome-driven salience: for the chunks we retrieved this turn,
|
|
2883
2887
|
// check which actually showed up in the response and adjust their
|
|
@@ -4188,14 +4192,15 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4188
4192
|
catch { /* non-fatal */ }
|
|
4189
4193
|
}
|
|
4190
4194
|
// ── Auto-Memory Extraction ────────────────────────────────────────
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
if (
|
|
4197
|
-
return false;
|
|
4198
|
-
// Only skip pure greetings with no substance at all
|
|
4195
|
+
lastExtractionTimes = new Map();
|
|
4196
|
+
memoryExtractionKey(sessionKey, profile) {
|
|
4197
|
+
return `${profile?.slug ?? 'global'}:${sessionKey ?? 'no-session'}`;
|
|
4198
|
+
}
|
|
4199
|
+
assessMemoryExtraction(prompt, response, sessionKey, profile) {
|
|
4200
|
+
if (!this.memoryStore)
|
|
4201
|
+
return { ok: false, reason: 'no_memory_store' };
|
|
4202
|
+
// Only skip pure greetings with no substance at all. Check this before
|
|
4203
|
+
// length so "hey" is diagnosable as intent, not generic shortness.
|
|
4199
4204
|
const pureGreetings = [
|
|
4200
4205
|
'hello', 'hi', 'hey', 'thanks', 'thank you',
|
|
4201
4206
|
'ok', 'okay', 'sure', 'got it', 'sounds good',
|
|
@@ -4203,20 +4208,54 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4203
4208
|
];
|
|
4204
4209
|
const lower = prompt.toLowerCase().trim();
|
|
4205
4210
|
if (pureGreetings.some((g) => lower === g || lower === g + '!' || lower === g + '.')) {
|
|
4206
|
-
return false;
|
|
4211
|
+
return { ok: false, reason: 'pure_greeting' };
|
|
4212
|
+
}
|
|
4213
|
+
if (prompt.length < AUTO_MEMORY_MIN_LENGTH || response.length < 100) {
|
|
4214
|
+
return { ok: false, reason: 'too_short' };
|
|
4207
4215
|
}
|
|
4208
|
-
// Rate limit
|
|
4216
|
+
// Rate limit per session/agent. The old process-wide throttle meant one
|
|
4217
|
+
// active chat could suppress memory extraction for unrelated agents.
|
|
4209
4218
|
const now = Date.now();
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4219
|
+
const key = this.memoryExtractionKey(sessionKey, profile);
|
|
4220
|
+
const last = this.lastExtractionTimes.get(key) ?? 0;
|
|
4221
|
+
if (now - last < 45_000)
|
|
4222
|
+
return { ok: false, reason: 'rate_limited' };
|
|
4223
|
+
this.lastExtractionTimes.set(key, now);
|
|
4224
|
+
return { ok: true };
|
|
4225
|
+
}
|
|
4226
|
+
logMemoryExtractionSkip(reason, userMessage, assistantResponse, sessionKey, profile) {
|
|
4227
|
+
logger.debug({
|
|
4228
|
+
reason,
|
|
4229
|
+
sessionKey,
|
|
4230
|
+
agentSlug: profile?.slug,
|
|
4231
|
+
promptChars: userMessage.length,
|
|
4232
|
+
responseChars: assistantResponse.length,
|
|
4233
|
+
}, 'Auto-memory extraction skipped');
|
|
4234
|
+
if (!this.memoryStore)
|
|
4235
|
+
return;
|
|
4236
|
+
try {
|
|
4237
|
+
this.memoryStore.logExtraction({
|
|
4238
|
+
sessionKey: sessionKey ?? 'unknown',
|
|
4239
|
+
userMessage: userMessage.slice(0, 500),
|
|
4240
|
+
toolName: 'auto_memory_skip',
|
|
4241
|
+
toolInput: JSON.stringify({
|
|
4242
|
+
reason,
|
|
4243
|
+
promptChars: userMessage.length,
|
|
4244
|
+
responseChars: assistantResponse.length,
|
|
4245
|
+
}),
|
|
4246
|
+
extractedAt: new Date().toISOString(),
|
|
4247
|
+
status: `skipped:${reason}`,
|
|
4248
|
+
agentSlug: profile?.slug,
|
|
4249
|
+
});
|
|
4250
|
+
}
|
|
4251
|
+
catch { /* telemetry only */ }
|
|
4214
4252
|
}
|
|
4215
4253
|
async spawnMemoryExtraction(userMessage, assistantResponse, sessionKey, profile) {
|
|
4216
4254
|
// Guard: skip memory extraction if the user message looks like injection
|
|
4217
4255
|
const memScan = scanner.scan(userMessage);
|
|
4218
4256
|
if (memScan.verdict === 'block') {
|
|
4219
4257
|
logger.info('Skipping memory extraction — message was flagged as injection');
|
|
4258
|
+
this.logMemoryExtractionSkip('injection_blocked', userMessage, assistantResponse, sessionKey, profile);
|
|
4220
4259
|
return;
|
|
4221
4260
|
}
|
|
4222
4261
|
let currentMemory = '';
|
|
@@ -10,6 +10,37 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { SelfImproveConfig, SelfImproveExperiment, SelfImproveState } from '../types.js';
|
|
12
12
|
import type { PersonalAssistant } from './assistant.js';
|
|
13
|
+
export declare const USER_MODEL_SLOT_KEYS: readonly ["user_facts", "goals", "relationships", "agent_persona"];
|
|
14
|
+
export type UserModelSlotKey = typeof USER_MODEL_SLOT_KEYS[number];
|
|
15
|
+
export interface SelfImproveEvidenceSnapshot {
|
|
16
|
+
feedbackCreatedAt?: string[];
|
|
17
|
+
reflectionCreatedAt?: string[];
|
|
18
|
+
cronErrorStartedAt?: string[];
|
|
19
|
+
cronReflectionAt?: string[];
|
|
20
|
+
triggerUpdatedAt?: string[];
|
|
21
|
+
triggerCount?: number;
|
|
22
|
+
userModelNeedsSeed?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function isPlateauExperiment(entry: Partial<SelfImproveExperiment>): boolean;
|
|
25
|
+
export declare function latestPlateauTime(history: Array<Partial<SelfImproveExperiment>>): number;
|
|
26
|
+
export declare function newestSelfImproveEvidenceTime(evidence: SelfImproveEvidenceSnapshot): number;
|
|
27
|
+
export declare function shouldSkipSelfImproveForPlateau(history: Array<Partial<SelfImproveExperiment>>, evidence: SelfImproveEvidenceSnapshot): {
|
|
28
|
+
skip: boolean;
|
|
29
|
+
reason?: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function shouldAppendPlateauMarker(history: Array<Partial<SelfImproveExperiment>>, nowMs?: number, windowMs?: number): boolean;
|
|
32
|
+
export declare function reconcileSelfImproveStateSnapshot(state: SelfImproveState, actualPending: number, opts?: {
|
|
33
|
+
nowMs?: number;
|
|
34
|
+
maxDurationMs?: number;
|
|
35
|
+
graceMs?: number;
|
|
36
|
+
}): {
|
|
37
|
+
state: SelfImproveState;
|
|
38
|
+
changed: boolean;
|
|
39
|
+
diagnostics: string[];
|
|
40
|
+
};
|
|
41
|
+
export declare function normalizeUserModelSlots(slots: unknown): Partial<Record<UserModelSlotKey, string>>;
|
|
42
|
+
export declare function sanitizeUserModelFrontmatter(frontmatterYaml: string): string;
|
|
43
|
+
export declare function buildUserModelMarkdown(frontmatterYaml: string, slots: Partial<Record<UserModelSlotKey, string>>, updatedAt?: string): string;
|
|
13
44
|
export declare class SelfImproveLoop {
|
|
14
45
|
private config;
|
|
15
46
|
private assistant;
|
|
@@ -18,6 +49,9 @@ export declare class SelfImproveLoop {
|
|
|
18
49
|
/** Run a focused self-improvement cycle for a specific agent. */
|
|
19
50
|
runForAgent(agentSlug: string, onProposal?: (experiment: SelfImproveExperiment) => Promise<void>): Promise<SelfImproveState>;
|
|
20
51
|
private gatherMetrics;
|
|
52
|
+
private evidenceSnapshot;
|
|
53
|
+
private pendingTriggerEvidence;
|
|
54
|
+
private userModelNeedsSeed;
|
|
21
55
|
private hypothesize;
|
|
22
56
|
private readCurrentState;
|
|
23
57
|
private evaluate;
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
* All proposed changes require Discord approval before being applied.
|
|
10
10
|
*/
|
|
11
11
|
import { randomBytes } from 'node:crypto';
|
|
12
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
12
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
13
13
|
import matter from 'gray-matter';
|
|
14
14
|
import { load as yamlLoad } from 'js-yaml';
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import pino from 'pino';
|
|
17
17
|
import { BASE_DIR, SELF_IMPROVE_DIR, SOUL_FILE, AGENTS_FILE, CRON_FILE, WORKFLOWS_DIR, VAULT_DIR, MEMORY_DB_PATH, AGENTS_DIR, CRON_REFLECTIONS_DIR, GOALS_DIR, } from '../config.js';
|
|
18
18
|
import { listAllGoals } from '../tools/shared.js';
|
|
19
|
+
import { MemoryStore } from '../memory/store.js';
|
|
19
20
|
const logger = pino({ name: 'clementine.self-improve' });
|
|
20
21
|
// ── Defaults ─────────────────────────────────────────────────────────
|
|
21
22
|
const DEFAULT_CONFIG = {
|
|
@@ -157,6 +158,129 @@ function classifyRisk(area) {
|
|
|
157
158
|
default: return 'high';
|
|
158
159
|
}
|
|
159
160
|
}
|
|
161
|
+
export const USER_MODEL_SLOT_KEYS = ['user_facts', 'goals', 'relationships', 'agent_persona'];
|
|
162
|
+
export function isPlateauExperiment(entry) {
|
|
163
|
+
return entry.reason?.startsWith('Plateau') === true
|
|
164
|
+
|| entry.hypothesis?.startsWith('No new hypothesis') === true;
|
|
165
|
+
}
|
|
166
|
+
function entryTimeMs(entry) {
|
|
167
|
+
const ts = Date.parse(entry.finishedAt ?? entry.startedAt ?? '');
|
|
168
|
+
return Number.isFinite(ts) ? ts : 0;
|
|
169
|
+
}
|
|
170
|
+
export function latestPlateauTime(history) {
|
|
171
|
+
let latest = 0;
|
|
172
|
+
for (const entry of history) {
|
|
173
|
+
if (!isPlateauExperiment(entry))
|
|
174
|
+
continue;
|
|
175
|
+
latest = Math.max(latest, entryTimeMs(entry));
|
|
176
|
+
}
|
|
177
|
+
return latest;
|
|
178
|
+
}
|
|
179
|
+
function latestIsoTime(values = []) {
|
|
180
|
+
let latest = 0;
|
|
181
|
+
for (const value of values) {
|
|
182
|
+
const ts = Date.parse(value ?? '');
|
|
183
|
+
if (Number.isFinite(ts))
|
|
184
|
+
latest = Math.max(latest, ts);
|
|
185
|
+
}
|
|
186
|
+
return latest;
|
|
187
|
+
}
|
|
188
|
+
export function newestSelfImproveEvidenceTime(evidence) {
|
|
189
|
+
if (evidence.userModelNeedsSeed)
|
|
190
|
+
return Date.now();
|
|
191
|
+
return Math.max(latestIsoTime(evidence.feedbackCreatedAt), latestIsoTime(evidence.reflectionCreatedAt), latestIsoTime(evidence.cronErrorStartedAt), latestIsoTime(evidence.cronReflectionAt), latestIsoTime(evidence.triggerUpdatedAt));
|
|
192
|
+
}
|
|
193
|
+
export function shouldSkipSelfImproveForPlateau(history, evidence) {
|
|
194
|
+
const plateauAt = latestPlateauTime(history);
|
|
195
|
+
if (plateauAt === 0)
|
|
196
|
+
return { skip: false };
|
|
197
|
+
const newestEvidenceAt = newestSelfImproveEvidenceTime(evidence);
|
|
198
|
+
if (newestEvidenceAt > plateauAt)
|
|
199
|
+
return { skip: false };
|
|
200
|
+
return {
|
|
201
|
+
skip: true,
|
|
202
|
+
reason: `No new self-improvement evidence since latest plateau at ${new Date(plateauAt).toISOString()}`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
export function shouldAppendPlateauMarker(history, nowMs = Date.now(), windowMs = 24 * 60 * 60 * 1000) {
|
|
206
|
+
const plateauAt = latestPlateauTime(history);
|
|
207
|
+
return plateauAt === 0 || nowMs - plateauAt > windowMs;
|
|
208
|
+
}
|
|
209
|
+
export function reconcileSelfImproveStateSnapshot(state, actualPending, opts = {}) {
|
|
210
|
+
const next = { ...state };
|
|
211
|
+
const diagnostics = [];
|
|
212
|
+
let changed = false;
|
|
213
|
+
if (next.pendingApprovals !== actualPending) {
|
|
214
|
+
next.pendingApprovals = actualPending;
|
|
215
|
+
diagnostics.push(`Pending approvals reconciled to ${actualPending}`);
|
|
216
|
+
changed = true;
|
|
217
|
+
}
|
|
218
|
+
if (next.status === 'running' && next.lastRunAt) {
|
|
219
|
+
const started = Date.parse(next.lastRunAt);
|
|
220
|
+
const now = opts.nowMs ?? Date.now();
|
|
221
|
+
const staleAfter = (opts.maxDurationMs ?? DEFAULT_CONFIG.maxDurationMs) + (opts.graceMs ?? 5 * 60 * 1000);
|
|
222
|
+
if (Number.isFinite(started) && now - started > staleAfter) {
|
|
223
|
+
next.status = 'failed';
|
|
224
|
+
next.currentIteration = 0;
|
|
225
|
+
next.lastDiagnostic = `Stale self-improve run cleared after ${Math.round((now - started) / 60_000)} minutes`;
|
|
226
|
+
diagnostics.push(next.lastDiagnostic);
|
|
227
|
+
changed = true;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return { state: next, changed, diagnostics };
|
|
231
|
+
}
|
|
232
|
+
export function normalizeUserModelSlots(slots) {
|
|
233
|
+
if (!slots || typeof slots !== 'object')
|
|
234
|
+
return {};
|
|
235
|
+
const input = slots;
|
|
236
|
+
const out = {};
|
|
237
|
+
for (const key of USER_MODEL_SLOT_KEYS) {
|
|
238
|
+
const value = input[key];
|
|
239
|
+
if (typeof value === 'string' && value.trim()) {
|
|
240
|
+
out[key] = value.trim();
|
|
241
|
+
}
|
|
242
|
+
else if (Array.isArray(value)) {
|
|
243
|
+
const lines = value
|
|
244
|
+
.map(v => typeof v === 'string' ? v.trim() : '')
|
|
245
|
+
.filter(Boolean);
|
|
246
|
+
if (lines.length > 0)
|
|
247
|
+
out[key] = lines.map(v => `- ${v.replace(/^[-*]\s*/, '')}`).join('\n');
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return out;
|
|
251
|
+
}
|
|
252
|
+
export function sanitizeUserModelFrontmatter(frontmatterYaml) {
|
|
253
|
+
const lines = frontmatterYaml
|
|
254
|
+
.trim()
|
|
255
|
+
.split(/\r?\n/)
|
|
256
|
+
.map(line => line.replace(/\s+$/, ''));
|
|
257
|
+
if (/^```(?:ya?ml)?\s*$/i.test(lines[0]?.trim() ?? '')) {
|
|
258
|
+
lines.shift();
|
|
259
|
+
}
|
|
260
|
+
if (/^```\s*$/.test(lines[lines.length - 1]?.trim() ?? '')) {
|
|
261
|
+
lines.pop();
|
|
262
|
+
}
|
|
263
|
+
while (lines[0]?.trim() === '---') {
|
|
264
|
+
lines.shift();
|
|
265
|
+
}
|
|
266
|
+
while (lines[lines.length - 1]?.trim() === '---') {
|
|
267
|
+
lines.pop();
|
|
268
|
+
}
|
|
269
|
+
const sanitized = lines
|
|
270
|
+
.filter(line => !/^\s*last_updated\s*:/i.test(line))
|
|
271
|
+
.join('\n')
|
|
272
|
+
.trim();
|
|
273
|
+
return sanitized || 'confidence_scores: {}';
|
|
274
|
+
}
|
|
275
|
+
export function buildUserModelMarkdown(frontmatterYaml, slots, updatedAt = new Date().toISOString()) {
|
|
276
|
+
const body = USER_MODEL_SLOT_KEYS
|
|
277
|
+
.filter(key => slots[key])
|
|
278
|
+
.map(key => `## ${key}\n\n${slots[key]}`)
|
|
279
|
+
.join('\n\n');
|
|
280
|
+
return `---\n${sanitizeUserModelFrontmatter(frontmatterYaml)}\nlast_updated: "${updatedAt}"\n---\n\n# User Model\n\n` +
|
|
281
|
+
`This file is auto-generated by the self-improvement loop. The DB-backed user_model_blocks table is the prompt source of truth.\n\n` +
|
|
282
|
+
`${body}\n`;
|
|
283
|
+
}
|
|
160
284
|
// ── SelfImproveLoop ──────────────────────────────────────────────────
|
|
161
285
|
export class SelfImproveLoop {
|
|
162
286
|
config;
|
|
@@ -204,6 +328,7 @@ export class SelfImproveLoop {
|
|
|
204
328
|
state.status = 'running';
|
|
205
329
|
state.lastRunAt = new Date().toISOString();
|
|
206
330
|
state.currentIteration = 0;
|
|
331
|
+
delete state.lastDiagnostic;
|
|
207
332
|
this.saveState(state);
|
|
208
333
|
const loopStart = Date.now();
|
|
209
334
|
const history = this.loadExperimentLog();
|
|
@@ -223,6 +348,15 @@ export class SelfImproveLoop {
|
|
|
223
348
|
cronSuccessRate: metrics.cronSuccessRate,
|
|
224
349
|
avgResponseQuality: 0, // Updated as we evaluate
|
|
225
350
|
};
|
|
351
|
+
const plateauSkip = shouldSkipSelfImproveForPlateau(history, this.evidenceSnapshot(metrics));
|
|
352
|
+
if (plateauSkip.skip) {
|
|
353
|
+
logger.info({ reason: plateauSkip.reason }, 'Self-improve skipped after plateau — no new evidence');
|
|
354
|
+
state.status = 'completed';
|
|
355
|
+
state.currentIteration = 0;
|
|
356
|
+
state.lastDiagnostic = plateauSkip.reason;
|
|
357
|
+
this.saveState(state);
|
|
358
|
+
return state;
|
|
359
|
+
}
|
|
226
360
|
// Synthesize feedback patterns and update user model before experiment loop
|
|
227
361
|
await this.synthesizeFeedbackPatterns();
|
|
228
362
|
await this.updateUserModel();
|
|
@@ -238,23 +372,31 @@ export class SelfImproveLoop {
|
|
|
238
372
|
// Record the plateau in the experiment log so it's not silently
|
|
239
373
|
// invisible. Helps the dashboard and failure monitor distinguish
|
|
240
374
|
// "exhausted diverse hypotheses" from "crashed mid-run".
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
375
|
+
if (shouldAppendPlateauMarker(history)) {
|
|
376
|
+
const plateauExperiment = {
|
|
377
|
+
id: randomBytes(4).toString('hex'),
|
|
378
|
+
iteration: i,
|
|
379
|
+
startedAt: new Date(loopStart).toISOString(),
|
|
380
|
+
finishedAt: new Date().toISOString(),
|
|
381
|
+
durationMs: Date.now() - loopStart,
|
|
382
|
+
area: 'soul',
|
|
383
|
+
target: 'n/a',
|
|
384
|
+
hypothesis: 'No new hypothesis — diversity constraint exhausted',
|
|
385
|
+
proposedChange: '',
|
|
386
|
+
baselineScore: 0,
|
|
387
|
+
score: 0,
|
|
388
|
+
accepted: false,
|
|
389
|
+
approvalStatus: 'denied',
|
|
390
|
+
reason: 'Plateau: no novel improvement area remaining',
|
|
391
|
+
};
|
|
392
|
+
this.appendExperimentLog(plateauExperiment);
|
|
393
|
+
history.push(plateauExperiment);
|
|
394
|
+
state.totalExperiments++;
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
logger.info('Recent plateau marker already exists — not appending duplicate');
|
|
398
|
+
}
|
|
399
|
+
state.lastDiagnostic = 'Plateau: no novel improvement area remaining';
|
|
258
400
|
break;
|
|
259
401
|
}
|
|
260
402
|
state.currentIteration = i;
|
|
@@ -644,6 +786,58 @@ export class SelfImproveLoop {
|
|
|
644
786
|
advisorInsights,
|
|
645
787
|
};
|
|
646
788
|
}
|
|
789
|
+
evidenceSnapshot(metrics) {
|
|
790
|
+
const triggerEvidence = this.pendingTriggerEvidence();
|
|
791
|
+
return {
|
|
792
|
+
feedbackCreatedAt: metrics.negativeFeedback.map(f => f.createdAt).filter((v) => !!v),
|
|
793
|
+
reflectionCreatedAt: metrics.cronReflections.map(r => r.timestamp).filter(Boolean),
|
|
794
|
+
cronErrorStartedAt: metrics.cronErrors.map(e => e.startedAt).filter((v) => !!v),
|
|
795
|
+
cronReflectionAt: metrics.cronReflections.map(r => r.timestamp).filter(Boolean),
|
|
796
|
+
triggerUpdatedAt: triggerEvidence.updatedAt,
|
|
797
|
+
triggerCount: triggerEvidence.count,
|
|
798
|
+
userModelNeedsSeed: this.userModelNeedsSeed(metrics),
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
pendingTriggerEvidence() {
|
|
802
|
+
const triggersDir = path.join(SELF_IMPROVE_DIR, 'triggers');
|
|
803
|
+
try {
|
|
804
|
+
if (!existsSync(triggersDir))
|
|
805
|
+
return { count: 0, updatedAt: [] };
|
|
806
|
+
const files = readdirSync(triggersDir).filter(f => f.endsWith('.json'));
|
|
807
|
+
return {
|
|
808
|
+
count: files.length,
|
|
809
|
+
updatedAt: files.map(f => {
|
|
810
|
+
try {
|
|
811
|
+
return statSync(path.join(triggersDir, f)).mtime.toISOString();
|
|
812
|
+
}
|
|
813
|
+
catch {
|
|
814
|
+
return '';
|
|
815
|
+
}
|
|
816
|
+
}).filter(Boolean),
|
|
817
|
+
};
|
|
818
|
+
}
|
|
819
|
+
catch {
|
|
820
|
+
return { count: 0, updatedAt: [] };
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
userModelNeedsSeed(metrics) {
|
|
824
|
+
try {
|
|
825
|
+
const store = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
|
|
826
|
+
store.initialize();
|
|
827
|
+
try {
|
|
828
|
+
const signalCount = store.getRecentReflections(30).length + store.getRecentFeedback(30).length;
|
|
829
|
+
if (signalCount < 5 && metrics.negativeFeedback.length + metrics.cronReflections.length < 5)
|
|
830
|
+
return false;
|
|
831
|
+
return store.getAllUserModelBlocks().filter(b => b.content.trim()).length === 0;
|
|
832
|
+
}
|
|
833
|
+
finally {
|
|
834
|
+
store.close();
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
catch {
|
|
838
|
+
return false;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
647
841
|
// ── Steps 2-3: Diagnose + Hypothesize ────────────────────────────
|
|
648
842
|
async hypothesize(metrics, history) {
|
|
649
843
|
// Read targeted triggers (written by cron scheduler when jobs fail repeatedly)
|
|
@@ -948,11 +1142,17 @@ export class SelfImproveLoop {
|
|
|
948
1142
|
: rawParsed ? [rawParsed] : [];
|
|
949
1143
|
if (opportunities.length === 0)
|
|
950
1144
|
return null;
|
|
951
|
-
// Pick the first opportunity that isn't over-targeted
|
|
952
|
-
|
|
1145
|
+
// Pick the first opportunity that isn't over-targeted. Down-rank SOUL.md
|
|
1146
|
+
// after plateau/denied loops unless feedback synthesis produced fresh
|
|
1147
|
+
// SOUL candidates; most operational signals should become prompt
|
|
1148
|
+
// overrides, advisor rules, agent changes, or cron fixes.
|
|
1149
|
+
const isViableOpportunity = (o) => {
|
|
953
1150
|
const key = `${o.area}:${o.target}`;
|
|
954
1151
|
return !overTargeted.includes(key) && !overTargetedAreas.includes(o.area);
|
|
955
|
-
}
|
|
1152
|
+
};
|
|
1153
|
+
const hasSoulCandidates = !!soulCandidatesText && !/No candidates/i.test(soulCandidatesText);
|
|
1154
|
+
const recentSoulPlateau = history.slice(-10).some(e => e.area === 'soul' && isPlateauExperiment(e));
|
|
1155
|
+
const selected = opportunities.find((o) => isViableOpportunity(o) && (o.area !== 'soul' || hasSoulCandidates || !recentSoulPlateau)) ?? opportunities.find(isViableOpportunity) ?? opportunities[0];
|
|
956
1156
|
// ── Step 2: Proposal — load only the target file, generate specific change ──
|
|
957
1157
|
const currentContent = await this.readCurrentState(selected.area, selected.target);
|
|
958
1158
|
const proposalPrompt = `You identified this as the highest-impact improvement:\n` +
|
|
@@ -1373,12 +1573,12 @@ export class SelfImproveLoop {
|
|
|
1373
1573
|
/** Update the structured user model from interaction data. */
|
|
1374
1574
|
async updateUserModel() {
|
|
1375
1575
|
try {
|
|
1376
|
-
const { MemoryStore } = await import('../memory/store.js');
|
|
1377
1576
|
const store = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
|
|
1378
1577
|
store.initialize();
|
|
1379
1578
|
const reflections = store.getRecentReflections(30);
|
|
1380
1579
|
const feedback = store.getRecentFeedback(30);
|
|
1381
1580
|
const patterns = store.getBehavioralPatterns(1);
|
|
1581
|
+
const existingDbModel = store.renderUserModel();
|
|
1382
1582
|
store.close();
|
|
1383
1583
|
if (reflections.length + feedback.length < 5) {
|
|
1384
1584
|
logger.info('Not enough interaction data for user model update');
|
|
@@ -1397,36 +1597,74 @@ export class SelfImproveLoop {
|
|
|
1397
1597
|
const feedbackSummary = feedback.slice(0, 15).map(f => `- [${f.rating}] ${f.channel}: ${f.comment || f.messageSnippet || '(no detail)'}`.slice(0, 120)).join('\n');
|
|
1398
1598
|
const patternSummary = patterns.map(p => `- "${p.correction}" [${p.category}] x${p.count}`).join('\n');
|
|
1399
1599
|
const prompt = `You are updating a structured user model based on interaction data. The model tracks the owner's expertise, priorities, communication preferences, and behavioral patterns.\n\n` +
|
|
1400
|
-
`## Current Model\n${existingModel || '(empty — first synthesis)'}\n\n` +
|
|
1600
|
+
`## Current Markdown Model\n${existingModel || '(empty — first synthesis)'}\n\n` +
|
|
1601
|
+
`## Current DB Slots\n${existingDbModel || '(empty — no user_model_blocks populated yet)'}\n\n` +
|
|
1401
1602
|
`## Recent Session Reflections (${reflections.length})\n${reflectionSummary || '(none)'}\n\n` +
|
|
1402
1603
|
`## Recent Feedback (${feedback.length})\n${feedbackSummary || '(none)'}\n\n` +
|
|
1403
1604
|
`## Recurring Behavioral Patterns\n${patternSummary || '(none)'}\n\n` +
|
|
1404
1605
|
`## Instructions\n` +
|
|
1405
|
-
`
|
|
1406
|
-
`-
|
|
1407
|
-
`-
|
|
1408
|
-
|
|
1409
|
-
`-
|
|
1410
|
-
`-
|
|
1411
|
-
|
|
1412
|
-
|
|
1606
|
+
`Return a JSON object with:\n` +
|
|
1607
|
+
`- frontmatterYaml: YAML body for USER_MODEL.md, without --- delimiters. Include expertise, priorities, communication, patterns, confidence_scores.\n` +
|
|
1608
|
+
`- slots: object with exactly these keys: user_facts, goals, relationships, agent_persona.\n\n` +
|
|
1609
|
+
`Slot guidance:\n` +
|
|
1610
|
+
`- user_facts: durable facts about the owner, expertise, working style, identifiers that should always be top-of-mind.\n` +
|
|
1611
|
+
`- goals: active intents/priorities only; omit stale or weakly inferred goals.\n` +
|
|
1612
|
+
`- relationships: people, companies, agents, projects, and how they relate to the owner.\n` +
|
|
1613
|
+
`- agent_persona: durable guidance for Clementine's behavior with this owner.\n\n` +
|
|
1614
|
+
`Keep each slot concise (prefer under 1200 chars). Preserve existing data that's still accurate. Only update fields where evidence supports a change. Use an empty string for a slot with no evidence.\n` +
|
|
1615
|
+
`Output ONLY valid JSON, no markdown.`;
|
|
1413
1616
|
const result = await this.assistant.runPlanStep('si-user-model', prompt, {
|
|
1414
1617
|
tier: 1,
|
|
1415
1618
|
maxTurns: 1,
|
|
1416
1619
|
disableTools: true,
|
|
1620
|
+
outputFormat: {
|
|
1621
|
+
type: 'json_schema',
|
|
1622
|
+
schema: {
|
|
1623
|
+
type: 'object',
|
|
1624
|
+
properties: {
|
|
1625
|
+
frontmatterYaml: { type: 'string' },
|
|
1626
|
+
slots: {
|
|
1627
|
+
type: 'object',
|
|
1628
|
+
properties: {
|
|
1629
|
+
user_facts: { type: 'string' },
|
|
1630
|
+
goals: { type: 'string' },
|
|
1631
|
+
relationships: { type: 'string' },
|
|
1632
|
+
agent_persona: { type: 'string' },
|
|
1633
|
+
},
|
|
1634
|
+
required: ['user_facts', 'goals', 'relationships', 'agent_persona'],
|
|
1635
|
+
},
|
|
1636
|
+
},
|
|
1637
|
+
required: ['frontmatterYaml', 'slots'],
|
|
1638
|
+
},
|
|
1639
|
+
},
|
|
1417
1640
|
});
|
|
1418
|
-
|
|
1419
|
-
const
|
|
1420
|
-
|
|
1421
|
-
|
|
1641
|
+
const parsed = this.parseJsonResponse(result);
|
|
1642
|
+
const slots = normalizeUserModelSlots(parsed?.slots);
|
|
1643
|
+
const frontmatterYaml = typeof parsed?.frontmatterYaml === 'string' && parsed.frontmatterYaml.trim()
|
|
1644
|
+
? parsed.frontmatterYaml.trim()
|
|
1645
|
+
: 'confidence_scores: {}';
|
|
1646
|
+
if (Object.keys(slots).length === 0) {
|
|
1647
|
+
logger.warn('User model synthesis returned no populated DB slots');
|
|
1422
1648
|
return;
|
|
1423
1649
|
}
|
|
1424
1650
|
const modelDir = path.join(VAULT_DIR, '00-System');
|
|
1425
1651
|
if (!existsSync(modelDir))
|
|
1426
1652
|
mkdirSync(modelDir, { recursive: true });
|
|
1427
|
-
const
|
|
1653
|
+
const writeStore = new MemoryStore(MEMORY_DB_PATH, VAULT_DIR);
|
|
1654
|
+
writeStore.initialize();
|
|
1655
|
+
try {
|
|
1656
|
+
for (const key of USER_MODEL_SLOT_KEYS) {
|
|
1657
|
+
const content = slots[key];
|
|
1658
|
+
if (content)
|
|
1659
|
+
writeStore.setUserModelBlock({ slot: key, content });
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
finally {
|
|
1663
|
+
writeStore.close();
|
|
1664
|
+
}
|
|
1665
|
+
const content = buildUserModelMarkdown(frontmatterYaml, slots);
|
|
1428
1666
|
writeFileSync(modelFile, content);
|
|
1429
|
-
logger.info('User model updated: USER_MODEL.md');
|
|
1667
|
+
logger.info({ slots: Object.keys(slots) }, 'User model updated: DB slots + USER_MODEL.md');
|
|
1430
1668
|
}
|
|
1431
1669
|
catch (err) {
|
|
1432
1670
|
logger.error({ err }, 'User model update failed');
|
|
@@ -1481,12 +1719,14 @@ export class SelfImproveLoop {
|
|
|
1481
1719
|
reconcileState() {
|
|
1482
1720
|
const state = this.loadState();
|
|
1483
1721
|
const actualPending = this.getPendingChanges().length;
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1722
|
+
const reconciled = reconcileSelfImproveStateSnapshot(state, actualPending, {
|
|
1723
|
+
maxDurationMs: this.config.maxDurationMs,
|
|
1724
|
+
});
|
|
1725
|
+
if (reconciled.changed) {
|
|
1726
|
+
logger.warn({ diagnostics: reconciled.diagnostics, storedPending: state.pendingApprovals, actualPending }, 'Self-improve state drift — reconciling');
|
|
1727
|
+
this.saveState(reconciled.state);
|
|
1488
1728
|
}
|
|
1489
|
-
return state;
|
|
1729
|
+
return reconciled.state;
|
|
1490
1730
|
}
|
|
1491
1731
|
/** Expire pending proposals older than APPROVAL_TTL_MS. */
|
|
1492
1732
|
expireStaleProposals() {
|
package/dist/gateway/router.js
CHANGED
|
@@ -1684,6 +1684,7 @@ export class Gateway {
|
|
|
1684
1684
|
`Last run: ${state.lastRunAt || 'never'}\n` +
|
|
1685
1685
|
`Total experiments: ${state.totalExperiments}\n` +
|
|
1686
1686
|
`Pending approvals: ${state.pendingApprovals}\n` +
|
|
1687
|
+
(state.lastDiagnostic ? `Diagnostic: ${state.lastDiagnostic}\n` : '') +
|
|
1687
1688
|
`Baseline — Feedback: ${(m.feedbackPositiveRatio * 100).toFixed(0)}% positive, ` +
|
|
1688
1689
|
`Cron: ${(m.cronSuccessRate * 100).toFixed(0)}% success, ` +
|
|
1689
1690
|
`Quality: ${m.avgResponseQuality.toFixed(2)}`;
|
package/dist/memory/store.d.ts
CHANGED
|
@@ -1282,12 +1282,23 @@ export declare class MemoryStore {
|
|
|
1282
1282
|
count: number;
|
|
1283
1283
|
}>;
|
|
1284
1284
|
tableRowCounts: Record<string, number>;
|
|
1285
|
+
recentActivity: {
|
|
1286
|
+
recallTracesLast7d: number;
|
|
1287
|
+
recallTracesLast30d: number;
|
|
1288
|
+
extractionSkipsLast30d: number;
|
|
1289
|
+
};
|
|
1285
1290
|
topCitedLast30d: Array<{
|
|
1286
1291
|
chunkId: number;
|
|
1287
1292
|
sourceFile: string;
|
|
1288
1293
|
section: string;
|
|
1289
1294
|
refCount: number;
|
|
1290
1295
|
}>;
|
|
1296
|
+
userModelSlots: {
|
|
1297
|
+
total: number;
|
|
1298
|
+
populated: number;
|
|
1299
|
+
global: number;
|
|
1300
|
+
agentScoped: number;
|
|
1301
|
+
};
|
|
1291
1302
|
staleUserModelSlots: Array<{
|
|
1292
1303
|
slot: string;
|
|
1293
1304
|
ageDays: number;
|
|
@@ -1300,6 +1311,7 @@ export declare class MemoryStore {
|
|
|
1300
1311
|
salience: number;
|
|
1301
1312
|
lastOutcomeScore: number;
|
|
1302
1313
|
}>;
|
|
1314
|
+
selfImprovePlateausLast7d: number;
|
|
1303
1315
|
chunkCacheStats: ReturnType<HotCache<number, unknown>['stats']>;
|
|
1304
1316
|
writeQueue: {
|
|
1305
1317
|
size: number;
|