clementine-agent 1.18.8 → 1.18.10
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 +9 -2
- package/dist/agent/assistant.js +246 -44
- package/dist/agent/local-turn.d.ts +32 -0
- package/dist/agent/local-turn.js +107 -0
- package/dist/agent/self-improve-loop.js +1 -0
- package/dist/agent/self-improve.d.ts +34 -0
- package/dist/agent/self-improve.js +282 -42
- package/dist/agent/turn-policy.d.ts +5 -0
- package/dist/agent/turn-policy.js +39 -0
- package/dist/channels/discord-agent-bot.js +2 -0
- package/dist/channels/slack-agent-bot.js +1 -1
- package/dist/channels/slack.js +1 -1
- package/dist/channels/telegram.js +10 -3
- package/dist/cli/dashboard.js +540 -51
- package/dist/config/clementine-json.d.ts +30 -0
- package/dist/config/clementine-json.js +39 -1
- package/dist/config/effective-config.js +5 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +6 -0
- package/dist/gateway/cron-scheduler.d.ts +1 -1
- package/dist/gateway/cron-scheduler.js +17 -3
- package/dist/gateway/router.d.ts +8 -0
- package/dist/gateway/router.js +254 -7
- 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 +2 -2
- 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
|
@@ -27,6 +27,11 @@ import { AgentManager } from './agent-manager.js';
|
|
|
27
27
|
* SDK result; this function is for pre-flight planning only.
|
|
28
28
|
*/
|
|
29
29
|
export declare function estimateTokens(text: string): number;
|
|
30
|
+
export declare function looksLikeContextThrashText(value: unknown): boolean;
|
|
31
|
+
export declare function contextThrashRecoveryNotice(): string;
|
|
32
|
+
export declare function buildContextThrashRecoveryPrompt(userRequest: string, priorFailureText?: string): string;
|
|
33
|
+
/** Autonomous jobs use this sentinel to mean "completed, but do not notify the owner." */
|
|
34
|
+
export declare function isAutonomousNothingOutput(response: string): boolean;
|
|
30
35
|
export interface ProjectMeta {
|
|
31
36
|
path: string;
|
|
32
37
|
description?: string;
|
|
@@ -251,8 +256,10 @@ export declare class PersonalAssistant {
|
|
|
251
256
|
/** Fire-and-forget: extract a reusable skill from a successful execution. */
|
|
252
257
|
private extractSkillFromExecution;
|
|
253
258
|
private preRotationFlush;
|
|
254
|
-
private
|
|
255
|
-
private
|
|
259
|
+
private lastExtractionTimes;
|
|
260
|
+
private memoryExtractionKey;
|
|
261
|
+
private assessMemoryExtraction;
|
|
262
|
+
private logMemoryExtractionSkip;
|
|
256
263
|
private spawnMemoryExtraction;
|
|
257
264
|
private static readonly MEMORY_TOOL_NAMES;
|
|
258
265
|
private extractMemory;
|
package/dist/agent/assistant.js
CHANGED
|
@@ -35,6 +35,7 @@ import { classifyIntent, getStrategyGuidance } from './intent-classifier.js';
|
|
|
35
35
|
import { getEventLog } from './session-event-log.js';
|
|
36
36
|
import { routeToolSurface, TOOL_SURFACE_WARN_THRESHOLD } from './tool-router.js';
|
|
37
37
|
import { decideTurnPolicy } from './turn-policy.js';
|
|
38
|
+
import { loadClementineJson } from '../config/clementine-json.js';
|
|
38
39
|
// ── Channel capabilities ────────────────────────────────────────────
|
|
39
40
|
/** Map channel label to its capabilities so the agent adapts its responses. */
|
|
40
41
|
function getChannelCapabilities(channel) {
|
|
@@ -172,6 +173,37 @@ export function estimateTokens(text) {
|
|
|
172
173
|
return 0;
|
|
173
174
|
return Math.ceil(text.length / 3.3);
|
|
174
175
|
}
|
|
176
|
+
export function looksLikeContextThrashText(value) {
|
|
177
|
+
const text = String(value ?? '');
|
|
178
|
+
return /autocompact\s+is\s+thrashing|context\s+refilled\s+to\s+the\s+limit|refilled\s+to\s+the\s+limit\s+within/i.test(text);
|
|
179
|
+
}
|
|
180
|
+
export function contextThrashRecoveryNotice() {
|
|
181
|
+
return [
|
|
182
|
+
'I hit a context-size recovery issue while working on that.',
|
|
183
|
+
'I saved the request and reset the session so I can continue with smaller reads instead of repeating the same large-output path.',
|
|
184
|
+
].join(' ');
|
|
185
|
+
}
|
|
186
|
+
export function buildContextThrashRecoveryPrompt(userRequest, priorFailureText = '') {
|
|
187
|
+
const parts = [
|
|
188
|
+
'[CONTEXT-THRASH RECOVERY]',
|
|
189
|
+
'',
|
|
190
|
+
'The previous interactive attempt failed because tool output filled the context window and SDK autocompact thrashed. Continue the user request, but use a small diagnostic pass.',
|
|
191
|
+
'',
|
|
192
|
+
'User request:',
|
|
193
|
+
userRequest,
|
|
194
|
+
'',
|
|
195
|
+
'Recovery rules:',
|
|
196
|
+
'- Do not repeat broad reads, full log dumps, full JSON dumps, or unbounded API/list commands.',
|
|
197
|
+
'- Prefer status files, summaries, indexes, `rg`, `tail -80`, `head -80`, and `sed -n` slices.',
|
|
198
|
+
'- For cron or unleashed jobs, inspect only `status.json`, the tail of `progress.jsonl`, and the latest run preview first. Do not read full run logs unless a short slice identifies the exact file and range.',
|
|
199
|
+
'- Preserve the user intent. Identify what failed, what you changed or verified, and the next action.',
|
|
200
|
+
'- Finish with `TASK_COMPLETE:` followed by a concise user-facing summary.',
|
|
201
|
+
];
|
|
202
|
+
if (priorFailureText.trim()) {
|
|
203
|
+
parts.push('', 'Prior failure excerpt:', priorFailureText.trim().slice(0, 1200));
|
|
204
|
+
}
|
|
205
|
+
return parts.join('\n');
|
|
206
|
+
}
|
|
175
207
|
/**
|
|
176
208
|
* Strip lone Unicode surrogates (U+D800–U+DFFF) from a string so it can be
|
|
177
209
|
* safely serialized to JSON. Lone surrogates are valid in JS strings but
|
|
@@ -640,6 +672,27 @@ function yesterdayISO() {
|
|
|
640
672
|
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
|
641
673
|
}
|
|
642
674
|
// ── Cron Output Extraction ──────────────────────────────────────────
|
|
675
|
+
/** Autonomous jobs use this sentinel to mean "completed, but do not notify the owner." */
|
|
676
|
+
export function isAutonomousNothingOutput(response) {
|
|
677
|
+
const trimmed = response.trim();
|
|
678
|
+
if (!trimmed)
|
|
679
|
+
return false;
|
|
680
|
+
if (trimmed === '__NOTHING__')
|
|
681
|
+
return true;
|
|
682
|
+
if (/^_*NOTHING_*$/i.test(trimmed))
|
|
683
|
+
return true;
|
|
684
|
+
if (/^_*NOTHING_*\s*(\(|$)/im.test(trimmed))
|
|
685
|
+
return true;
|
|
686
|
+
if (/^(_*NOTHING_*\s*)?\[MONITORING\]\s*$/i.test(trimmed))
|
|
687
|
+
return true;
|
|
688
|
+
if (trimmed.length > 80)
|
|
689
|
+
return false;
|
|
690
|
+
const lower = trimmed.toLowerCase();
|
|
691
|
+
return lower === 'nothing to report'
|
|
692
|
+
|| lower === 'nothing new to report'
|
|
693
|
+
|| lower === 'no updates'
|
|
694
|
+
|| lower === 'all clear';
|
|
695
|
+
}
|
|
643
696
|
/** Return the last non-empty text block that came after the last tool call, or '' if nothing/sentinel. */
|
|
644
697
|
function extractDeliverable(trace) {
|
|
645
698
|
if (trace.length === 0)
|
|
@@ -657,7 +710,7 @@ function extractDeliverable(trace) {
|
|
|
657
710
|
for (let i = trace.length - 1; i > lastToolIdx; i--) {
|
|
658
711
|
if (trace[i].type === 'text') {
|
|
659
712
|
const text = trace[i].content.trim();
|
|
660
|
-
if (text
|
|
713
|
+
if (isAutonomousNothingOutput(text))
|
|
661
714
|
return '';
|
|
662
715
|
if (text.length > 0)
|
|
663
716
|
return text;
|
|
@@ -1609,6 +1662,54 @@ Never spawn a sub-agent with vague instructions like "handle this brief."
|
|
|
1609
1662
|
|
|
1610
1663
|
When ${owner} expresses satisfaction ("nice", "perfect", "great job", "thanks") or dissatisfaction ("no", "wrong", "that's not right", "ugh"), call \`feedback_log\` with an appropriate rating ('positive' or 'negative') and a brief comment summarizing the context. This helps me learn from interactions.`);
|
|
1611
1664
|
}
|
|
1665
|
+
try {
|
|
1666
|
+
const jsonExperience = loadClementineJson(BASE_DIR).assistant ?? {};
|
|
1667
|
+
const pick = (value, allowed) => allowed.includes(value) ? value : undefined;
|
|
1668
|
+
const experience = {
|
|
1669
|
+
proactivity: pick(process.env.ASSISTANT_PROACTIVITY, ['quiet', 'balanced', 'proactive', 'operator']) ?? jsonExperience.proactivity,
|
|
1670
|
+
responseStyle: pick(process.env.ASSISTANT_RESPONSE_STYLE, ['concise', 'balanced', 'detailed']) ?? jsonExperience.responseStyle,
|
|
1671
|
+
progressVisibility: pick(process.env.ASSISTANT_PROGRESS_VISIBILITY, ['quiet', 'normal', 'detailed']) ?? jsonExperience.progressVisibility,
|
|
1672
|
+
autonomy: pick(process.env.ASSISTANT_AUTONOMY, ['ask_first', 'balanced', 'act_when_safe']) ?? jsonExperience.autonomy,
|
|
1673
|
+
};
|
|
1674
|
+
const lines = [];
|
|
1675
|
+
if (experience.proactivity) {
|
|
1676
|
+
const guidance = {
|
|
1677
|
+
quiet: 'Only interrupt for urgent or explicitly requested work. Avoid unsolicited next steps.',
|
|
1678
|
+
balanced: 'Offer useful next steps when natural, but do not create extra work without a clear reason.',
|
|
1679
|
+
proactive: 'Surface likely next actions, risks, and background-work opportunities before the owner has to ask.',
|
|
1680
|
+
operator: 'Operate forward: propose plans, queue safe background work, monitor progress, and keep the owner informed.',
|
|
1681
|
+
};
|
|
1682
|
+
lines.push(`- Proactivity: ${experience.proactivity}. ${guidance[experience.proactivity]}`);
|
|
1683
|
+
}
|
|
1684
|
+
if (experience.responseStyle) {
|
|
1685
|
+
const guidance = {
|
|
1686
|
+
concise: 'Default to short, direct answers. Expand only when the task needs it.',
|
|
1687
|
+
balanced: 'Match detail to task complexity.',
|
|
1688
|
+
detailed: 'Include more reasoning, context, and verification detail for substantive work.',
|
|
1689
|
+
};
|
|
1690
|
+
lines.push(`- Response style: ${experience.responseStyle}. ${guidance[experience.responseStyle]}`);
|
|
1691
|
+
}
|
|
1692
|
+
if (experience.progressVisibility) {
|
|
1693
|
+
const guidance = {
|
|
1694
|
+
quiet: 'Minimize process narration unless work is slow, blocked, or risky.',
|
|
1695
|
+
normal: 'Share important progress and decision points.',
|
|
1696
|
+
detailed: 'Keep the owner posted during background or multi-tool work, including failures and recoveries.',
|
|
1697
|
+
};
|
|
1698
|
+
lines.push(`- Progress visibility: ${experience.progressVisibility}. ${guidance[experience.progressVisibility]}`);
|
|
1699
|
+
}
|
|
1700
|
+
if (experience.autonomy) {
|
|
1701
|
+
const guidance = {
|
|
1702
|
+
ask_first: 'Ask before taking actions that change external systems or user data.',
|
|
1703
|
+
balanced: 'Act on low-risk reversible steps; ask on irreversible, costly, or ambiguous steps.',
|
|
1704
|
+
act_when_safe: 'Use judgment and proceed on safe, reversible, clearly beneficial work.',
|
|
1705
|
+
};
|
|
1706
|
+
lines.push(`- Autonomy: ${experience.autonomy}. ${guidance[experience.autonomy]}`);
|
|
1707
|
+
}
|
|
1708
|
+
if (lines.length > 0) {
|
|
1709
|
+
parts.push(`## Owner Experience Preferences\n\n${lines.join('\n')}`);
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
catch { /* config preferences are optional */ }
|
|
1612
1713
|
// Verbose level overrides
|
|
1613
1714
|
if (verboseLevel === 'quiet') {
|
|
1614
1715
|
parts.push(`## Verbosity: Quiet\n\nGive results directly. Skip reasoning and progress updates unless asked.`);
|
|
@@ -2667,8 +2768,22 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2667
2768
|
}
|
|
2668
2769
|
// Lone-surrogate sanitization happens at the SDK boundary (see query() wrapper).
|
|
2669
2770
|
let effectivePrompt = text;
|
|
2771
|
+
const recentExchangesForIntent = key ? this.lastExchanges.get(key) : undefined;
|
|
2772
|
+
const intent = classifyIntent(text, recentExchangesForIntent);
|
|
2773
|
+
const turnPolicy = decideTurnPolicy({
|
|
2774
|
+
text,
|
|
2775
|
+
intent,
|
|
2776
|
+
hasRecentContext: !!(recentExchangesForIntent?.length || (key && this.sessions.has(key))),
|
|
2777
|
+
});
|
|
2778
|
+
const suppressContextInjection = turnPolicy.suppressContextInjection === true;
|
|
2779
|
+
if (key && turnPolicy.suppressSessionResume) {
|
|
2780
|
+
this.sessions.delete(key);
|
|
2781
|
+
this.exchangeCounts.set(key, 0);
|
|
2782
|
+
this.restoredSessions.delete(key);
|
|
2783
|
+
this._compactedSessions.delete(key);
|
|
2784
|
+
}
|
|
2670
2785
|
// If session rotated, use instant local summary + handoff + kick off LLM summary in background
|
|
2671
|
-
if (sessionRotated && key) {
|
|
2786
|
+
if (sessionRotated && key && !suppressContextInjection) {
|
|
2672
2787
|
const summary = this.buildLocalSummary(key);
|
|
2673
2788
|
const handoff = this.loadHandoff(key);
|
|
2674
2789
|
const contextParts = [];
|
|
@@ -2687,7 +2802,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2687
2802
|
this.summarizeSessionAsync(key).catch(err => logger.debug({ err, key }, 'Session summarization failed'));
|
|
2688
2803
|
}
|
|
2689
2804
|
// Resilience: inject exchange history if no session_id stored
|
|
2690
|
-
if (key && !this.sessions.has(key) && !sessionRotated) {
|
|
2805
|
+
if (key && !suppressContextInjection && !this.sessions.has(key) && !sessionRotated) {
|
|
2691
2806
|
const exchanges = this.lastExchanges.get(key) ?? [];
|
|
2692
2807
|
if (exchanges.length > 0) {
|
|
2693
2808
|
const historyLines = [];
|
|
@@ -2700,7 +2815,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2700
2815
|
}
|
|
2701
2816
|
}
|
|
2702
2817
|
// Inject context on first message after a daemon restart (session restored from disk)
|
|
2703
|
-
if (key && this.restoredSessions.has(key)) {
|
|
2818
|
+
if (key && !suppressContextInjection && this.restoredSessions.has(key)) {
|
|
2704
2819
|
const exchanges = this.lastExchanges.get(key) ?? [];
|
|
2705
2820
|
if (exchanges.length > 0) {
|
|
2706
2821
|
const olderSummary = this.buildOlderTurnsContext(key, exchanges);
|
|
@@ -2720,7 +2835,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2720
2835
|
this.restoredSessions.delete(key); // Only inject once per restored session
|
|
2721
2836
|
}
|
|
2722
2837
|
// Fresh session with no history — inject last conversation context
|
|
2723
|
-
if (key && !sessionRotated && !this.restoredSessions.has(key)) {
|
|
2838
|
+
if (key && !suppressContextInjection && !sessionRotated && !this.restoredSessions.has(key)) {
|
|
2724
2839
|
const exchanges = this.lastExchanges.get(key) ?? [];
|
|
2725
2840
|
if (exchanges.length === 0 && this.memoryStore) {
|
|
2726
2841
|
try {
|
|
@@ -2741,7 +2856,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2741
2856
|
}
|
|
2742
2857
|
}
|
|
2743
2858
|
// Time-gap awareness: let the agent know how long it's been
|
|
2744
|
-
if (key && this.sessionTimestamps.has(key)) {
|
|
2859
|
+
if (key && !suppressContextInjection && this.sessionTimestamps.has(key)) {
|
|
2745
2860
|
const gapMs = Date.now() - this.sessionTimestamps.get(key).getTime();
|
|
2746
2861
|
const gapHours = Math.round(gapMs / 3_600_000);
|
|
2747
2862
|
if (gapHours >= 8) {
|
|
@@ -2753,7 +2868,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2753
2868
|
// injectContext uses the base session key (e.g. discord:user:123) but
|
|
2754
2869
|
// chat may use a profile-suffixed key (discord:user:123:sales-agent),
|
|
2755
2870
|
// so also check any pending key that the current key starts with.
|
|
2756
|
-
if (key) {
|
|
2871
|
+
if (key && !suppressContextInjection) {
|
|
2757
2872
|
const allPending = [];
|
|
2758
2873
|
for (const [pendingKey, pending] of this.pendingContext) {
|
|
2759
2874
|
if (key === pendingKey || key.startsWith(pendingKey + ':')) {
|
|
@@ -2771,7 +2886,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2771
2886
|
}
|
|
2772
2887
|
}
|
|
2773
2888
|
// Inject stall nudge if the previous query for this session showed stall signals
|
|
2774
|
-
if (key && this.stallNudges.has(key)) {
|
|
2889
|
+
if (key && !suppressContextInjection && this.stallNudges.has(key)) {
|
|
2775
2890
|
const nudge = this.stallNudges.get(key);
|
|
2776
2891
|
this.stallNudges.delete(key);
|
|
2777
2892
|
effectivePrompt =
|
|
@@ -2780,16 +2895,6 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2780
2895
|
`Either take the action NOW using your tools, or tell the user exactly what is blocking you. ` +
|
|
2781
2896
|
`If a file can't be read, say so. If you're stuck, say so. Never stall silently.]\n\n${effectivePrompt}`;
|
|
2782
2897
|
}
|
|
2783
|
-
// ── Intent classification ─────────────────────────────────────
|
|
2784
|
-
// Classify intent before the main query to dynamically tune response
|
|
2785
|
-
// strategy, maxTurns, and effort level
|
|
2786
|
-
const recentExchanges = key ? this.lastExchanges.get(key) : undefined;
|
|
2787
|
-
const intent = classifyIntent(text, recentExchanges);
|
|
2788
|
-
const turnPolicy = decideTurnPolicy({
|
|
2789
|
-
text,
|
|
2790
|
-
intent,
|
|
2791
|
-
hasRecentContext: !!(recentExchanges?.length || (key && this.sessions.has(key))),
|
|
2792
|
-
});
|
|
2793
2898
|
logger.debug({
|
|
2794
2899
|
intent: intent.type,
|
|
2795
2900
|
confidence: intent.confidence,
|
|
@@ -2833,7 +2938,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2833
2938
|
if (key && !isApiError) {
|
|
2834
2939
|
this.exchangeCounts.set(key, (this.exchangeCounts.get(key) ?? 0) + 1);
|
|
2835
2940
|
this.sessionTimestamps.set(key, new Date());
|
|
2836
|
-
const history = this.lastExchanges.get(key) ?? [];
|
|
2941
|
+
const history = turnPolicy.suppressContextInjection ? [] : (this.lastExchanges.get(key) ?? []);
|
|
2837
2942
|
history.push({ user: text, assistant: responseText });
|
|
2838
2943
|
if (history.length > SESSION_EXCHANGE_HISTORY_SIZE) {
|
|
2839
2944
|
this.lastExchanges.set(key, history.slice(-SESSION_EXCHANGE_HISTORY_SIZE));
|
|
@@ -2872,12 +2977,16 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
2872
2977
|
logger.warn({ err, sessionKey: key }, 'Transcript save failed');
|
|
2873
2978
|
}
|
|
2874
2979
|
}
|
|
2875
|
-
// Fire background memory extraction (non-blocking)
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2980
|
+
// Fire background memory extraction (non-blocking). Skips are logged with
|
|
2981
|
+
// structured reasons so memory gaps are diagnosable without reading chats.
|
|
2982
|
+
if (responseText && !responseText.startsWith('Error:')) {
|
|
2983
|
+
const extractionDecision = this.assessMemoryExtraction(text, responseText, key, profile);
|
|
2984
|
+
if (extractionDecision.ok) {
|
|
2985
|
+
this.spawnMemoryExtraction(text, responseText, key, profile).catch(err => logger.debug({ err }, 'Memory extraction failed'));
|
|
2986
|
+
}
|
|
2987
|
+
else {
|
|
2988
|
+
this.logMemoryExtractionSkip(extractionDecision.reason, text, responseText, key, profile);
|
|
2989
|
+
}
|
|
2881
2990
|
}
|
|
2882
2991
|
// Score outcome-driven salience: for the chunks we retrieved this turn,
|
|
2883
2992
|
// check which actually showed up in the response and adjust their
|
|
@@ -3030,7 +3139,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3030
3139
|
sdkOptions.cwd = matchedProject.path;
|
|
3031
3140
|
}
|
|
3032
3141
|
// Set resume session if available
|
|
3033
|
-
if (sessionKey && this.sessions.has(sessionKey)) {
|
|
3142
|
+
if (sessionKey && this.sessions.has(sessionKey) && !effectiveTurnPolicy?.suppressSessionResume) {
|
|
3034
3143
|
sdkOptions.resume = this.sessions.get(sessionKey);
|
|
3035
3144
|
}
|
|
3036
3145
|
// Context window guard: estimate token usage and bail if too tight.
|
|
@@ -3253,7 +3362,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3253
3362
|
// Auth errors — throw so the gateway circuit breaker catches it
|
|
3254
3363
|
throw new Error(errorText);
|
|
3255
3364
|
}
|
|
3256
|
-
else if (
|
|
3365
|
+
else if (looksLikeContextThrashText(errorText)) {
|
|
3257
3366
|
// Autocompact thrashing — treat like the exception path
|
|
3258
3367
|
logger.warn({ sessionKey }, 'Autocompact thrashing (result error) — will rotate session');
|
|
3259
3368
|
// Capture mid-task state BEFORE rotating, so the retry
|
|
@@ -3293,6 +3402,25 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3293
3402
|
else if ('result' in result && result.result) {
|
|
3294
3403
|
// Success: use SDK result text if streaming didn't capture a substantive response
|
|
3295
3404
|
const sdkResult = result.result;
|
|
3405
|
+
if (looksLikeContextThrashText(sdkResult)) {
|
|
3406
|
+
logger.warn({ sessionKey }, 'Autocompact thrashing surfaced as SDK result text — rotating session');
|
|
3407
|
+
preRotationSnapshot = {
|
|
3408
|
+
toolCalls: stallGuard?.getToolCalls() ?? [],
|
|
3409
|
+
partialText: responseText.slice(-1000),
|
|
3410
|
+
};
|
|
3411
|
+
if (sessionKey) {
|
|
3412
|
+
try {
|
|
3413
|
+
this.compactContext(sessionKey);
|
|
3414
|
+
}
|
|
3415
|
+
catch { /* best-effort */ }
|
|
3416
|
+
this.sessions.delete(sessionKey);
|
|
3417
|
+
this.exchangeCounts.set(sessionKey, 0);
|
|
3418
|
+
this._compactedSessions.delete(sessionKey);
|
|
3419
|
+
}
|
|
3420
|
+
staleSession = true;
|
|
3421
|
+
contextRecovery = true;
|
|
3422
|
+
break;
|
|
3423
|
+
}
|
|
3296
3424
|
logger.info({ sessionKey, streamedLen: responseText.length, resultLen: sdkResult.length }, 'SDK result text available');
|
|
3297
3425
|
if (!responseText.trim()) {
|
|
3298
3426
|
responseText = sdkResult;
|
|
@@ -3354,7 +3482,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3354
3482
|
}
|
|
3355
3483
|
}
|
|
3356
3484
|
}
|
|
3357
|
-
else if (
|
|
3485
|
+
else if (looksLikeContextThrashText(e)) {
|
|
3358
3486
|
// SDK autocompact thrashing — tool outputs are too large for the context window.
|
|
3359
3487
|
// Rotate session and retry with a fresh context so the agent can continue.
|
|
3360
3488
|
logger.warn({ sessionKey }, 'Autocompact thrashing — rotating session and retrying');
|
|
@@ -3379,7 +3507,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3379
3507
|
responseText = '';
|
|
3380
3508
|
continue;
|
|
3381
3509
|
}
|
|
3382
|
-
responseText = responseText ||
|
|
3510
|
+
responseText = responseText || contextThrashRecoveryNotice();
|
|
3383
3511
|
}
|
|
3384
3512
|
else if (errStr.includes('prompt is too long') || errStr.includes('prompt too long') || errStr.includes('context_length')) {
|
|
3385
3513
|
responseText = responseText || ('The conversation got too large to process (tool responses filled the context window). ' +
|
|
@@ -3432,6 +3560,9 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3432
3560
|
}
|
|
3433
3561
|
continue;
|
|
3434
3562
|
}
|
|
3563
|
+
if (staleSession && contextRecovery && !responseText.trim()) {
|
|
3564
|
+
responseText = contextThrashRecoveryNotice();
|
|
3565
|
+
}
|
|
3435
3566
|
if (hitRateLimit && attempt < PersonalAssistant.RATE_LIMIT_MAX_RETRIES) {
|
|
3436
3567
|
const base = rateLimitRetryAfterMs
|
|
3437
3568
|
?? PersonalAssistant.RATE_LIMIT_BACKOFF[Math.min(attempt, PersonalAssistant.RATE_LIMIT_BACKOFF.length - 1)];
|
|
@@ -3446,6 +3577,27 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
3446
3577
|
if (hitRateLimit && !responseText) {
|
|
3447
3578
|
responseText = "I'm being rate limited right now. Give me a minute and try again.";
|
|
3448
3579
|
}
|
|
3580
|
+
if (looksLikeContextThrashText(responseText)) {
|
|
3581
|
+
logger.warn({ sessionKey }, 'Autocompact thrashing escaped into response text — rotating session before reply');
|
|
3582
|
+
if (sessionKey) {
|
|
3583
|
+
try {
|
|
3584
|
+
this.compactContext(sessionKey);
|
|
3585
|
+
}
|
|
3586
|
+
catch { /* best-effort */ }
|
|
3587
|
+
this.sessions.delete(sessionKey);
|
|
3588
|
+
this.exchangeCounts.set(sessionKey, 0);
|
|
3589
|
+
this._compactedSessions.delete(sessionKey);
|
|
3590
|
+
}
|
|
3591
|
+
if (attempt < PersonalAssistant.RATE_LIMIT_MAX_RETRIES) {
|
|
3592
|
+
prompt = buildContextRecoveredPrompt(prompt, {
|
|
3593
|
+
toolCalls: stallGuard?.getToolCalls() ?? [],
|
|
3594
|
+
partialText: '',
|
|
3595
|
+
});
|
|
3596
|
+
responseText = '';
|
|
3597
|
+
continue;
|
|
3598
|
+
}
|
|
3599
|
+
responseText = contextThrashRecoveryNotice();
|
|
3600
|
+
}
|
|
3449
3601
|
// ── Response guarantee ─────────────────────────────────────────
|
|
3450
3602
|
// The model often generates 30+ tool calls with minimal/no text. Ensure
|
|
3451
3603
|
// the user always gets a substantive response after real work is done.
|
|
@@ -4188,14 +4340,15 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4188
4340
|
catch { /* non-fatal */ }
|
|
4189
4341
|
}
|
|
4190
4342
|
// ── Auto-Memory Extraction ────────────────────────────────────────
|
|
4191
|
-
|
|
4192
|
-
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
if (
|
|
4197
|
-
return false;
|
|
4198
|
-
// Only skip pure greetings with no substance at all
|
|
4343
|
+
lastExtractionTimes = new Map();
|
|
4344
|
+
memoryExtractionKey(sessionKey, profile) {
|
|
4345
|
+
return `${profile?.slug ?? 'global'}:${sessionKey ?? 'no-session'}`;
|
|
4346
|
+
}
|
|
4347
|
+
assessMemoryExtraction(prompt, response, sessionKey, profile) {
|
|
4348
|
+
if (!this.memoryStore)
|
|
4349
|
+
return { ok: false, reason: 'no_memory_store' };
|
|
4350
|
+
// Only skip pure greetings with no substance at all. Check this before
|
|
4351
|
+
// length so "hey" is diagnosable as intent, not generic shortness.
|
|
4199
4352
|
const pureGreetings = [
|
|
4200
4353
|
'hello', 'hi', 'hey', 'thanks', 'thank you',
|
|
4201
4354
|
'ok', 'okay', 'sure', 'got it', 'sounds good',
|
|
@@ -4203,20 +4356,54 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4203
4356
|
];
|
|
4204
4357
|
const lower = prompt.toLowerCase().trim();
|
|
4205
4358
|
if (pureGreetings.some((g) => lower === g || lower === g + '!' || lower === g + '.')) {
|
|
4206
|
-
return false;
|
|
4359
|
+
return { ok: false, reason: 'pure_greeting' };
|
|
4360
|
+
}
|
|
4361
|
+
if (prompt.length < AUTO_MEMORY_MIN_LENGTH || response.length < 100) {
|
|
4362
|
+
return { ok: false, reason: 'too_short' };
|
|
4207
4363
|
}
|
|
4208
|
-
// Rate limit
|
|
4364
|
+
// Rate limit per session/agent. The old process-wide throttle meant one
|
|
4365
|
+
// active chat could suppress memory extraction for unrelated agents.
|
|
4209
4366
|
const now = Date.now();
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4367
|
+
const key = this.memoryExtractionKey(sessionKey, profile);
|
|
4368
|
+
const last = this.lastExtractionTimes.get(key) ?? 0;
|
|
4369
|
+
if (now - last < 45_000)
|
|
4370
|
+
return { ok: false, reason: 'rate_limited' };
|
|
4371
|
+
this.lastExtractionTimes.set(key, now);
|
|
4372
|
+
return { ok: true };
|
|
4373
|
+
}
|
|
4374
|
+
logMemoryExtractionSkip(reason, userMessage, assistantResponse, sessionKey, profile) {
|
|
4375
|
+
logger.debug({
|
|
4376
|
+
reason,
|
|
4377
|
+
sessionKey,
|
|
4378
|
+
agentSlug: profile?.slug,
|
|
4379
|
+
promptChars: userMessage.length,
|
|
4380
|
+
responseChars: assistantResponse.length,
|
|
4381
|
+
}, 'Auto-memory extraction skipped');
|
|
4382
|
+
if (!this.memoryStore)
|
|
4383
|
+
return;
|
|
4384
|
+
try {
|
|
4385
|
+
this.memoryStore.logExtraction({
|
|
4386
|
+
sessionKey: sessionKey ?? 'unknown',
|
|
4387
|
+
userMessage: userMessage.slice(0, 500),
|
|
4388
|
+
toolName: 'auto_memory_skip',
|
|
4389
|
+
toolInput: JSON.stringify({
|
|
4390
|
+
reason,
|
|
4391
|
+
promptChars: userMessage.length,
|
|
4392
|
+
responseChars: assistantResponse.length,
|
|
4393
|
+
}),
|
|
4394
|
+
extractedAt: new Date().toISOString(),
|
|
4395
|
+
status: `skipped:${reason}`,
|
|
4396
|
+
agentSlug: profile?.slug,
|
|
4397
|
+
});
|
|
4398
|
+
}
|
|
4399
|
+
catch { /* telemetry only */ }
|
|
4214
4400
|
}
|
|
4215
4401
|
async spawnMemoryExtraction(userMessage, assistantResponse, sessionKey, profile) {
|
|
4216
4402
|
// Guard: skip memory extraction if the user message looks like injection
|
|
4217
4403
|
const memScan = scanner.scan(userMessage);
|
|
4218
4404
|
if (memScan.verdict === 'block') {
|
|
4219
4405
|
logger.info('Skipping memory extraction — message was flagged as injection');
|
|
4406
|
+
this.logMemoryExtractionSkip('injection_blocked', userMessage, assistantResponse, sessionKey, profile);
|
|
4220
4407
|
return;
|
|
4221
4408
|
}
|
|
4222
4409
|
let currentMemory = '';
|
|
@@ -4855,7 +5042,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
4855
5042
|
if (cronGuard) {
|
|
4856
5043
|
const summary = cronGuard.getSummary();
|
|
4857
5044
|
const mc = summary.metacognition;
|
|
4858
|
-
if (mc.confidenceFinal === 'low' && deliverable && deliverable
|
|
5045
|
+
if (mc.confidenceFinal === 'low' && deliverable && !isAutonomousNothingOutput(deliverable)) {
|
|
4859
5046
|
try {
|
|
4860
5047
|
const escalationsFile = path.join(BASE_DIR, 'escalations.json');
|
|
4861
5048
|
const escalations = fs.existsSync(escalationsFile)
|
|
@@ -5386,6 +5573,21 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
|
|
|
5386
5573
|
lastPhaseOutputPreview: lastOutput.slice(0, 300),
|
|
5387
5574
|
});
|
|
5388
5575
|
logger.info(`Unleashed task ${jobName}: phase ${phase} complete (${(phaseDurationMs / 1000).toFixed(0)}s)`);
|
|
5576
|
+
// The job explicitly says there is nothing to report. Treat that as a
|
|
5577
|
+
// clean terminal state instead of resuming the same no-op phase until
|
|
5578
|
+
// the max-phase guard fires.
|
|
5579
|
+
if (isAutonomousNothingOutput(lastOutput)) {
|
|
5580
|
+
appendProgress({ event: 'completed_silent', phase });
|
|
5581
|
+
writeStatus({ jobName, status: 'completed', phase, startedAt, finishedAt: new Date().toISOString(), silent: true });
|
|
5582
|
+
logger.info(`Unleashed task ${jobName} completed silently at phase ${phase}`);
|
|
5583
|
+
if (this.onUnleashedComplete) {
|
|
5584
|
+
try {
|
|
5585
|
+
this.onUnleashedComplete(jobName, '__NOTHING__');
|
|
5586
|
+
}
|
|
5587
|
+
catch { /* non-fatal */ }
|
|
5588
|
+
}
|
|
5589
|
+
return '__NOTHING__';
|
|
5590
|
+
}
|
|
5389
5591
|
// Notify phase progress callback
|
|
5390
5592
|
if (this.onPhaseComplete) {
|
|
5391
5593
|
try {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ClementineJson } from '../config/clementine-json.js';
|
|
2
|
+
export type ProactivityMode = 'quiet' | 'balanced' | 'proactive' | 'operator';
|
|
3
|
+
export type ResponseStyle = 'concise' | 'balanced' | 'detailed';
|
|
4
|
+
export type ProgressVisibility = 'quiet' | 'normal' | 'detailed';
|
|
5
|
+
export type AutonomyMode = 'ask_first' | 'balanced' | 'act_when_safe';
|
|
6
|
+
export interface AssistantExperienceUpdate {
|
|
7
|
+
proactivity?: ProactivityMode;
|
|
8
|
+
responseStyle?: ResponseStyle;
|
|
9
|
+
progressVisibility?: ProgressVisibility;
|
|
10
|
+
autonomy?: AutonomyMode;
|
|
11
|
+
}
|
|
12
|
+
export type LocalTurnIntent = {
|
|
13
|
+
kind: 'none';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'ack';
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'greeting';
|
|
18
|
+
} | {
|
|
19
|
+
kind: 'stop';
|
|
20
|
+
} | {
|
|
21
|
+
kind: 'status';
|
|
22
|
+
} | {
|
|
23
|
+
kind: 'preference_update';
|
|
24
|
+
updates: AssistantExperienceUpdate;
|
|
25
|
+
summary: string;
|
|
26
|
+
};
|
|
27
|
+
export declare function isStopRequest(text: string): boolean;
|
|
28
|
+
export declare function isStatusRequest(text: string): boolean;
|
|
29
|
+
export declare function isTinyAcknowledgment(text: string): boolean;
|
|
30
|
+
export declare function detectLocalTurn(text: string): LocalTurnIntent;
|
|
31
|
+
export declare function applyAssistantExperienceUpdate(cfg: ClementineJson, updates: AssistantExperienceUpdate): ClementineJson;
|
|
32
|
+
//# sourceMappingURL=local-turn.d.ts.map
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { isStandaloneGreeting } from './turn-policy.js';
|
|
2
|
+
function normalize(text) {
|
|
3
|
+
return text
|
|
4
|
+
.trim()
|
|
5
|
+
.toLowerCase()
|
|
6
|
+
.replace(/[.!?]+$/g, '')
|
|
7
|
+
.replace(/\s+/g, ' ');
|
|
8
|
+
}
|
|
9
|
+
function wordCount(text) {
|
|
10
|
+
const t = text.trim();
|
|
11
|
+
return t ? t.split(/\s+/).length : 0;
|
|
12
|
+
}
|
|
13
|
+
export function isStopRequest(text) {
|
|
14
|
+
const n = normalize(text);
|
|
15
|
+
if (wordCount(n) > 5)
|
|
16
|
+
return false;
|
|
17
|
+
return /^(stop|cancel|abort|halt|pause|nevermind|never mind|wait stop|stop please|cancel that|stop that)$/.test(n);
|
|
18
|
+
}
|
|
19
|
+
export function isStatusRequest(text) {
|
|
20
|
+
const n = normalize(text);
|
|
21
|
+
if (wordCount(n) > 8)
|
|
22
|
+
return false;
|
|
23
|
+
return /^(status|task status|deep status|progress|what'?s happening|what'?s going on|what are you doing|are you working|anything running|what'?s running|background status|check status|where are we)$/.test(n);
|
|
24
|
+
}
|
|
25
|
+
export function isTinyAcknowledgment(text) {
|
|
26
|
+
const n = normalize(text);
|
|
27
|
+
if (wordCount(n) > 4)
|
|
28
|
+
return false;
|
|
29
|
+
return /^(thanks|thank you|thx|ty|nice|great|perfect|awesome|cool|ok|okay|sounds good|got it|makes sense|love it)$/.test(n);
|
|
30
|
+
}
|
|
31
|
+
function parseProactivity(text) {
|
|
32
|
+
if (/\b(operator mode|operator)\b/i.test(text))
|
|
33
|
+
return 'operator';
|
|
34
|
+
if (/\b(more proactive|be proactive|proactive mode|set proactivity to proactive)\b/i.test(text))
|
|
35
|
+
return 'proactive';
|
|
36
|
+
if (/\b(less proactive|quieter|quiet mode|be quiet|only urgent|do not interrupt)\b/i.test(text))
|
|
37
|
+
return 'quiet';
|
|
38
|
+
if (/\b(balanced proactivity|balanced mode|normal proactivity)\b/i.test(text))
|
|
39
|
+
return 'balanced';
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
function parseResponseStyle(text) {
|
|
43
|
+
if (/\b(be concise|keep it concise|shorter replies|brief replies|reply briefly|less verbose)\b/i.test(text))
|
|
44
|
+
return 'concise';
|
|
45
|
+
if (/\b(more detail|detailed replies|be detailed|explain more|more verbose)\b/i.test(text))
|
|
46
|
+
return 'detailed';
|
|
47
|
+
if (/\b(balanced replies|normal replies|balanced detail)\b/i.test(text))
|
|
48
|
+
return 'balanced';
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function parseProgressVisibility(text) {
|
|
52
|
+
if (/\b(show more progress|keep me posted|more updates|detailed progress|tell me what'?s happening)\b/i.test(text))
|
|
53
|
+
return 'detailed';
|
|
54
|
+
if (/\b(less progress|fewer updates|quiet progress|don'?t narrate)\b/i.test(text))
|
|
55
|
+
return 'quiet';
|
|
56
|
+
if (/\b(normal progress|balanced progress)\b/i.test(text))
|
|
57
|
+
return 'normal';
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
function parseAutonomy(text) {
|
|
61
|
+
if (/\b(ask first|ask me first|ask before acting|do not act without asking)\b/i.test(text))
|
|
62
|
+
return 'ask_first';
|
|
63
|
+
if (/\b(act when safe|more autonomous|use your judgment|handle it when safe)\b/i.test(text))
|
|
64
|
+
return 'act_when_safe';
|
|
65
|
+
if (/\b(balanced autonomy|normal autonomy)\b/i.test(text))
|
|
66
|
+
return 'balanced';
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
export function detectLocalTurn(text) {
|
|
70
|
+
if (isStopRequest(text))
|
|
71
|
+
return { kind: 'stop' };
|
|
72
|
+
if (isStatusRequest(text))
|
|
73
|
+
return { kind: 'status' };
|
|
74
|
+
if (isStandaloneGreeting(text))
|
|
75
|
+
return { kind: 'greeting' };
|
|
76
|
+
if (isTinyAcknowledgment(text))
|
|
77
|
+
return { kind: 'ack' };
|
|
78
|
+
const updates = {};
|
|
79
|
+
const proactivity = parseProactivity(text);
|
|
80
|
+
const responseStyle = parseResponseStyle(text);
|
|
81
|
+
const progressVisibility = parseProgressVisibility(text);
|
|
82
|
+
const autonomy = parseAutonomy(text);
|
|
83
|
+
if (proactivity)
|
|
84
|
+
updates.proactivity = proactivity;
|
|
85
|
+
if (responseStyle)
|
|
86
|
+
updates.responseStyle = responseStyle;
|
|
87
|
+
if (progressVisibility)
|
|
88
|
+
updates.progressVisibility = progressVisibility;
|
|
89
|
+
if (autonomy)
|
|
90
|
+
updates.autonomy = autonomy;
|
|
91
|
+
const entries = Object.entries(updates);
|
|
92
|
+
if (entries.length === 0)
|
|
93
|
+
return { kind: 'none' };
|
|
94
|
+
const summary = entries.map(([k, v]) => `${k}: ${v}`).join(', ');
|
|
95
|
+
return { kind: 'preference_update', updates, summary };
|
|
96
|
+
}
|
|
97
|
+
export function applyAssistantExperienceUpdate(cfg, updates) {
|
|
98
|
+
return {
|
|
99
|
+
...cfg,
|
|
100
|
+
schemaVersion: 1,
|
|
101
|
+
assistant: {
|
|
102
|
+
...(cfg.assistant ?? {}),
|
|
103
|
+
...updates,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=local-turn.js.map
|
|
@@ -76,6 +76,7 @@ const PATTERNS = [
|
|
|
76
76
|
recipe: () => ({
|
|
77
77
|
category: 'safe-cron-config',
|
|
78
78
|
description: 'Context window blowing up mid-run. Switching to unleashed mode so each phase starts with a fresh context.',
|
|
79
|
+
fields: ['mode', 'max_hours'],
|
|
79
80
|
apply: (job) => {
|
|
80
81
|
let changed = false;
|
|
81
82
|
if (job.mode !== 'unleashed') {
|