titan-agent 5.4.2 → 5.5.6
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/README.md +1 -1
- package/dist/agent/agent.js +9 -5
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/agentLoop.js +7 -3
- package/dist/agent/agentLoop.js.map +1 -1
- package/dist/agent/checkpoint.js +2 -2
- package/dist/agent/checkpoint.js.map +1 -1
- package/dist/agent/commandPost.js +3 -3
- package/dist/agent/commandPost.js.map +1 -1
- package/dist/agent/goalProposer.js +2 -2
- package/dist/agent/goalProposer.js.map +1 -1
- package/dist/agent/goals.js +3 -3
- package/dist/agent/goals.js.map +1 -1
- package/dist/agent/peerAdvise.js +1 -1
- package/dist/agent/peerAdvise.js.map +1 -1
- package/dist/agent/planner.js +4 -4
- package/dist/agent/planner.js.map +1 -1
- package/dist/agent/userProfile.js +2 -2
- package/dist/agent/userProfile.js.map +1 -1
- package/dist/cli/doctor.js +33 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/onboard.js +4 -4
- package/dist/cli/onboard.js.map +1 -1
- package/dist/config/config.js +3 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.js +8 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/gateway/routes/adminRouter.js +500 -0
- package/dist/gateway/routes/adminRouter.js.map +1 -0
- package/dist/gateway/routes/agents.js +231 -0
- package/dist/gateway/routes/agents.js.map +1 -0
- package/dist/gateway/routes/agentsRouter.js +32 -0
- package/dist/gateway/routes/agentsRouter.js.map +1 -0
- package/dist/gateway/routes/checkpoints.js +41 -0
- package/dist/gateway/routes/checkpoints.js.map +1 -0
- package/dist/gateway/routes/commandPost.js +755 -0
- package/dist/gateway/routes/commandPost.js.map +1 -0
- package/dist/gateway/routes/companies.js +166 -0
- package/dist/gateway/routes/companies.js.map +1 -0
- package/dist/gateway/routes/files.js +295 -0
- package/dist/gateway/routes/files.js.map +1 -0
- package/dist/gateway/routes/hardwareRouter.js +151 -0
- package/dist/gateway/routes/hardwareRouter.js.map +1 -0
- package/dist/gateway/routes/mcpRouter.js +88 -0
- package/dist/gateway/routes/mcpRouter.js.map +1 -0
- package/dist/gateway/routes/mesh.js +464 -0
- package/dist/gateway/routes/mesh.js.map +1 -0
- package/dist/gateway/routes/metricsRouter.js +131 -0
- package/dist/gateway/routes/metricsRouter.js.map +1 -0
- package/dist/gateway/routes/organism.js +82 -0
- package/dist/gateway/routes/organism.js.map +1 -0
- package/dist/gateway/routes/paperclip.js +101 -0
- package/dist/gateway/routes/paperclip.js.map +1 -0
- package/dist/gateway/routes/sessions.js +227 -0
- package/dist/gateway/routes/sessions.js.map +1 -0
- package/dist/gateway/routes/skills.js +295 -0
- package/dist/gateway/routes/skills.js.map +1 -0
- package/dist/gateway/routes/socialRouter.js +145 -0
- package/dist/gateway/routes/socialRouter.js.map +1 -0
- package/dist/gateway/routes/systemRouter.js +220 -0
- package/dist/gateway/routes/systemRouter.js.map +1 -0
- package/dist/gateway/routes/teamsRecipes.js +297 -0
- package/dist/gateway/routes/teamsRecipes.js.map +1 -0
- package/dist/gateway/routes/tests.js +401 -0
- package/dist/gateway/routes/tests.js.map +1 -0
- package/dist/gateway/routes/traces.js +33 -0
- package/dist/gateway/routes/traces.js.map +1 -0
- package/dist/gateway/routes/voiceRouter.js +770 -0
- package/dist/gateway/routes/voiceRouter.js.map +1 -0
- package/dist/gateway/routes/watchRouter.js +131 -0
- package/dist/gateway/routes/watchRouter.js.map +1 -0
- package/dist/gateway/server.js +1179 -7379
- package/dist/gateway/server.js.map +1 -1
- package/dist/mcp/registry.js +2 -2
- package/dist/mcp/registry.js.map +1 -1
- package/dist/memory/episodic.js +2 -2
- package/dist/memory/episodic.js.map +1 -1
- package/dist/memory/learning.js +3 -3
- package/dist/memory/learning.js.map +1 -1
- package/dist/memory/memory.js +3 -3
- package/dist/memory/memory.js.map +1 -1
- package/dist/organism/drives.js +2 -2
- package/dist/organism/drives.js.map +1 -1
- package/dist/providers/errorTaxonomy.js +13 -0
- package/dist/providers/errorTaxonomy.js.map +1 -1
- package/dist/providers/ollama.js +3 -1
- package/dist/providers/ollama.js.map +1 -1
- package/dist/providers/openai_compat.js +4 -3
- package/dist/providers/openai_compat.js.map +1 -1
- package/dist/providers/router.js +13 -0
- package/dist/providers/router.js.map +1 -1
- package/dist/safety/fixOscillation.js +15 -0
- package/dist/safety/fixOscillation.js.map +1 -1
- package/dist/safety/killSwitch.js +2 -2
- package/dist/safety/killSwitch.js.map +1 -1
- package/dist/safety/selfRepair.js +7 -3
- package/dist/safety/selfRepair.js.map +1 -1
- package/dist/skills/builtin/agent_debate.js +2 -2
- package/dist/skills/builtin/agent_debate.js.map +1 -1
- package/dist/skills/builtin/apply_patch.js +3 -3
- package/dist/skills/builtin/apply_patch.js.map +1 -1
- package/dist/skills/builtin/shell.js +2 -2
- package/dist/skills/builtin/shell.js.map +1 -1
- package/dist/skills/builtin/voice_control.js +49 -0
- package/dist/skills/builtin/voice_control.js.map +1 -0
- package/dist/skills/builtin/widget_gallery.js +6 -1
- package/dist/skills/builtin/widget_gallery.js.map +1 -1
- package/dist/skills/registry.js +15 -4
- package/dist/skills/registry.js.map +1 -1
- package/dist/storage/JsonStorage.js +4 -4
- package/dist/storage/JsonStorage.js.map +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/constants.js.map +1 -1
- package/dist/utils/helpers.js +3 -1
- package/dist/utils/helpers.js.map +1 -1
- package/dist/utils/lifecycle.js +86 -0
- package/dist/utils/lifecycle.js.map +1 -0
- package/dist/voice/bridge.js +136 -0
- package/dist/voice/bridge.js.map +1 -0
- package/docs/COO-MASTER-PLAN-2026-05-02.md +474 -0
- package/docs/HANDOFF/2026-04-29.md +141 -0
- package/docs/HANDOFF-2026-04-30.md +144 -0
- package/docs/HANDOFF-2026-05-03.md +114 -0
- package/docs/adr/2026-04-29-widget-pipeline-traceability.md +49 -0
- package/docs/agent-memory/README.md +45 -0
- package/docs/agent-memory/commands.md +100 -0
- package/docs/agent-memory/context-tree.md +101 -0
- package/docs/agent-memory/current-state.md +54 -0
- package/docs/agent-memory/decisions.md +78 -0
- package/docs/agent-memory/known-issues.md +76 -0
- package/docs/agent-memory/reflections.md +52 -0
- package/docs/agent-memory/skills-candidates.md +80 -0
- package/docs/superpowers/plans/2026-04-29-comprehensive-audit.md +256 -0
- package/docs/superpowers/plans/2026-04-29-comprehensive-test-plan.md +396 -0
- package/docs/superpowers/plans/2026-04-29-fix-all-prs.md +251 -0
- package/docs/superpowers/plans/2026-04-29-gitnexus-gap-remediation.md +969 -0
- package/package.json +5 -2
- package/ui/dist/assets/{AuditPanel-CM6Wg9hO.js → AuditPanel-VzSndmDN.js} +2 -2
- package/ui/dist/assets/{AutonomyPanel-CESx3ANg.js → AutonomyPanel-BiFouzAV.js} +2 -2
- package/ui/dist/assets/AutopilotPanel-fjOfM668.js +1 -0
- package/ui/dist/assets/{AutoresearchPanel-DR47NqT5.js → AutoresearchPanel-CVCxzAH3.js} +2 -2
- package/ui/dist/assets/BackupPanel-CHVTG--q.js +1 -0
- package/ui/dist/assets/{BrowserPanel-C15x9bLn.js → BrowserPanel-D5mvMKFU.js} +2 -2
- package/ui/dist/assets/CPActivity-B12mt35m.js +1 -0
- package/ui/dist/assets/CPAgentDetail-DsdShc-1.js +1 -0
- package/ui/dist/assets/CPAgents-j_7C-oQV.js +1 -0
- package/ui/dist/assets/CPApprovals-BShKSX9X.js +1 -0
- package/ui/dist/assets/CPCosts-CKPlhBDs.js +1 -0
- package/ui/dist/assets/CPDashboard-11c0nkxK.js +1 -0
- package/ui/dist/assets/CPFiles-BhLEOnXy.js +1 -0
- package/ui/dist/assets/CPGoals-Bi3t1b2P.js +1 -0
- package/ui/dist/assets/CPInbox-Bbr7khp6.js +11 -0
- package/ui/dist/assets/CPIssueDetail-DSdgNK8r.js +1 -0
- package/ui/dist/assets/CPIssues-DDEVKhX6.js +1 -0
- package/ui/dist/assets/CPLayout-DgPOfyGv.js +17 -0
- package/ui/dist/assets/CPOrg-Df73RrRJ.js +8 -0
- package/ui/dist/assets/CPRuns-ByioAz8w.js +1 -0
- package/ui/dist/assets/{CPSocial-nb-j7sOE.js → CPSocial-Dlnr_w1X.js} +2 -2
- package/ui/dist/assets/ChannelsPanel-DQjQCTK5.js +1 -0
- package/ui/dist/assets/CheckpointsPanel-C4vKjlAJ.js +1 -0
- package/ui/dist/assets/CommandPostHub-C9pp5Giq.js +24 -0
- package/ui/dist/assets/CronPanel-C6bzUfrD.js +1 -0
- package/ui/dist/assets/DaemonPanel-BA5Tb_UO.js +1 -0
- package/ui/dist/assets/{DataTable-B2Ma8hfi.js → DataTable-CH7IYJJh.js} +1 -1
- package/ui/dist/assets/{EmptyState-CcKyk5Yn.js → EmptyState-jU6yNDnF.js} +1 -1
- package/ui/dist/assets/{EvalHarnessPanel-BqtMc1ZM.js → EvalHarnessPanel-DnYqredY.js} +2 -2
- package/ui/dist/assets/EvalPanel-ChO7CD1r.js +1 -0
- package/ui/dist/assets/{FilesPanel-3QKvrWPo.js → FilesPanel-CaUkv2is.js} +2 -2
- package/ui/dist/assets/FleetPanel-DC_5uj0N.js +1 -0
- package/ui/dist/assets/{HomelabPanel-DhrjTX9m.js → HomelabPanel-CE5PGRpL.js} +2 -2
- package/ui/dist/assets/InfraView-C-uSlvb9.js +2 -0
- package/ui/dist/assets/InlineEditableField-BMQjiE6-.js +1 -0
- package/ui/dist/assets/Input-Bu_b3qmY.js +1 -0
- package/ui/dist/assets/IntegrationsPanel-DsYpAq43.js +1 -0
- package/ui/dist/assets/IntelligenceView-DUdIO1K7.js +2 -0
- package/ui/dist/assets/LearningPanel-UpQZC-mA.js +1 -0
- package/ui/dist/assets/LogsPanel-ClXJ4fcr.js +1 -0
- package/ui/dist/assets/McpPanel-JKgtIERQ.js +1 -0
- package/ui/dist/assets/{MemoryGraphPanel-Bzvjmzvk.js → MemoryGraphPanel-Bo2OrvA6.js} +2 -2
- package/ui/dist/assets/MemoryWikiPanel-BqJ1AmYm.js +11 -0
- package/ui/dist/assets/{MeshPanel-C3LJSlht.js → MeshPanel-BJVGYvwk.js} +2 -2
- package/ui/dist/assets/Modal-CAAooiZU.js +1 -0
- package/ui/dist/assets/NvidiaPanel-BtCg3G4w.js +1 -0
- package/ui/dist/assets/OrganismPanel-DgrTTzcF.js +1 -0
- package/ui/dist/assets/OverviewPanel-rVav1Hox.js +1 -0
- package/ui/dist/assets/{PageHeader-BimceqQo.js → PageHeader-CnZtP8ek.js} +1 -1
- package/ui/dist/assets/PaperclipPanel-C-FKdhiF.js +1 -0
- package/ui/dist/assets/{PersonasPanel-L1j78p6H.js → PersonasPanel-BmlxokfB.js} +1 -1
- package/ui/dist/assets/RecipesPanel-BNKKChis.js +1 -0
- package/ui/dist/assets/SecurityPanel-I7JRHiNy.js +1 -0
- package/ui/dist/assets/SelfImprovePanel-u9h0Lt3p.js +1 -0
- package/ui/dist/assets/{SelfProposalsPanel-lNmiDThB.js → SelfProposalsPanel-DKl9iBjM.js} +2 -2
- package/ui/dist/assets/SessionsPanel-BhRiWI_g.js +1 -0
- package/ui/dist/assets/{SessionsTab-JQbltWww.js → SessionsTab-Bk08wyeY.js} +1 -1
- package/ui/dist/assets/SettingsPanel-haLfmG2k.js +1 -0
- package/ui/dist/assets/SettingsView--gi3fxI8.js +2 -0
- package/ui/dist/assets/{SkeletonLoader-atQtpcF5.js → SkeletonLoader-B5v09EF_.js} +1 -1
- package/ui/dist/assets/{SkillsPanel-DlFs2ih7.js → SkillsPanel-BlAHFLcQ.js} +1 -1
- package/ui/dist/assets/SomaView-CExtS3zw.js +5 -0
- package/ui/dist/assets/{StatCard-DciE_Iqc.js → StatCard-BIsyMybM.js} +1 -1
- package/ui/dist/assets/{StatusBadge-BtfSPoW2.js → StatusBadge-D5nU7El8.js} +1 -1
- package/ui/dist/assets/Tabs-BBYZrBI8.js +1 -0
- package/ui/dist/assets/TeamsPanel-LPXJg823.js +1 -0
- package/ui/dist/assets/TelemetryPanel-EqpRBmOI.js +1 -0
- package/ui/dist/assets/TitanCanvas-BCbWnLMd.js +985 -0
- package/ui/dist/assets/ToolsView-CeP0Zz-N.js +2 -0
- package/ui/dist/assets/{Tooltip-70UK0E2I.js → Tooltip-BSO2XVpF.js} +1 -1
- package/ui/dist/assets/TraceViewer-BKI7o5B0.js +1 -0
- package/ui/dist/assets/TrainingPanel-c-RhjdE1.js +1 -0
- package/ui/dist/assets/VoiceOverlay-D-gc58b0.js +27 -0
- package/ui/dist/assets/VramPanel-C6xc7zgd.js +1 -0
- package/ui/dist/assets/{WatchView-C-sGFpVy.js → WatchView-dqBVCVH0.js} +1 -1
- package/ui/dist/assets/WorkTab-CBoLNrTM.js +1 -0
- package/ui/dist/assets/{WorkflowsPanel-CvgQU1xI.js → WorkflowsPanel-BAnSTOYe.js} +2 -2
- package/ui/dist/assets/approvalHeadline-DB9SgR-9.js +1 -0
- package/ui/dist/assets/{arrow-left-DwqHtJiU.js → arrow-left-5chqas7J.js} +1 -1
- package/ui/dist/assets/briefcase-D4vLzudp.js +6 -0
- package/ui/dist/assets/{chart-column-BtNO6sRy.js → chart-column-CdFlBpoP.js} +1 -1
- package/ui/dist/assets/check-Bpm1IONe.js +6 -0
- package/ui/dist/assets/chevron-down-D7OLjvuD.js +6 -0
- package/ui/dist/assets/chevron-right-aQEw2mUW.js +6 -0
- package/ui/dist/assets/chevron-up-C5g6pEj8.js +6 -0
- package/ui/dist/assets/{circle-check-big-DZRE_MbN.js → circle-check-big-fPhEdP88.js} +1 -1
- package/ui/dist/assets/clock-CTsgP_Sn.js +6 -0
- package/ui/dist/assets/{dollar-sign-aVG3a5eL.js → dollar-sign-CudFVYFc.js} +1 -1
- package/ui/dist/assets/{download-BxiWJU4G.js → download-DZRxDn67.js} +1 -1
- package/ui/dist/assets/external-link-BZ0y_Ahx.js +6 -0
- package/ui/dist/assets/{eye-off-CkgfFYhm.js → eye-off-BmJF0YYx.js} +1 -1
- package/ui/dist/assets/folder-DA43TRCm.js +11 -0
- package/ui/dist/assets/{funnel-PkLdxKyC.js → funnel-J3mULzrz.js} +1 -1
- package/ui/dist/assets/{git-branch-BM-Gw95X.js → git-branch-oHibJqDq.js} +1 -1
- package/ui/dist/assets/{index-D0RJ8701.css → index-BR0vfkIi.css} +1 -1
- package/ui/dist/assets/{index-CahJbWSR.js → index-DzwowwSI.js} +20 -20
- package/ui/dist/assets/{layers-BuGf4FIJ.js → layers-DsyEyu7z.js} +1 -1
- package/ui/dist/assets/{legacy-CR6o4t-y.js → legacy-8ITl64sV.js} +1 -1
- package/ui/dist/assets/{lightbulb-n8gc_XAL.js → lightbulb-C54Ske-p.js} +1 -1
- package/ui/dist/assets/list-todo-Cnd4rdoK.js +6 -0
- package/ui/dist/assets/loader-circle-1YOBsoQp.js +6 -0
- package/ui/dist/assets/network-DbGDAdrn.js +6 -0
- package/ui/dist/assets/{pause-DCV52koX.js → pause-CYhO_uQo.js} +1 -1
- package/ui/dist/assets/{play-CcJ9BnCh.js → play-DVY9c5Ck.js} +1 -1
- package/ui/dist/assets/{plug-CfWBXfCl.js → plug-BcXjlPUL.js} +1 -1
- package/ui/dist/assets/plus-Csu2v9GN.js +6 -0
- package/ui/dist/assets/{proxy-CzZDfLmm.js → proxy-DxS2_9D7.js} +1 -1
- package/ui/dist/assets/rotate-ccw-Co-_W04j.js +6 -0
- package/ui/dist/assets/save-Btx-kpoW.js +6 -0
- package/ui/dist/assets/search-0hXTwEZR.js +6 -0
- package/ui/dist/assets/send-TEpapzQR.js +6 -0
- package/ui/dist/assets/shield-check-DjBJXZUr.js +6 -0
- package/ui/dist/assets/{square-DJpUhlxi.js → square-OweUvjP-.js} +1 -1
- package/ui/dist/assets/{target-DWcmM_9m.js → target-BRW80Xer.js} +1 -1
- package/ui/dist/assets/terminal-BtiqJ628.js +16 -0
- package/ui/dist/assets/{toggle-right-YusFQ69L.js → toggle-right-CKtSrl28.js} +1 -1
- package/ui/dist/assets/{trash-2-CK7yQ55V.js → trash-2-DgWrHVax.js} +1 -1
- package/ui/dist/assets/{trending-up-DGjFyubC.js → trending-up-MpIrE4j6.js} +1 -1
- package/ui/dist/assets/{trophy-uQv_NgDB.js → trophy-CECuZNhX.js} +1 -1
- package/ui/dist/assets/users-dZgv4ePG.js +16 -0
- package/ui/dist/assets/wrench-CDz3xYve.js +11 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/AutopilotPanel-DtEet1hJ.js +0 -1
- package/ui/dist/assets/BackupPanel-BGP8p3l3.js +0 -1
- package/ui/dist/assets/CPAgents-DYUtPzSq.js +0 -1
- package/ui/dist/assets/CPDashboard-Bf0-SyCh.js +0 -6
- package/ui/dist/assets/CPFiles-CxgxjQcO.js +0 -1
- package/ui/dist/assets/CPGoals-BsmCMTvT.js +0 -1
- package/ui/dist/assets/CPInbox-tMSbmQ9H.js +0 -11
- package/ui/dist/assets/ChannelsPanel-DP5C2OKd.js +0 -1
- package/ui/dist/assets/CheckpointsPanel-DlranVLZ.js +0 -1
- package/ui/dist/assets/CommandPostHub-BgxIa4Ev.js +0 -29
- package/ui/dist/assets/CronPanel-LoT5yKwJ.js +0 -1
- package/ui/dist/assets/DaemonPanel-DBGMqaE_.js +0 -1
- package/ui/dist/assets/EvalPanel-Bc33j0pN.js +0 -1
- package/ui/dist/assets/FleetPanel-CSsXuQYj.js +0 -1
- package/ui/dist/assets/InfraView-CR6HyrL6.js +0 -2
- package/ui/dist/assets/InlineEditableField-CnvF-yFR.js +0 -1
- package/ui/dist/assets/Input-GTHp2Rkr.js +0 -1
- package/ui/dist/assets/IntegrationsPanel-CymCRE3T.js +0 -1
- package/ui/dist/assets/IntelligenceView-C1IHxJRC.js +0 -2
- package/ui/dist/assets/LearningPanel-DOCES3lH.js +0 -1
- package/ui/dist/assets/LogsPanel-BLnAqEaZ.js +0 -1
- package/ui/dist/assets/McpPanel-ChUzmr3z.js +0 -1
- package/ui/dist/assets/MemoryWikiPanel-Dwk3Aqwd.js +0 -11
- package/ui/dist/assets/NvidiaPanel-CeZK_-CV.js +0 -1
- package/ui/dist/assets/OrganismPanel-BB6YOiQV.js +0 -1
- package/ui/dist/assets/OverviewPanel-BmtBhQnv.js +0 -1
- package/ui/dist/assets/PaperclipPanel-C-brgwA3.js +0 -1
- package/ui/dist/assets/RecipesPanel-34lCfynJ.js +0 -1
- package/ui/dist/assets/SecurityPanel-CBTPWLj6.js +0 -1
- package/ui/dist/assets/SelfImprovePanel-BrPbFHhG.js +0 -1
- package/ui/dist/assets/SessionsPanel-DAEYIn83.js +0 -1
- package/ui/dist/assets/SettingsPanel-CzRROAYQ.js +0 -1
- package/ui/dist/assets/SettingsView-CN7ii2uw.js +0 -2
- package/ui/dist/assets/SomaView-Ba642Oqb.js +0 -5
- package/ui/dist/assets/TeamsPanel-DKQ5z2Qe.js +0 -1
- package/ui/dist/assets/TelemetryPanel-B6KAc55Q.js +0 -1
- package/ui/dist/assets/TitanCanvas-C-s0A-lv.js +0 -1092
- package/ui/dist/assets/ToolsView-Dei0KMP0.js +0 -2
- package/ui/dist/assets/TraceViewer-BniolyBx.js +0 -1
- package/ui/dist/assets/TrainingPanel-Bz4CTPGW.js +0 -1
- package/ui/dist/assets/VoiceOverlay-CmNCrLcd.js +0 -37
- package/ui/dist/assets/VramPanel-Xh_OtRDR.js +0 -1
- package/ui/dist/assets/WorkTab-BjLNmgIK.js +0 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { TITAN_HOME } from "../utils/constants.js";
|
|
5
|
-
import {
|
|
5
|
+
import { mkdirIfNotExists } from "../utils/helpers.js";
|
|
6
6
|
import { loadConfig } from "../config/config.js";
|
|
7
7
|
import { auxChat, resolveAuxiliaryModel } from "../providers/auxiliary.js";
|
|
8
8
|
import { applyOutputGuardrails } from "./outputGuardrails.js";
|
|
@@ -25,7 +25,7 @@ function loadRateState() {
|
|
|
25
25
|
}
|
|
26
26
|
function saveRateState(state) {
|
|
27
27
|
try {
|
|
28
|
-
|
|
28
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
29
29
|
writeFileSync(RATE_STATE_PATH, JSON.stringify(state, null, 2), "utf-8");
|
|
30
30
|
} catch (err) {
|
|
31
31
|
logger.warn(COMPONENT, `Failed to save rate state: ${err.message}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/goalProposer.ts"],"sourcesContent":["/**\n * TITAN — Self-Directed Goal Proposer\n *\n * Runs during the nightly dreaming cycle (Phase 4: Dream) after memory\n * consolidation has happened. Each registered agent examines recent activity,\n * open issues, failed subtasks, and consolidation findings, then proposes\n * 0-3 new goals it thinks would be worth doing.\n *\n * Proposals go into the Command Post approval queue as `type: 'goal_proposal'`.\n * A human (or designated approver agent) accepts or rejects them. On accept,\n * the existing createGoal() pipeline fires and Initiative picks up the work.\n *\n * Opt-in via config.agent.autoProposeGoals (default false).\n * Rate-limited per-agent via config.agent.proposalRateLimitPerDay.\n */\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport { loadConfig } from '../config/config.js';\nimport { chat } from '../providers/router.js';\nimport { auxChat, resolveAuxiliaryModel } from '../providers/auxiliary.js';\nimport { applyOutputGuardrails } from './outputGuardrails.js';\nimport { getActivity, requestGoalProposalApproval, type CPApproval } from './commandPost.js';\nimport { listGoals } from './goals.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'GoalProposer';\nconst RATE_STATE_PATH = join(TITAN_HOME, 'goal-proposer-state.json');\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface ProposedGoal {\n title: string;\n description: string;\n rationale: string;\n priority?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n}\n\nexport interface GoalProposerContext {\n /** Recent activity feed entries — max last 50. */\n recentActivity?: string[];\n /** Titles of currently active goals so proposals don't duplicate. */\n activeGoals?: string[];\n /** Titles of recently failed subtasks worth retrying or reframing. */\n failedSubtasks?: string[];\n /** Free-form notes from the dreaming consolidation log. */\n consolidationNotes?: string;\n /**\n * v4.9.0-local.4: extra prompt blocks (episodic recall, experiment\n * history, identity) pre-loaded by the caller. Keeps buildPrompt\n * synchronous.\n */\n extraBlocks?: string[];\n}\n\ninterface RateLimitState {\n /** Map of agentId → ISO timestamps of proposals filed in the last 24h. */\n proposalsByAgent: Record<string, string[]>;\n}\n\n// ── Rate Limiting ────────────────────────────────────────────────\n\nfunction loadRateState(): RateLimitState {\n if (!existsSync(RATE_STATE_PATH)) return { proposalsByAgent: {} };\n try {\n const raw = readFileSync(RATE_STATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<RateLimitState>;\n // v4.9.0-local.6: defensive normalize. A prior bug (+ the goal-\n // reset script) can write `{}` to this file, losing the\n // `proposalsByAgent` key. Without this, every\n // `state.proposalsByAgent[agentId]` access crashes with\n // \"Cannot read properties of undefined (reading '<agent>')\"\n // and proposals silently fail for hours.\n return {\n proposalsByAgent: parsed?.proposalsByAgent ?? {},\n };\n } catch {\n return { proposalsByAgent: {} };\n }\n}\n\nfunction saveRateState(state: RateLimitState): void {\n try {\n ensureDir(TITAN_HOME);\n writeFileSync(RATE_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n logger.warn(COMPONENT, `Failed to save rate state: ${(err as Error).message}`);\n }\n}\n\n/** Returns how many slots the agent has remaining in the current 24h window. */\nexport function remainingSlots(agentId: string, limitPerDay: number): number {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const stamps = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n return Math.max(0, limitPerDay - stamps.length);\n}\n\nfunction recordProposal(agentId: string): void {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const existing = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n existing.push(new Date().toISOString());\n state.proposalsByAgent[agentId] = existing;\n saveRateState(state);\n}\n\n// ── Prompt ───────────────────────────────────────────────────────\n\nfunction buildPrompt(agentId: string, slotsLeft: number, ctx: GoalProposerContext): string {\n const sections: string[] = [];\n sections.push(`You are agent \"${agentId}\". You have been given a quiet window to reflect on the system's current state and propose new goals that would meaningfully help.`);\n sections.push(`You may propose 0 to ${slotsLeft} goals. It is OK — often preferable — to propose zero if nothing is clearly worth doing.`);\n sections.push('');\n\n if (ctx.activeGoals && ctx.activeGoals.length) {\n sections.push('## Currently Active Goals (do not duplicate)');\n for (const title of ctx.activeGoals.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.recentActivity && ctx.recentActivity.length) {\n sections.push('## Recent Activity (last ~50 events)');\n for (const line of ctx.recentActivity.slice(-50)) sections.push(`- ${line}`);\n sections.push('');\n }\n if (ctx.failedSubtasks && ctx.failedSubtasks.length) {\n sections.push('## Recently Failed Subtasks');\n for (const title of ctx.failedSubtasks.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.consolidationNotes) {\n sections.push('## Memory Consolidation Notes');\n sections.push(ctx.consolidationNotes);\n sections.push('');\n }\n\n // v4.9.0-local.4: extra memory blocks (episodic, experiments,\n // identity) pre-loaded by the async caller and passed through ctx.\n // Keeps buildPrompt synchronous while still giving the proposer\n // full context of what TITAN has already done + who it is.\n if (ctx.extraBlocks && ctx.extraBlocks.length > 0) {\n for (const block of ctx.extraBlocks) {\n if (block && block.trim()) {\n sections.push(block);\n sections.push('');\n }\n }\n }\n\n sections.push('## Output Format');\n sections.push('Return ONLY a JSON array (no prose, no markdown fences). Each element:');\n sections.push('```');\n sections.push('{');\n sections.push(' \"title\": \"short imperative, under 80 chars\",');\n sections.push(' \"description\": \"what success looks like, 1-3 sentences\",');\n sections.push(' \"rationale\": \"why this goal is worth doing NOW\",');\n sections.push(' \"priority\": 1-5 (1 = highest),');\n sections.push(' \"tags\": [\"optional\", \"labels\"],');\n sections.push(' \"subtasks\": [{\"title\": \"...\", \"description\": \"...\"}]');\n sections.push('}');\n sections.push('```');\n sections.push('If nothing is worth proposing, return `[]`. Never return more than the slot limit.');\n\n return sections.join('\\n');\n}\n\n/** JSON schema passed to Ollama's native structured-outputs `format` field.\n * Constrains the model to emit an array of proposal objects matching the\n * fields normalizeProposal() accepts. Belt-and-suspenders — the downstream\n * defensive parser is still the authoritative validator. */\nconst PROPOSAL_ARRAY_SCHEMA: Record<string, unknown> = {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description', 'rationale'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n rationale: { type: 'string' },\n priority: { type: 'number' },\n tags: { type: 'array', items: { type: 'string' } },\n subtasks: {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n dependsOn: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n};\n\n// ── JSON Extraction ──────────────────────────────────────────────\n\n/** Defensively parse a JSON array from LLM output. Returns [] on failure. */\nfunction extractProposalArray(raw: string): unknown[] {\n const trimmed = raw.trim();\n // Try direct parse first.\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Strip code fences.\n const fenceStripped = trimmed.replace(/^```(?:json)?\\s*/i, '').replace(/\\s*```$/, '');\n try {\n const parsed = JSON.parse(fenceStripped);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Find the first `[...]` substring.\n const match = trimmed.match(/\\[[\\s\\S]*\\]/);\n if (match) {\n try {\n const parsed = JSON.parse(match[0]);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* give up */ }\n }\n return [];\n}\n\nfunction normalizeProposal(raw: unknown): ProposedGoal | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n let title = typeof r.title === 'string' ? r.title.trim() : '';\n let description = typeof r.description === 'string' ? r.description.trim() : '';\n const rationale = typeof r.rationale === 'string' ? r.rationale.trim() : '';\n if (!title || !description || !rationale) return null;\n if (title.length > 200 || description.length > 2000 || rationale.length > 2000) return null;\n\n const priority = typeof r.priority === 'number' && r.priority >= 1 && r.priority <= 5\n ? Math.floor(r.priority)\n : undefined;\n let tags: string[] | undefined = Array.isArray(r.tags)\n ? r.tags.filter((t): t is string => typeof t === 'string' && t.length < 40).slice(0, 6)\n : undefined;\n const parentGoalId = typeof r.parentGoalId === 'string' ? r.parentGoalId : undefined;\n\n type Subtask = { title: string; description: string; dependsOn?: string[] };\n let subtasks: Subtask[] | undefined;\n if (Array.isArray(r.subtasks)) {\n const collected: Subtask[] = [];\n for (const s of r.subtasks) {\n if (!s || typeof s !== 'object') continue;\n const rec = s as Record<string, unknown>;\n const t = typeof rec.title === 'string' ? rec.title.trim() : '';\n const d = typeof rec.description === 'string' ? rec.description.trim() : '';\n if (!t || !d) continue;\n const deps = Array.isArray(rec.dependsOn)\n ? rec.dependsOn.filter((x): x is string => typeof x === 'string')\n : undefined;\n // Subtask-level rewrite happens after we know the parent goal's\n // self-mod status (below), so stash refs.\n void t; void d;\n collected.push({ title: t, description: d, dependsOn: deps });\n if (collected.length >= 12) break;\n }\n if (collected.length > 0) subtasks = collected;\n }\n\n // v4.9.0-local.8: self-mod disambiguation. When the proposer emits a\n // goal that sounds like it wants to modify \"the framework\" / \"core\" /\n // etc, the specialist picking it up historically interpreted this as\n // \"build something under ~/titan-saas\" because that's where Next.js\n // project scaffolding lives. We close the ambiguity at creation time:\n //\n // 1. Detect self-mod trigger words in title + description + tags\n // 2. If matched, ensure tags include 'self-mod' so the toolRunner\n // scope-lock + staging gate activates for work on this goal\n // 3. Append an explicit scope-lock note to the description pointing\n // at the actual target path\n // 4. Rewrite common ambiguous phrases in subtasks to spell out the\n // target path\n const selfModTriggers = [\n /\\bself[\\s-]?heal/i,\n /\\bself[\\s-]?repair/i,\n /\\bself[\\s-]?mod/i,\n /\\bcore[\\s-]framework/i,\n /\\bTITAN['’]?s?\\s+(own|core|framework|architecture|source|runtime)/i,\n /\\bframework\\s+(component|module|core|runtime)/i,\n ];\n const selfModTagValues = new Set([\n 'self-healing', 'self-repair', 'self-mod', 'self-modification',\n 'core-framework', 'framework', 'architecture', 'core', 'autonomy',\n ]);\n const tagsLower = new Set((tags || []).map(t => t.toLowerCase()));\n const haystack = `${title}\\n${description}\\n${(tags || []).join(' ')}`;\n const matchedByText = selfModTriggers.some(re => re.test(haystack));\n const matchedByTag = [...tagsLower].some(t => selfModTagValues.has(t));\n const isSelfMod = matchedByText || matchedByTag;\n\n if (isSelfMod) {\n const cfg = loadConfig();\n const target = (cfg.autonomy?.selfMod as { target?: string } | undefined)?.target || '/opt/TITAN';\n // Ensure the canonical 'self-mod' tag is present so toolRunner sees it\n tags = tags ? [...tags] : [];\n if (!tagsLower.has('self-mod')) tags.push('self-mod');\n tags = tags.slice(0, 6);\n\n // Append an unmistakable scope-lock note to the description — the\n // specialist reading this goal sees the target path explicitly\n // instead of having to infer \"the framework\" from context.\n const scopeNote = `\\n\\n[SCOPE-LOCK] This is a self-modification goal. All file writes MUST target ${target} (TITAN's own source tree). Writes to any other path will be refused by the toolRunner scope-lock. When staging is enabled, writes are diverted to ${target}/../self-mod-staging/<goalId>/ and surface as a self_mod_pr approval for human review before applying.`;\n if (!/\\[SCOPE-LOCK\\]/.test(description)) {\n description = (description + scopeNote).slice(0, 2000);\n }\n\n // Rewrite common ambiguous phrases in title/subtasks so the\n // specialist-level prompt mentions the target explicitly.\n const rewrite = (s: string): string => s\n .replace(/\\b(the\\s+)?core\\s+framework\\b/gi, `${target} (TITAN core framework)`)\n .replace(/\\b(the\\s+)?(TITAN\\s+)?framework\\b(?!\\s+component)/gi, `${target} (TITAN framework)`);\n title = rewrite(title).slice(0, 200);\n if (subtasks) {\n subtasks = subtasks.map(s => ({\n title: rewrite(s.title).slice(0, 200),\n description: rewrite(s.description).slice(0, 2000),\n dependsOn: s.dependsOn,\n }));\n }\n }\n\n return { title, description, rationale, priority, tags, parentGoalId, subtasks };\n}\n\n// ── Main Entry Point ─────────────────────────────────────────────\n\n/**\n * Generate goal proposals for a single agent and file them as pending approvals.\n * Returns the list of CPApproval records created (may be empty).\n *\n * Called by the dreaming watcher's Phase 4 (Dream). Safe to call ad-hoc from\n * debug endpoints or tests.\n */\nexport async function generateGoalProposals(\n agentId: string,\n ctx: GoalProposerContext,\n type: 'goal_proposal' | 'soma_proposal' = 'goal_proposal'\n): Promise<CPApproval[]> {\n const config = loadConfig();\n const enabled = config.agent.autoProposeGoals;\n if (!enabled) {\n logger.debug(COMPONENT, `autoProposeGoals disabled — skipping for agent ${agentId}`);\n return [];\n }\n\n const limit = config.agent.proposalRateLimitPerDay;\n const slotsLeft = remainingSlots(agentId, limit);\n if (slotsLeft <= 0) {\n logger.info(COMPONENT, `Agent ${agentId} has hit daily proposal limit (${limit}) — skipping`);\n return [];\n }\n\n const modelAlias = config.agent.proposalModel || 'fast';\n const model = config.agent.modelAliases[modelAlias] || modelAlias;\n\n // v4.9.0-local.4: pre-load extra memory blocks (episodic, experiments,\n // identity) before building the proposer prompt. Closes the repeat-\n // task feedback loop — the proposer now sees what TITAN has recently\n // done and won't re-propose the same ant colony sim three times.\n // Each block is best-effort; silent fallthrough if a module isn't\n // available at proposer time.\n const extraBlocks: string[] = [];\n try {\n const { renderRecallBlock } = await import('../memory/episodic.js');\n const block = renderRecallBlock({ limit: 12, windowHours: 72 });\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { renderRecentExperimentsBlock } = await import('../memory/experiments.js');\n const block = renderRecentExperimentsBlock(8);\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { getIdentity } = await import('../memory/identity.js');\n const id = getIdentity();\n if (id) {\n extraBlocks.push([\n '## Your identity (persistent)',\n `Mission: ${id.core.mission}`,\n `Non-negotiables: ${id.core.nonNegotiables.slice(0, 3).join('; ')}`,\n 'Propose ONLY goals that align with the mission and never violate a non-negotiable.',\n ].join('\\n'));\n }\n } catch { /* ok */ }\n\n const ctxWithBlocks: GoalProposerContext = { ...ctx, extraBlocks };\n const prompt = buildPrompt(agentId, slotsLeft, ctxWithBlocks);\n\n // v4.13 ancestor-extraction: route goal-proposal JSON extraction through\n // the auxiliary model client. The main agent model (gemma4:31b on the\n // Titan PC default) produces empty arrays for structured JSON tasks; a\n // dedicated fast+cheap model (minimax-m2.7:cloud) reliably produces valid\n // proposals. Falls back to the main `model` when no auxiliary is\n // configured.\n const auxModel = resolveAuxiliaryModel('json_extraction');\n const effectiveModel = auxModel || model;\n const isOllamaEffective = effectiveModel.toLowerCase().startsWith('ollama/');\n\n let rawContent: string;\n try {\n const response = await auxChat(\n 'json_extraction',\n {\n messages: [\n { role: 'system', content: 'You are a careful autonomous agent proposing new work. Output ONLY valid JSON. No explanation, no prose.' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.4,\n maxTokens: 1500,\n ...(isOllamaEffective ? { format: PROPOSAL_ARRAY_SCHEMA } : {}),\n },\n model, // fallback to main agent model if no aux is configured\n );\n if (!response) {\n logger.warn(COMPONENT, `Auxiliary call returned null for agent ${agentId} — treating as no proposals`);\n return [];\n }\n rawContent = response.content || '';\n if (auxModel && auxModel !== model) {\n logger.info(COMPONENT, `Agent ${agentId} goal-proposal routed via auxiliary model ${auxModel} (main: ${model})`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `LLM call failed for agent ${agentId}: ${(err as Error).message}`);\n return [];\n }\n\n // Strip chain-of-thought leakage before parsing JSON.\n const guarded = applyOutputGuardrails(rawContent, { type: 'sub_agent' });\n const parsed = extractProposalArray(guarded.content);\n if (parsed.length === 0) {\n logger.info(COMPONENT, `Agent ${agentId} proposed no goals (parsed empty array)`);\n return [];\n }\n\n const proposals: ProposedGoal[] = [];\n for (const item of parsed) {\n const normalized = normalizeProposal(item);\n if (normalized) proposals.push(normalized);\n if (proposals.length >= slotsLeft) break;\n }\n\n // v5.0.0: dedupe against ALL recent goals (not just active) and enforce\n // goal-overload backoff. Prevents the runaway loops that produced 1000+\n // duplicate \"Publish content\" goals.\n let allGoalTitles: string[] = [];\n let activeGoalCount = 0;\n try {\n const { listGoals } = await import('./goals.js');\n const all = listGoals();\n allGoalTitles = all.map(g => g.title);\n activeGoalCount = all.filter(g => g.status === 'active').length;\n } catch { /* best-effort */ }\n\n // Overload backoff: if the system is already swamped, only allow\n // cleanup / meta proposals (titles containing \"resolve\", \"cancel\",\n // \"close\", \"audit\", \"clean\", \"dedupe\"). Everything else is deferred\n // until the backlog drops.\n const isOverload = activeGoalCount >= 25;\n const isCleanupProposal = (t: string) => /\\b(resolve|cancel|close|audit|clean|dedupe|consolidate|prune)\\b/i.test(t);\n\n const approvals: CPApproval[] = [];\n for (const proposal of proposals) {\n // Dedupe against ANY existing goal (active, paused, completed, failed)\n const dup = allGoalTitles.find(t => titleSimilarity(t, proposal.title) >= 0.72);\n if (dup) {\n logger.info(COMPONENT, `Agent ${agentId} skipped duplicate proposal \"${proposal.title}\" (matches existing goal \"${dup}\")`);\n continue;\n }\n // Overload gate\n if (isOverload && !isCleanupProposal(proposal.title)) {\n logger.info(COMPONENT, `Agent ${agentId} skipped proposal \"${proposal.title}\" — goal overload (${activeGoalCount} active). Only cleanup proposals allowed.`);\n continue;\n }\n try {\n const approval = requestGoalProposalApproval(agentId, proposal, type);\n approvals.push(approval);\n recordProposal(agentId);\n allGoalTitles.push(proposal.title); // prevent intra-batch dupes too\n logger.info(COMPONENT, `Agent ${agentId} filed proposal \"${proposal.title}\" (approval ${approval.id})`);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to file proposal \"${proposal.title}\": ${(err as Error).message}`);\n }\n }\n\n return approvals;\n}\n\n/**\n * v4.5.6: simple title similarity for dedupe. Normalizes case, strips\n * filler words, compares token overlap (Jaccard). 0.72 threshold catches\n * \"Satiate Hunger\" vs \"Satiate hunger\" vs \"Satiate hunger backlog\"\n * but not \"Satiate Purpose\" vs \"Satiate hunger\" — which is what we want.\n */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2 && !STOP_WORDS.has(w))\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\nconst STOP_WORDS = new Set([\n 'the', 'and', 'for', 'with', 'new', 'novel', 'build', 'using', 'from',\n 'into', 'over', 'onto', 'that', 'this', 'some', 'any',\n]);\n\n// ── Context Helpers ──────────────────────────────────────────────\n\n/**\n * Build the default context for a goal proposer run from current TITAN state.\n * Extracted so tests can construct contexts deterministically.\n */\nexport function buildDefaultContext(): GoalProposerContext {\n const activeGoals = listGoals('active').map(g => g.title);\n const failedSubtasks: string[] = [];\n for (const g of listGoals()) {\n for (const st of g.subtasks || []) {\n if (st.status === 'failed') failedSubtasks.push(`${g.title} → ${st.title}`);\n }\n }\n const recentActivity: string[] = [];\n try {\n const feed = getActivity({ limit: 50 });\n for (const entry of feed) {\n recentActivity.push(`[${entry.type}] ${entry.message}`);\n }\n } catch { /* feed may be unavailable in early boot */ }\n\n return {\n activeGoals,\n failedSubtasks: failedSubtasks.slice(0, 20),\n recentActivity,\n };\n}\n"],"mappings":"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","names":["listGoals"]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/goalProposer.ts"],"sourcesContent":["/**\n * TITAN — Self-Directed Goal Proposer\n *\n * Runs during the nightly dreaming cycle (Phase 4: Dream) after memory\n * consolidation has happened. Each registered agent examines recent activity,\n * open issues, failed subtasks, and consolidation findings, then proposes\n * 0-3 new goals it thinks would be worth doing.\n *\n * Proposals go into the Command Post approval queue as `type: 'goal_proposal'`.\n * A human (or designated approver agent) accepts or rejects them. On accept,\n * the existing createGoal() pipeline fires and Initiative picks up the work.\n *\n * Opt-in via config.agent.autoProposeGoals (default false).\n * Rate-limited per-agent via config.agent.proposalRateLimitPerDay.\n */\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { loadConfig } from '../config/config.js';\nimport { chat } from '../providers/router.js';\nimport { auxChat, resolveAuxiliaryModel } from '../providers/auxiliary.js';\nimport { applyOutputGuardrails } from './outputGuardrails.js';\nimport { getActivity, requestGoalProposalApproval, type CPApproval } from './commandPost.js';\nimport { listGoals } from './goals.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'GoalProposer';\nconst RATE_STATE_PATH = join(TITAN_HOME, 'goal-proposer-state.json');\n\n// ── Types ────────────────────────────────────────────────────────\n\nexport interface ProposedGoal {\n title: string;\n description: string;\n rationale: string;\n priority?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n}\n\nexport interface GoalProposerContext {\n /** Recent activity feed entries — max last 50. */\n recentActivity?: string[];\n /** Titles of currently active goals so proposals don't duplicate. */\n activeGoals?: string[];\n /** Titles of recently failed subtasks worth retrying or reframing. */\n failedSubtasks?: string[];\n /** Free-form notes from the dreaming consolidation log. */\n consolidationNotes?: string;\n /**\n * v4.9.0-local.4: extra prompt blocks (episodic recall, experiment\n * history, identity) pre-loaded by the caller. Keeps buildPrompt\n * synchronous.\n */\n extraBlocks?: string[];\n}\n\ninterface RateLimitState {\n /** Map of agentId → ISO timestamps of proposals filed in the last 24h. */\n proposalsByAgent: Record<string, string[]>;\n}\n\n// ── Rate Limiting ────────────────────────────────────────────────\n\nfunction loadRateState(): RateLimitState {\n if (!existsSync(RATE_STATE_PATH)) return { proposalsByAgent: {} };\n try {\n const raw = readFileSync(RATE_STATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as Partial<RateLimitState>;\n // v4.9.0-local.6: defensive normalize. A prior bug (+ the goal-\n // reset script) can write `{}` to this file, losing the\n // `proposalsByAgent` key. Without this, every\n // `state.proposalsByAgent[agentId]` access crashes with\n // \"Cannot read properties of undefined (reading '<agent>')\"\n // and proposals silently fail for hours.\n return {\n proposalsByAgent: parsed?.proposalsByAgent ?? {},\n };\n } catch {\n return { proposalsByAgent: {} };\n }\n}\n\nfunction saveRateState(state: RateLimitState): void {\n try {\n mkdirIfNotExists(TITAN_HOME);\n writeFileSync(RATE_STATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n logger.warn(COMPONENT, `Failed to save rate state: ${(err as Error).message}`);\n }\n}\n\n/** Returns how many slots the agent has remaining in the current 24h window. */\nexport function remainingSlots(agentId: string, limitPerDay: number): number {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const stamps = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n return Math.max(0, limitPerDay - stamps.length);\n}\n\nfunction recordProposal(agentId: string): void {\n const state = loadRateState();\n const now = Date.now();\n const dayMs = 24 * 3600 * 1000;\n const existing = (state.proposalsByAgent[agentId] || []).filter(t => now - new Date(t).getTime() < dayMs);\n existing.push(new Date().toISOString());\n state.proposalsByAgent[agentId] = existing;\n saveRateState(state);\n}\n\n// ── Prompt ───────────────────────────────────────────────────────\n\nfunction buildPrompt(agentId: string, slotsLeft: number, ctx: GoalProposerContext): string {\n const sections: string[] = [];\n sections.push(`You are agent \"${agentId}\". You have been given a quiet window to reflect on the system's current state and propose new goals that would meaningfully help.`);\n sections.push(`You may propose 0 to ${slotsLeft} goals. It is OK — often preferable — to propose zero if nothing is clearly worth doing.`);\n sections.push('');\n\n if (ctx.activeGoals && ctx.activeGoals.length) {\n sections.push('## Currently Active Goals (do not duplicate)');\n for (const title of ctx.activeGoals.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.recentActivity && ctx.recentActivity.length) {\n sections.push('## Recent Activity (last ~50 events)');\n for (const line of ctx.recentActivity.slice(-50)) sections.push(`- ${line}`);\n sections.push('');\n }\n if (ctx.failedSubtasks && ctx.failedSubtasks.length) {\n sections.push('## Recently Failed Subtasks');\n for (const title of ctx.failedSubtasks.slice(0, 20)) sections.push(`- ${title}`);\n sections.push('');\n }\n if (ctx.consolidationNotes) {\n sections.push('## Memory Consolidation Notes');\n sections.push(ctx.consolidationNotes);\n sections.push('');\n }\n\n // v4.9.0-local.4: extra memory blocks (episodic, experiments,\n // identity) pre-loaded by the async caller and passed through ctx.\n // Keeps buildPrompt synchronous while still giving the proposer\n // full context of what TITAN has already done + who it is.\n if (ctx.extraBlocks && ctx.extraBlocks.length > 0) {\n for (const block of ctx.extraBlocks) {\n if (block && block.trim()) {\n sections.push(block);\n sections.push('');\n }\n }\n }\n\n sections.push('## Output Format');\n sections.push('Return ONLY a JSON array (no prose, no markdown fences). Each element:');\n sections.push('```');\n sections.push('{');\n sections.push(' \"title\": \"short imperative, under 80 chars\",');\n sections.push(' \"description\": \"what success looks like, 1-3 sentences\",');\n sections.push(' \"rationale\": \"why this goal is worth doing NOW\",');\n sections.push(' \"priority\": 1-5 (1 = highest),');\n sections.push(' \"tags\": [\"optional\", \"labels\"],');\n sections.push(' \"subtasks\": [{\"title\": \"...\", \"description\": \"...\"}]');\n sections.push('}');\n sections.push('```');\n sections.push('If nothing is worth proposing, return `[]`. Never return more than the slot limit.');\n\n return sections.join('\\n');\n}\n\n/** JSON schema passed to Ollama's native structured-outputs `format` field.\n * Constrains the model to emit an array of proposal objects matching the\n * fields normalizeProposal() accepts. Belt-and-suspenders — the downstream\n * defensive parser is still the authoritative validator. */\nconst PROPOSAL_ARRAY_SCHEMA: Record<string, unknown> = {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description', 'rationale'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n rationale: { type: 'string' },\n priority: { type: 'number' },\n tags: { type: 'array', items: { type: 'string' } },\n subtasks: {\n type: 'array',\n items: {\n type: 'object',\n required: ['title', 'description'],\n properties: {\n title: { type: 'string' },\n description: { type: 'string' },\n dependsOn: { type: 'array', items: { type: 'string' } },\n },\n },\n },\n },\n },\n};\n\n// ── JSON Extraction ──────────────────────────────────────────────\n\n/** Defensively parse a JSON array from LLM output. Returns [] on failure. */\nfunction extractProposalArray(raw: string): unknown[] {\n const trimmed = raw.trim();\n // Try direct parse first.\n try {\n const parsed = JSON.parse(trimmed);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Strip code fences.\n const fenceStripped = trimmed.replace(/^```(?:json)?\\s*/i, '').replace(/\\s*```$/, '');\n try {\n const parsed = JSON.parse(fenceStripped);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* fall through */ }\n // Find the first `[...]` substring.\n const match = trimmed.match(/\\[[\\s\\S]*\\]/);\n if (match) {\n try {\n const parsed = JSON.parse(match[0]);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* give up */ }\n }\n return [];\n}\n\nfunction normalizeProposal(raw: unknown): ProposedGoal | null {\n if (!raw || typeof raw !== 'object') return null;\n const r = raw as Record<string, unknown>;\n let title = typeof r.title === 'string' ? r.title.trim() : '';\n let description = typeof r.description === 'string' ? r.description.trim() : '';\n const rationale = typeof r.rationale === 'string' ? r.rationale.trim() : '';\n if (!title || !description || !rationale) return null;\n if (title.length > 200 || description.length > 2000 || rationale.length > 2000) return null;\n\n const priority = typeof r.priority === 'number' && r.priority >= 1 && r.priority <= 5\n ? Math.floor(r.priority)\n : undefined;\n let tags: string[] | undefined = Array.isArray(r.tags)\n ? r.tags.filter((t): t is string => typeof t === 'string' && t.length < 40).slice(0, 6)\n : undefined;\n const parentGoalId = typeof r.parentGoalId === 'string' ? r.parentGoalId : undefined;\n\n type Subtask = { title: string; description: string; dependsOn?: string[] };\n let subtasks: Subtask[] | undefined;\n if (Array.isArray(r.subtasks)) {\n const collected: Subtask[] = [];\n for (const s of r.subtasks) {\n if (!s || typeof s !== 'object') continue;\n const rec = s as Record<string, unknown>;\n const t = typeof rec.title === 'string' ? rec.title.trim() : '';\n const d = typeof rec.description === 'string' ? rec.description.trim() : '';\n if (!t || !d) continue;\n const deps = Array.isArray(rec.dependsOn)\n ? rec.dependsOn.filter((x): x is string => typeof x === 'string')\n : undefined;\n // Subtask-level rewrite happens after we know the parent goal's\n // self-mod status (below), so stash refs.\n void t; void d;\n collected.push({ title: t, description: d, dependsOn: deps });\n if (collected.length >= 12) break;\n }\n if (collected.length > 0) subtasks = collected;\n }\n\n // v4.9.0-local.8: self-mod disambiguation. When the proposer emits a\n // goal that sounds like it wants to modify \"the framework\" / \"core\" /\n // etc, the specialist picking it up historically interpreted this as\n // \"build something under ~/titan-saas\" because that's where Next.js\n // project scaffolding lives. We close the ambiguity at creation time:\n //\n // 1. Detect self-mod trigger words in title + description + tags\n // 2. If matched, ensure tags include 'self-mod' so the toolRunner\n // scope-lock + staging gate activates for work on this goal\n // 3. Append an explicit scope-lock note to the description pointing\n // at the actual target path\n // 4. Rewrite common ambiguous phrases in subtasks to spell out the\n // target path\n const selfModTriggers = [\n /\\bself[\\s-]?heal/i,\n /\\bself[\\s-]?repair/i,\n /\\bself[\\s-]?mod/i,\n /\\bcore[\\s-]framework/i,\n /\\bTITAN['’]?s?\\s+(own|core|framework|architecture|source|runtime)/i,\n /\\bframework\\s+(component|module|core|runtime)/i,\n ];\n const selfModTagValues = new Set([\n 'self-healing', 'self-repair', 'self-mod', 'self-modification',\n 'core-framework', 'framework', 'architecture', 'core', 'autonomy',\n ]);\n const tagsLower = new Set((tags || []).map(t => t.toLowerCase()));\n const haystack = `${title}\\n${description}\\n${(tags || []).join(' ')}`;\n const matchedByText = selfModTriggers.some(re => re.test(haystack));\n const matchedByTag = [...tagsLower].some(t => selfModTagValues.has(t));\n const isSelfMod = matchedByText || matchedByTag;\n\n if (isSelfMod) {\n const cfg = loadConfig();\n const target = (cfg.autonomy?.selfMod as { target?: string } | undefined)?.target || '/opt/TITAN';\n // Ensure the canonical 'self-mod' tag is present so toolRunner sees it\n tags = tags ? [...tags] : [];\n if (!tagsLower.has('self-mod')) tags.push('self-mod');\n tags = tags.slice(0, 6);\n\n // Append an unmistakable scope-lock note to the description — the\n // specialist reading this goal sees the target path explicitly\n // instead of having to infer \"the framework\" from context.\n const scopeNote = `\\n\\n[SCOPE-LOCK] This is a self-modification goal. All file writes MUST target ${target} (TITAN's own source tree). Writes to any other path will be refused by the toolRunner scope-lock. When staging is enabled, writes are diverted to ${target}/../self-mod-staging/<goalId>/ and surface as a self_mod_pr approval for human review before applying.`;\n if (!/\\[SCOPE-LOCK\\]/.test(description)) {\n description = (description + scopeNote).slice(0, 2000);\n }\n\n // Rewrite common ambiguous phrases in title/subtasks so the\n // specialist-level prompt mentions the target explicitly.\n const rewrite = (s: string): string => s\n .replace(/\\b(the\\s+)?core\\s+framework\\b/gi, `${target} (TITAN core framework)`)\n .replace(/\\b(the\\s+)?(TITAN\\s+)?framework\\b(?!\\s+component)/gi, `${target} (TITAN framework)`);\n title = rewrite(title).slice(0, 200);\n if (subtasks) {\n subtasks = subtasks.map(s => ({\n title: rewrite(s.title).slice(0, 200),\n description: rewrite(s.description).slice(0, 2000),\n dependsOn: s.dependsOn,\n }));\n }\n }\n\n return { title, description, rationale, priority, tags, parentGoalId, subtasks };\n}\n\n// ── Main Entry Point ─────────────────────────────────────────────\n\n/**\n * Generate goal proposals for a single agent and file them as pending approvals.\n * Returns the list of CPApproval records created (may be empty).\n *\n * Called by the dreaming watcher's Phase 4 (Dream). Safe to call ad-hoc from\n * debug endpoints or tests.\n */\nexport async function generateGoalProposals(\n agentId: string,\n ctx: GoalProposerContext,\n type: 'goal_proposal' | 'soma_proposal' = 'goal_proposal'\n): Promise<CPApproval[]> {\n const config = loadConfig();\n const enabled = config.agent.autoProposeGoals;\n if (!enabled) {\n logger.debug(COMPONENT, `autoProposeGoals disabled — skipping for agent ${agentId}`);\n return [];\n }\n\n const limit = config.agent.proposalRateLimitPerDay;\n const slotsLeft = remainingSlots(agentId, limit);\n if (slotsLeft <= 0) {\n logger.info(COMPONENT, `Agent ${agentId} has hit daily proposal limit (${limit}) — skipping`);\n return [];\n }\n\n const modelAlias = config.agent.proposalModel || 'fast';\n const model = config.agent.modelAliases[modelAlias] || modelAlias;\n\n // v4.9.0-local.4: pre-load extra memory blocks (episodic, experiments,\n // identity) before building the proposer prompt. Closes the repeat-\n // task feedback loop — the proposer now sees what TITAN has recently\n // done and won't re-propose the same ant colony sim three times.\n // Each block is best-effort; silent fallthrough if a module isn't\n // available at proposer time.\n const extraBlocks: string[] = [];\n try {\n const { renderRecallBlock } = await import('../memory/episodic.js');\n const block = renderRecallBlock({ limit: 12, windowHours: 72 });\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { renderRecentExperimentsBlock } = await import('../memory/experiments.js');\n const block = renderRecentExperimentsBlock(8);\n if (block) extraBlocks.push(block);\n } catch { /* ok */ }\n try {\n const { getIdentity } = await import('../memory/identity.js');\n const id = getIdentity();\n if (id) {\n extraBlocks.push([\n '## Your identity (persistent)',\n `Mission: ${id.core.mission}`,\n `Non-negotiables: ${id.core.nonNegotiables.slice(0, 3).join('; ')}`,\n 'Propose ONLY goals that align with the mission and never violate a non-negotiable.',\n ].join('\\n'));\n }\n } catch { /* ok */ }\n\n const ctxWithBlocks: GoalProposerContext = { ...ctx, extraBlocks };\n const prompt = buildPrompt(agentId, slotsLeft, ctxWithBlocks);\n\n // v4.13 ancestor-extraction: route goal-proposal JSON extraction through\n // the auxiliary model client. The main agent model (gemma4:31b on the\n // Titan PC default) produces empty arrays for structured JSON tasks; a\n // dedicated fast+cheap model (minimax-m2.7:cloud) reliably produces valid\n // proposals. Falls back to the main `model` when no auxiliary is\n // configured.\n const auxModel = resolveAuxiliaryModel('json_extraction');\n const effectiveModel = auxModel || model;\n const isOllamaEffective = effectiveModel.toLowerCase().startsWith('ollama/');\n\n let rawContent: string;\n try {\n const response = await auxChat(\n 'json_extraction',\n {\n messages: [\n { role: 'system', content: 'You are a careful autonomous agent proposing new work. Output ONLY valid JSON. No explanation, no prose.' },\n { role: 'user', content: prompt },\n ],\n temperature: 0.4,\n maxTokens: 1500,\n ...(isOllamaEffective ? { format: PROPOSAL_ARRAY_SCHEMA } : {}),\n },\n model, // fallback to main agent model if no aux is configured\n );\n if (!response) {\n logger.warn(COMPONENT, `Auxiliary call returned null for agent ${agentId} — treating as no proposals`);\n return [];\n }\n rawContent = response.content || '';\n if (auxModel && auxModel !== model) {\n logger.info(COMPONENT, `Agent ${agentId} goal-proposal routed via auxiliary model ${auxModel} (main: ${model})`);\n }\n } catch (err) {\n logger.warn(COMPONENT, `LLM call failed for agent ${agentId}: ${(err as Error).message}`);\n return [];\n }\n\n // Strip chain-of-thought leakage before parsing JSON.\n const guarded = applyOutputGuardrails(rawContent, { type: 'sub_agent' });\n const parsed = extractProposalArray(guarded.content);\n if (parsed.length === 0) {\n logger.info(COMPONENT, `Agent ${agentId} proposed no goals (parsed empty array)`);\n return [];\n }\n\n const proposals: ProposedGoal[] = [];\n for (const item of parsed) {\n const normalized = normalizeProposal(item);\n if (normalized) proposals.push(normalized);\n if (proposals.length >= slotsLeft) break;\n }\n\n // v5.0.0: dedupe against ALL recent goals (not just active) and enforce\n // goal-overload backoff. Prevents the runaway loops that produced 1000+\n // duplicate \"Publish content\" goals.\n let allGoalTitles: string[] = [];\n let activeGoalCount = 0;\n try {\n const { listGoals } = await import('./goals.js');\n const all = listGoals();\n allGoalTitles = all.map(g => g.title);\n activeGoalCount = all.filter(g => g.status === 'active').length;\n } catch { /* best-effort */ }\n\n // Overload backoff: if the system is already swamped, only allow\n // cleanup / meta proposals (titles containing \"resolve\", \"cancel\",\n // \"close\", \"audit\", \"clean\", \"dedupe\"). Everything else is deferred\n // until the backlog drops.\n const isOverload = activeGoalCount >= 25;\n const isCleanupProposal = (t: string) => /\\b(resolve|cancel|close|audit|clean|dedupe|consolidate|prune)\\b/i.test(t);\n\n const approvals: CPApproval[] = [];\n for (const proposal of proposals) {\n // Dedupe against ANY existing goal (active, paused, completed, failed)\n const dup = allGoalTitles.find(t => titleSimilarity(t, proposal.title) >= 0.72);\n if (dup) {\n logger.info(COMPONENT, `Agent ${agentId} skipped duplicate proposal \"${proposal.title}\" (matches existing goal \"${dup}\")`);\n continue;\n }\n // Overload gate\n if (isOverload && !isCleanupProposal(proposal.title)) {\n logger.info(COMPONENT, `Agent ${agentId} skipped proposal \"${proposal.title}\" — goal overload (${activeGoalCount} active). Only cleanup proposals allowed.`);\n continue;\n }\n try {\n const approval = requestGoalProposalApproval(agentId, proposal, type);\n approvals.push(approval);\n recordProposal(agentId);\n allGoalTitles.push(proposal.title); // prevent intra-batch dupes too\n logger.info(COMPONENT, `Agent ${agentId} filed proposal \"${proposal.title}\" (approval ${approval.id})`);\n } catch (err) {\n logger.warn(COMPONENT, `Failed to file proposal \"${proposal.title}\": ${(err as Error).message}`);\n }\n }\n\n return approvals;\n}\n\n/**\n * v4.5.6: simple title similarity for dedupe. Normalizes case, strips\n * filler words, compares token overlap (Jaccard). 0.72 threshold catches\n * \"Satiate Hunger\" vs \"Satiate hunger\" vs \"Satiate hunger backlog\"\n * but not \"Satiate Purpose\" vs \"Satiate hunger\" — which is what we want.\n */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2 && !STOP_WORDS.has(w))\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\nconst STOP_WORDS = new Set([\n 'the', 'and', 'for', 'with', 'new', 'novel', 'build', 'using', 'from',\n 'into', 'over', 'onto', 'that', 'this', 'some', 'any',\n]);\n\n// ── Context Helpers ──────────────────────────────────────────────\n\n/**\n * Build the default context for a goal proposer run from current TITAN state.\n * Extracted so tests can construct contexts deterministically.\n */\nexport function buildDefaultContext(): GoalProposerContext {\n const activeGoals = listGoals('active').map(g => g.title);\n const failedSubtasks: string[] = [];\n for (const g of listGoals()) {\n for (const st of g.subtasks || []) {\n if (st.status === 'failed') failedSubtasks.push(`${g.title} → ${st.title}`);\n }\n }\n const recentActivity: string[] = [];\n try {\n const feed = getActivity({ limit: 50 });\n for (const entry of feed) {\n recentActivity.push(`[${entry.type}] ${entry.message}`);\n }\n } catch { /* feed may be unavailable in early boot */ }\n\n return {\n activeGoals,\n failedSubtasks: failedSubtasks.slice(0, 20),\n recentActivity,\n };\n}\n"],"mappings":"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","names":["listGoals"]}
|
package/dist/agent/goals.js
CHANGED
|
@@ -3,7 +3,7 @@ import { v4 as uuid } from "uuid";
|
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { TITAN_HOME } from "../utils/constants.js";
|
|
6
|
-
import {
|
|
6
|
+
import { mkdirIfNotExists } from "../utils/helpers.js";
|
|
7
7
|
import { titanEvents } from "./daemon.js";
|
|
8
8
|
import logger from "../utils/logger.js";
|
|
9
9
|
const COMPONENT = "Goals";
|
|
@@ -26,7 +26,7 @@ function loadRateState() {
|
|
|
26
26
|
}
|
|
27
27
|
function saveRateState(state) {
|
|
28
28
|
try {
|
|
29
|
-
|
|
29
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
30
30
|
writeFileSync(RATE_PATH, JSON.stringify(state, null, 2), "utf-8");
|
|
31
31
|
} catch {
|
|
32
32
|
}
|
|
@@ -77,7 +77,7 @@ function loadGoals() {
|
|
|
77
77
|
function saveGoals() {
|
|
78
78
|
const goals = goalsCache || [];
|
|
79
79
|
try {
|
|
80
|
-
|
|
80
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
81
81
|
const store = {
|
|
82
82
|
goals,
|
|
83
83
|
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
package/dist/agent/goals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/goals.ts"],"sourcesContent":["/**\n * TITAN — Goal Management System\n * Persistent goals with subtasks, scheduling, budget tracking, and progress monitoring.\n * Goals drive the autopilot system — each cycle picks the next actionable subtask.\n */\nimport { v4 as uuid } from 'uuid';\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport { titanEvents } from './daemon.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'Goals';\nconst GOALS_PATH = join(TITAN_HOME, 'goals.json');\nconst RATE_PATH = join(TITAN_HOME, 'goal-creation-rate.json');\n\n/** Safety limits — prevent runaway goal proliferation (SOMA or agent loops). */\nconst MAX_TOTAL_GOALS = 150;\nconst MAX_ACTIVE_GOALS = 50;\nconst MAX_GOALS_PER_HOUR = 10;\nconst RECENT_DEDUPE_HOURS = 24;\nconst SIMILARITY_THRESHOLD = 0.82; // Jaccard — catches \"Publish content: AI agents\" vs \"Publish content: tech\"\n\n/** Load rate-limit state from disk. */\nfunction loadRateState(): { creations: string[] } {\n if (!existsSync(RATE_PATH)) return { creations: [] };\n try {\n const raw = readFileSync(RATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as { creations?: string[] };\n return { creations: Array.isArray(parsed?.creations) ? parsed.creations : [] };\n } catch {\n return { creations: [] };\n }\n}\n\nfunction saveRateState(state: { creations: string[] }): void {\n try {\n ensureDir(TITAN_HOME);\n writeFileSync(RATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch { /* non-critical */ }\n}\n\n/** Jaccard similarity for fuzzy dedupe. 0–1, higher = more similar. */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2)\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/** Returns true if we should block creation due to rate limits. */\nfunction isRateLimited(force: boolean): { limited: boolean; reason?: string } {\n if (force) return { limited: false };\n const state = loadRateState();\n const now = Date.now();\n const hourMs = 60 * 60 * 1000;\n const recent = state.creations.filter(t => now - new Date(t).getTime() < hourMs);\n if (recent.length >= MAX_GOALS_PER_HOUR) {\n return { limited: true, reason: `rate limit: ${recent.length} goals created in the last hour (max ${MAX_GOALS_PER_HOUR})` };\n }\n recent.push(new Date().toISOString());\n saveRateState({ creations: recent });\n return { limited: false };\n}\n\nexport type GoalStatus = 'active' | 'paused' | 'completed' | 'failed';\nexport type SubtaskStatus = 'pending' | 'running' | 'done' | 'failed' | 'skipped';\n\nexport interface SubtaskTrigger {\n type: 'schedule' | 'event' | 'dependency' | 'manual';\n /** Event name to match (e.g., 'health:ollama:down', 'cron:stuck') */\n event?: string;\n /** Cron expression for scheduled triggers */\n schedule?: string;\n /** LLM-evaluated condition (e.g., \"when error rate exceeds 50%\") */\n condition?: string;\n}\n\nexport interface Subtask {\n id: string;\n title: string;\n description: string;\n status: SubtaskStatus;\n result?: string;\n error?: string;\n completedAt?: string;\n retries: number;\n /** Subtask IDs within the same goal that must complete before this one can start */\n dependsOn?: string[];\n /** Optional trigger — when set, subtask activates on matching events instead of linearly */\n trigger?: SubtaskTrigger;\n}\n\nexport interface Goal {\n id: string;\n title: string;\n description: string;\n status: GoalStatus;\n priority: number; // 1 = highest\n subtasks: Subtask[];\n schedule?: string; // cron expression (e.g., \"0 9 * * 1,4\" for Mon+Thu 9am)\n budgetLimit?: number; // max USD spend for this goal\n totalCost: number;\n progress: number; // 0-100 percentage\n createdAt: string;\n updatedAt: string;\n completedAt?: string;\n tags?: string[];\n /** Parent goal ID for ancestry chain (Command Post) */\n parentGoalId?: string;\n}\n\ninterface GoalsStore {\n goals: Goal[];\n lastUpdated: string;\n}\n\n/** In-memory cache of goals */\nlet goalsCache: Goal[] | null = null;\n\n/** Load goals from disk */\nfunction loadGoals(): Goal[] {\n if (goalsCache) return goalsCache;\n\n if (!existsSync(GOALS_PATH)) {\n goalsCache = [];\n return goalsCache;\n }\n\n try {\n const raw = readFileSync(GOALS_PATH, 'utf-8');\n const store = JSON.parse(raw) as GoalsStore;\n goalsCache = store.goals || [];\n return goalsCache;\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load goals: ${(err as Error).message}`);\n goalsCache = [];\n return goalsCache;\n }\n}\n\n/** Save goals to disk */\nfunction saveGoals(): void {\n const goals = goalsCache || [];\n try {\n ensureDir(TITAN_HOME);\n const store: GoalsStore = {\n goals,\n lastUpdated: new Date().toISOString(),\n };\n writeFileSync(GOALS_PATH, JSON.stringify(store, null, 2), 'utf-8');\n } catch (err) {\n logger.error(COMPONENT, `Failed to save goals: ${(err as Error).message}`);\n }\n}\n\n/** Create a new goal */\nexport function createGoal(options: {\n title: string;\n description: string;\n priority?: number;\n schedule?: string;\n budgetLimit?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n /** Bypass rate limits and soft caps (human-initiated only). */\n force?: boolean;\n}): Goal {\n const goals = loadGoals();\n\n // ── v5.0.0: Multi-layer dedupe + runaway prevention ──────────────\n\n // 1. Exact title match against ACTIVE goals (existing v4.10 behavior)\n const existingActive = goals.find(g =>\n g.status === 'active' && g.title.trim() === options.title.trim()\n );\n if (existingActive) {\n logger.info(COMPONENT, `createGoal dedupe: \"${options.title}\" already active as ${existingActive.id} — returning existing`);\n return existingActive;\n }\n\n // 2. Fuzzy similarity match against ACTIVE goals (catches \"Publish content: X\" variants)\n const fuzzyDup = goals.find(g =>\n g.status === 'active' && titleSimilarity(g.title, options.title) >= SIMILARITY_THRESHOLD\n );\n if (fuzzyDup) {\n logger.info(COMPONENT, `createGoal fuzzy dedupe: \"${options.title}\" similar to active goal \"${fuzzyDup.title}\" (${fuzzyDup.id}) — returning existing`);\n return fuzzyDup;\n }\n\n // 3. Recent exact match against ANY status (prevents rapid re-creation of completed/failed goals)\n const cutoffMs = RECENT_DEDUPE_HOURS * 60 * 60 * 1000;\n const recentDup = goals.find(g => {\n if (g.title.trim() !== options.title.trim()) return false;\n const age = Date.now() - new Date(g.createdAt).getTime();\n return age < cutoffMs;\n });\n if (recentDup) {\n logger.info(COMPONENT, `createGoal recent dedupe: \"${options.title}\" created ${recentDup.id} within ${RECENT_DEDUPE_HOURS}h — returning existing`);\n return recentDup;\n }\n\n // 4. Hard caps\n const activeCount = goals.filter(g => g.status === 'active').length;\n if (!options.force && activeCount >= MAX_ACTIVE_GOALS) {\n logger.warn(COMPONENT, `createGoal blocked: ${activeCount} active goals >= cap ${MAX_ACTIVE_GOALS}. Use force=true to override.`);\n throw new Error(`Goal cap exceeded: ${activeCount} active goals (max ${MAX_ACTIVE_GOALS}). Close some goals first.`);\n }\n if (!options.force && goals.length >= MAX_TOTAL_GOALS) {\n logger.warn(COMPONENT, `createGoal blocked: ${goals.length} total goals >= cap ${MAX_TOTAL_GOALS}. Use force=true to override.`);\n throw new Error(`Goal cap exceeded: ${goals.length} total goals (max ${MAX_TOTAL_GOALS}). Close some goals first.`);\n }\n\n // 5. Rate limit\n const rateCheck = isRateLimited(!!options.force);\n if (rateCheck.limited) {\n logger.warn(COMPONENT, `createGoal blocked: ${rateCheck.reason}`);\n throw new Error(`Goal creation rate limited: ${rateCheck.reason}`);\n }\n\n const subtasks: Subtask[] = (options.subtasks || []).map((st, i) => ({\n id: `st-${i + 1}`,\n title: st.title,\n description: st.description,\n status: 'pending' as SubtaskStatus,\n retries: 0,\n dependsOn: st.dependsOn,\n }));\n\n // Validate no circular dependencies (DFS cycle check)\n if (subtasks.some(st => st.dependsOn?.length)) {\n const idSet = new Set(subtasks.map(st => st.id));\n const adjList = new Map<string, string[]>();\n for (const st of subtasks) {\n adjList.set(st.id, (st.dependsOn || []).filter(d => idSet.has(d)));\n }\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const hasCycle = (node: string): boolean => {\n if (inStack.has(node)) return true;\n if (visited.has(node)) return false;\n visited.add(node);\n inStack.add(node);\n for (const dep of adjList.get(node) || []) {\n if (hasCycle(dep)) return true;\n }\n inStack.delete(node);\n return false;\n };\n for (const st of subtasks) {\n if (hasCycle(st.id)) {\n throw new Error(`Circular dependency detected in subtask ${st.id}`);\n }\n }\n }\n\n const goal: Goal = {\n id: uuid().slice(0, 8),\n title: options.title,\n description: options.description,\n status: 'active',\n priority: options.priority || Math.min(goals.length + 1, 99),\n subtasks,\n schedule: options.schedule,\n budgetLimit: options.budgetLimit,\n totalCost: 0,\n progress: 0,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n tags: options.tags,\n parentGoalId: options.parentGoalId,\n };\n\n goals.push(goal);\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal created: \"${goal.title}\" (${goal.id}) with ${goal.subtasks.length} subtasks`);\n titanEvents.emit('goal:created', { goalId: goal.id, title: goal.title, subtasks: goal.subtasks.length });\n return goal;\n}\n\n/** Get all goals, optionally filtered by status */\nexport function listGoals(status?: GoalStatus): Goal[] {\n const goals = loadGoals();\n if (status) return goals.filter(g => g.status === status);\n return goals;\n}\n\n/** Get a single goal by ID */\nexport function getGoal(goalId: string): Goal | undefined {\n return loadGoals().find(g => g.id === goalId);\n}\n\n/** Update a goal's properties */\nexport function updateGoal(goalId: string, updates: {\n title?: string;\n description?: string;\n status?: GoalStatus;\n priority?: number;\n progress?: number;\n schedule?: string;\n budgetLimit?: number;\n tags?: string[];\n}): Goal | undefined {\n const goals = loadGoals();\n const goal = goals.find(g => g.id === goalId);\n if (!goal) return undefined;\n\n if (updates.title !== undefined) goal.title = updates.title;\n if (updates.description !== undefined) goal.description = updates.description;\n if (updates.status !== undefined) goal.status = updates.status;\n if (updates.priority !== undefined) goal.priority = updates.priority;\n if (updates.progress !== undefined) goal.progress = updates.progress;\n if (updates.schedule !== undefined) goal.schedule = updates.schedule;\n if (updates.budgetLimit !== undefined) goal.budgetLimit = updates.budgetLimit;\n if (updates.tags !== undefined) goal.tags = updates.tags;\n\n if (updates.status === 'completed') {\n goal.completedAt = new Date().toISOString();\n goal.progress = 100;\n }\n\n goal.updatedAt = new Date().toISOString();\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal updated: \"${goal.title}\" (${goal.id})`);\n return goal;\n}\n\n/** Delete a goal */\nexport function deleteGoal(goalId: string): boolean {\n const goals = loadGoals();\n const idx = goals.findIndex(g => g.id === goalId);\n if (idx === -1) return false;\n\n goals.splice(idx, 1);\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal deleted: ${goalId}`);\n return true;\n}\n\n/** Add a subtask to a goal */\nexport function addSubtask(goalId: string, title: string, description: string): Subtask | undefined {\n const goal = getGoal(goalId);\n if (!goal) return undefined;\n\n const subtask: Subtask = {\n id: `st-${goal.subtasks.length + 1}`,\n title,\n description,\n status: 'pending',\n retries: 0,\n };\n\n goal.subtasks.push(subtask);\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return subtask;\n}\n\n/** Complete a subtask and update goal progress */\nexport function completeSubtask(goalId: string, subtaskId: string, result: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n\n subtask.status = 'done';\n subtask.result = result;\n subtask.completedAt = new Date().toISOString();\n\n // Recalculate progress\n const done = goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').length;\n goal.progress = Math.round((done / goal.subtasks.length) * 100);\n\n // Auto-complete goal if all subtasks done\n if (goal.subtasks.every(st => st.status === 'done' || st.status === 'skipped')) {\n goal.status = 'completed';\n goal.completedAt = new Date().toISOString();\n logger.info(COMPONENT, `Goal auto-completed: \"${goal.title}\"`);\n titanEvents.emit('goal:completed', { goalId: goal.id, title: goal.title });\n } else {\n titanEvents.emit('goal:progress', { goalId: goal.id, title: goal.title, progress: goal.progress, subtaskId, result });\n }\n\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Fail a subtask (with retry logic) */\nexport function failSubtask(goalId: string, subtaskId: string, error: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n\n subtask.retries++;\n if (subtask.retries >= 3) {\n subtask.status = 'failed';\n subtask.error = error;\n titanEvents.emit('goal:failed', { goalId, subtaskId, title: subtask.title, error, retries: subtask.retries });\n } else {\n subtask.status = 'pending'; // Will retry\n }\n\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Retry a subtask: reset to pending, clear error, zero retry counter.\n * v4.1: UI path for \"Retry\" button on failed subtasks in WorkflowsPanel. */\nexport function retrySubtask(goalId: string, subtaskId: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n subtask.status = 'pending';\n subtask.error = undefined;\n subtask.retries = 0;\n subtask.completedAt = undefined;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Update a subtask's title and/or description. */\nexport function updateSubtask(\n goalId: string,\n subtaskId: string,\n updates: { title?: string; description?: string },\n): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n if (typeof updates.title === 'string') subtask.title = updates.title;\n if (typeof updates.description === 'string') subtask.description = updates.description;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Get the next ready subtasks across all active goals (sorted by priority) */\nexport function getReadyTasks(): Array<{ goal: Goal; subtask: Subtask }> {\n const goals = loadGoals()\n .filter(g => g.status === 'active')\n .sort((a, b) => a.priority - b.priority);\n\n const ready: Array<{ goal: Goal; subtask: Subtask }> = [];\n\n for (const goal of goals) {\n // Check budget\n if (goal.budgetLimit && goal.totalCost >= goal.budgetLimit) continue;\n\n // Build a set of completed subtask IDs for dependency checking\n const completedIds = new Set(\n goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').map(st => st.id)\n );\n\n for (const subtask of goal.subtasks) {\n if (subtask.status !== 'pending') continue;\n\n // Check all dependencies are satisfied\n const deps = subtask.dependsOn || [];\n const depsReady = deps.every(depId => completedIds.has(depId));\n if (depsReady) {\n ready.push({ goal, subtask });\n }\n }\n }\n\n return ready;\n}\n\n/** Record cost against a goal */\nexport function recordGoalCost(goalId: string, cost: number): void {\n const goal = getGoal(goalId);\n if (!goal) return;\n\n goal.totalCost += cost;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n}\n\n/** Get a summary of all goals for reporting */\nexport function getGoalsSummary(): string {\n const goals = loadGoals();\n if (goals.length === 0) return 'No goals defined.';\n\n const lines: string[] = ['## Goals Summary', ''];\n\n for (const goal of goals.sort((a, b) => a.priority - b.priority)) {\n const icon = goal.status === 'completed' ? '✅' : goal.status === 'active' ? '🎯' : goal.status === 'paused' ? '⏸️' : '❌';\n const done = goal.subtasks.filter(st => st.status === 'done').length;\n lines.push(`${icon} **${goal.title}** [${goal.status}] — ${done}/${goal.subtasks.length} subtasks (${goal.progress}%)`);\n if (goal.schedule) lines.push(` Schedule: ${goal.schedule}`);\n if (goal.budgetLimit) lines.push(` Budget: $${goal.totalCost.toFixed(2)} / $${goal.budgetLimit.toFixed(2)}`);\n }\n\n return lines.join('\\n');\n}\n\n/** Check if any subtasks match a given event and mark them as ready */\nexport function matchEventTriggers(eventName: string): Array<{ goal: Goal; subtask: Subtask }> {\n const goals = loadGoals().filter(g => g.status === 'active');\n const matched: Array<{ goal: Goal; subtask: Subtask }> = [];\n\n for (const goal of goals) {\n for (const subtask of goal.subtasks) {\n if (subtask.status !== 'pending') continue;\n if (!subtask.trigger || subtask.trigger.type !== 'event') continue;\n if (!subtask.trigger.event) continue;\n\n // Match exact event name or wildcard prefix (e.g., 'health:*' matches 'health:ollama:down')\n const pattern = subtask.trigger.event;\n const matches = pattern.endsWith('*')\n ? eventName.startsWith(pattern.slice(0, -1))\n : eventName === pattern;\n\n if (matches) {\n matched.push({ goal, subtask });\n logger.info(COMPONENT, `Event trigger matched: \"${subtask.title}\" (goal: ${goal.title}) on event: ${eventName}`);\n }\n }\n }\n\n return matched;\n}\n\n/** Dynamically add a subtask after another completes (for adaptive goal planning) */\nexport function addDynamicSubtask(goalId: string, afterSubtaskId: string, title: string, description: string): Subtask | undefined {\n const goal = getGoal(goalId);\n if (!goal) return undefined;\n\n const maxSubtasks = 30; // Safety cap\n if (goal.subtasks.length >= maxSubtasks) {\n logger.warn(COMPONENT, `Cannot add dynamic subtask to \"${goal.title}\" — max ${maxSubtasks} reached`);\n return undefined;\n }\n\n const subtask: Subtask = {\n id: `st-dyn-${goal.subtasks.length + 1}`,\n title,\n description,\n status: 'pending',\n retries: 0,\n dependsOn: [afterSubtaskId],\n };\n\n goal.subtasks.push(subtask);\n goal.updatedAt = new Date().toISOString();\n\n // Recalculate progress with new subtask\n const done = goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').length;\n goal.progress = Math.round((done / goal.subtasks.length) * 100);\n\n saveGoals();\n logger.info(COMPONENT, `Dynamic subtask added to \"${goal.title}\": \"${title}\" (depends on ${afterSubtaskId})`);\n titanEvents.emit('goal:subtask:added', { goalId, subtaskId: subtask.id, title, afterSubtaskId });\n return subtask;\n}\n\n/** Force reload from disk (useful after external edits) */\nexport function reloadGoals(): void {\n goalsCache = null;\n loadGoals();\n}\n\n/** v5.0.0: Bulk close duplicate goals. Keeps the newest active goal for each\n * exact title and marks the rest as failed. Returns counts for logging. */\nexport function dedupeGoalsBulk(): { scanned: number; closed: number; kept: number } {\n const goals = loadGoals();\n const seen = new Map<string, Goal>(); // title -> newest kept goal\n let closed = 0;\n\n // Sort by createdAt desc so we keep the newest\n const sorted = [...goals].sort((a, b) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n );\n\n for (const g of sorted) {\n const key = g.title.trim().toLowerCase();\n if (!seen.has(key)) {\n seen.set(key, g);\n continue;\n }\n // Duplicate — close it if active\n if (g.status === 'active') {\n g.status = 'failed';\n g.updatedAt = new Date().toISOString();\n closed++;\n logger.info(COMPONENT, `Bulk dedupe closed duplicate goal \"${g.title}\" (${g.id})`);\n }\n }\n\n if (closed > 0) {\n goalsCache = goals;\n saveGoals();\n }\n return { scanned: goals.length, closed, kept: seen.size };\n}\n"],"mappings":";AAKA,SAAS,MAAM,YAAY;AAC3B,SAAS,YAAY,cAAc,qBAAqB;AACxD,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,iBAAiB;AAC1B,SAAS,mBAAmB;AAC5B,OAAO,YAAY;AAEnB,MAAM,YAAY;AAClB,MAAM,aAAa,KAAK,YAAY,YAAY;AAChD,MAAM,YAAY,KAAK,YAAY,yBAAyB;AAG5D,MAAM,kBAAkB;AACxB,MAAM,mBAAmB;AACzB,MAAM,qBAAqB;AAC3B,MAAM,sBAAsB;AAC5B,MAAM,uBAAuB;AAG7B,SAAS,gBAAyC;AAC9C,MAAI,CAAC,WAAW,SAAS,EAAG,QAAO,EAAE,WAAW,CAAC,EAAE;AACnD,MAAI;AACA,UAAM,MAAM,aAAa,WAAW,OAAO;AAC3C,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,WAAO,EAAE,WAAW,MAAM,QAAQ,QAAQ,SAAS,IAAI,OAAO,YAAY,CAAC,EAAE;AAAA,EACjF,QAAQ;AACJ,WAAO,EAAE,WAAW,CAAC,EAAE;AAAA,EAC3B;AACJ;AAEA,SAAS,cAAc,OAAsC;AACzD,MAAI;AACA,cAAU,UAAU;AACpB,kBAAc,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EACpE,QAAQ;AAAA,EAAqB;AACjC;AAGA,SAAS,gBAAgB,GAAW,GAAmB;AACnD,QAAM,WAAW,CAAC,MAAc,IAAI;AAAA,IAChC,EAAE,YAAY,EACT,QAAQ,YAAY,GAAG,EACvB,MAAM,KAAK,EACX,OAAO,OAAK,EAAE,SAAS,CAAC;AAAA,EACjC;AACA,QAAM,KAAK,SAAS,CAAC;AACrB,QAAM,KAAK,SAAS,CAAC;AACrB,MAAI,GAAG,SAAS,KAAK,GAAG,SAAS,EAAG,QAAO;AAC3C,MAAI,eAAe;AACnB,aAAW,KAAK,GAAI,KAAI,GAAG,IAAI,CAAC,EAAG;AACnC,QAAM,QAAQ,GAAG,OAAO,GAAG,OAAO;AAClC,SAAO,UAAU,IAAI,IAAI,eAAe;AAC5C;AAGA,SAAS,cAAc,OAAuD;AAC1E,MAAI,MAAO,QAAO,EAAE,SAAS,MAAM;AACnC,QAAM,QAAQ,cAAc;AAC5B,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,SAAS,KAAK,KAAK;AACzB,QAAM,SAAS,MAAM,UAAU,OAAO,OAAK,MAAM,IAAI,KAAK,CAAC,EAAE,QAAQ,IAAI,MAAM;AAC/E,MAAI,OAAO,UAAU,oBAAoB;AACrC,WAAO,EAAE,SAAS,MAAM,QAAQ,eAAe,OAAO,MAAM,wCAAwC,kBAAkB,IAAI;AAAA,EAC9H;AACA,SAAO,MAAK,oBAAI,KAAK,GAAE,YAAY,CAAC;AACpC,gBAAc,EAAE,WAAW,OAAO,CAAC;AACnC,SAAO,EAAE,SAAS,MAAM;AAC5B;AAuDA,IAAI,aAA4B;AAGhC,SAAS,YAAoB;AACzB,MAAI,WAAY,QAAO;AAEvB,MAAI,CAAC,WAAW,UAAU,GAAG;AACzB,iBAAa,CAAC;AACd,WAAO;AAAA,EACX;AAEA,MAAI;AACA,UAAM,MAAM,aAAa,YAAY,OAAO;AAC5C,UAAM,QAAQ,KAAK,MAAM,GAAG;AAC5B,iBAAa,MAAM,SAAS,CAAC;AAC7B,WAAO;AAAA,EACX,SAAS,KAAK;AACV,WAAO,KAAK,WAAW,yBAA0B,IAAc,OAAO,EAAE;AACxE,iBAAa,CAAC;AACd,WAAO;AAAA,EACX;AACJ;AAGA,SAAS,YAAkB;AACvB,QAAM,QAAQ,cAAc,CAAC;AAC7B,MAAI;AACA,cAAU,UAAU;AACpB,UAAM,QAAoB;AAAA,MACtB;AAAA,MACA,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,IACxC;AACA,kBAAc,YAAY,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EACrE,SAAS,KAAK;AACV,WAAO,MAAM,WAAW,yBAA0B,IAAc,OAAO,EAAE;AAAA,EAC7E;AACJ;AAGO,SAAS,WAAW,SAWlB;AACL,QAAM,QAAQ,UAAU;AAKxB,QAAM,iBAAiB,MAAM;AAAA,IAAK,OAC9B,EAAE,WAAW,YAAY,EAAE,MAAM,KAAK,MAAM,QAAQ,MAAM,KAAK;AAAA,EACnE;AACA,MAAI,gBAAgB;AAChB,WAAO,KAAK,WAAW,uBAAuB,QAAQ,KAAK,uBAAuB,eAAe,EAAE,4BAAuB;AAC1H,WAAO;AAAA,EACX;AAGA,QAAM,WAAW,MAAM;AAAA,IAAK,OACxB,EAAE,WAAW,YAAY,gBAAgB,EAAE,OAAO,QAAQ,KAAK,KAAK;AAAA,EACxE;AACA,MAAI,UAAU;AACV,WAAO,KAAK,WAAW,6BAA6B,QAAQ,KAAK,6BAA6B,SAAS,KAAK,MAAM,SAAS,EAAE,6BAAwB;AACrJ,WAAO;AAAA,EACX;AAGA,QAAM,WAAW,sBAAsB,KAAK,KAAK;AACjD,QAAM,YAAY,MAAM,KAAK,OAAK;AAC9B,QAAI,EAAE,MAAM,KAAK,MAAM,QAAQ,MAAM,KAAK,EAAG,QAAO;AACpD,UAAM,MAAM,KAAK,IAAI,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AACvD,WAAO,MAAM;AAAA,EACjB,CAAC;AACD,MAAI,WAAW;AACX,WAAO,KAAK,WAAW,8BAA8B,QAAQ,KAAK,aAAa,UAAU,EAAE,WAAW,mBAAmB,6BAAwB;AACjJ,WAAO;AAAA,EACX;AAGA,QAAM,cAAc,MAAM,OAAO,OAAK,EAAE,WAAW,QAAQ,EAAE;AAC7D,MAAI,CAAC,QAAQ,SAAS,eAAe,kBAAkB;AACnD,WAAO,KAAK,WAAW,uBAAuB,WAAW,wBAAwB,gBAAgB,+BAA+B;AAChI,UAAM,IAAI,MAAM,sBAAsB,WAAW,sBAAsB,gBAAgB,4BAA4B;AAAA,EACvH;AACA,MAAI,CAAC,QAAQ,SAAS,MAAM,UAAU,iBAAiB;AACnD,WAAO,KAAK,WAAW,uBAAuB,MAAM,MAAM,uBAAuB,eAAe,+BAA+B;AAC/H,UAAM,IAAI,MAAM,sBAAsB,MAAM,MAAM,qBAAqB,eAAe,4BAA4B;AAAA,EACtH;AAGA,QAAM,YAAY,cAAc,CAAC,CAAC,QAAQ,KAAK;AAC/C,MAAI,UAAU,SAAS;AACnB,WAAO,KAAK,WAAW,uBAAuB,UAAU,MAAM,EAAE;AAChE,UAAM,IAAI,MAAM,+BAA+B,UAAU,MAAM,EAAE;AAAA,EACrE;AAEA,QAAM,YAAuB,QAAQ,YAAY,CAAC,GAAG,IAAI,CAAC,IAAI,OAAO;AAAA,IACjE,IAAI,MAAM,IAAI,CAAC;AAAA,IACf,OAAO,GAAG;AAAA,IACV,aAAa,GAAG;AAAA,IAChB,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW,GAAG;AAAA,EAClB,EAAE;AAGF,MAAI,SAAS,KAAK,QAAM,GAAG,WAAW,MAAM,GAAG;AAC3C,UAAM,QAAQ,IAAI,IAAI,SAAS,IAAI,QAAM,GAAG,EAAE,CAAC;AAC/C,UAAM,UAAU,oBAAI,IAAsB;AAC1C,eAAW,MAAM,UAAU;AACvB,cAAQ,IAAI,GAAG,KAAK,GAAG,aAAa,CAAC,GAAG,OAAO,OAAK,MAAM,IAAI,CAAC,CAAC,CAAC;AAAA,IACrE;AACA,UAAM,UAAU,oBAAI,IAAY;AAChC,UAAM,UAAU,oBAAI,IAAY;AAChC,UAAM,WAAW,CAAC,SAA0B;AACxC,UAAI,QAAQ,IAAI,IAAI,EAAG,QAAO;AAC9B,UAAI,QAAQ,IAAI,IAAI,EAAG,QAAO;AAC9B,cAAQ,IAAI,IAAI;AAChB,cAAQ,IAAI,IAAI;AAChB,iBAAW,OAAO,QAAQ,IAAI,IAAI,KAAK,CAAC,GAAG;AACvC,YAAI,SAAS,GAAG,EAAG,QAAO;AAAA,MAC9B;AACA,cAAQ,OAAO,IAAI;AACnB,aAAO;AAAA,IACX;AACA,eAAW,MAAM,UAAU;AACvB,UAAI,SAAS,GAAG,EAAE,GAAG;AACjB,cAAM,IAAI,MAAM,2CAA2C,GAAG,EAAE,EAAE;AAAA,MACtE;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,OAAa;AAAA,IACf,IAAI,KAAK,EAAE,MAAM,GAAG,CAAC;AAAA,IACrB,OAAO,QAAQ;AAAA,IACf,aAAa,QAAQ;AAAA,IACrB,QAAQ;AAAA,IACR,UAAU,QAAQ,YAAY,KAAK,IAAI,MAAM,SAAS,GAAG,EAAE;AAAA,IAC3D;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,aAAa,QAAQ;AAAA,IACrB,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,MAAM,QAAQ;AAAA,IACd,cAAc,QAAQ;AAAA,EAC1B;AAEA,QAAM,KAAK,IAAI;AACf,eAAa;AACb,YAAU;AAEV,SAAO,KAAK,WAAW,kBAAkB,KAAK,KAAK,MAAM,KAAK,EAAE,UAAU,KAAK,SAAS,MAAM,WAAW;AACzG,cAAY,KAAK,gBAAgB,EAAE,QAAQ,KAAK,IAAI,OAAO,KAAK,OAAO,UAAU,KAAK,SAAS,OAAO,CAAC;AACvG,SAAO;AACX;AAGO,SAAS,UAAU,QAA6B;AACnD,QAAM,QAAQ,UAAU;AACxB,MAAI,OAAQ,QAAO,MAAM,OAAO,OAAK,EAAE,WAAW,MAAM;AACxD,SAAO;AACX;AAGO,SAAS,QAAQ,QAAkC;AACtD,SAAO,UAAU,EAAE,KAAK,OAAK,EAAE,OAAO,MAAM;AAChD;AAGO,SAAS,WAAW,QAAgB,SAStB;AACjB,QAAM,QAAQ,UAAU;AACxB,QAAM,OAAO,MAAM,KAAK,OAAK,EAAE,OAAO,MAAM;AAC5C,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,QAAQ,UAAU,OAAW,MAAK,QAAQ,QAAQ;AACtD,MAAI,QAAQ,gBAAgB,OAAW,MAAK,cAAc,QAAQ;AAClE,MAAI,QAAQ,WAAW,OAAW,MAAK,SAAS,QAAQ;AACxD,MAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,MAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,MAAI,QAAQ,aAAa,OAAW,MAAK,WAAW,QAAQ;AAC5D,MAAI,QAAQ,gBAAgB,OAAW,MAAK,cAAc,QAAQ;AAClE,MAAI,QAAQ,SAAS,OAAW,MAAK,OAAO,QAAQ;AAEpD,MAAI,QAAQ,WAAW,aAAa;AAChC,SAAK,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC1C,SAAK,WAAW;AAAA,EACpB;AAEA,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,eAAa;AACb,YAAU;AAEV,SAAO,KAAK,WAAW,kBAAkB,KAAK,KAAK,MAAM,KAAK,EAAE,GAAG;AACnE,SAAO;AACX;AAGO,SAAS,WAAW,QAAyB;AAChD,QAAM,QAAQ,UAAU;AACxB,QAAM,MAAM,MAAM,UAAU,OAAK,EAAE,OAAO,MAAM;AAChD,MAAI,QAAQ,GAAI,QAAO;AAEvB,QAAM,OAAO,KAAK,CAAC;AACnB,eAAa;AACb,YAAU;AAEV,SAAO,KAAK,WAAW,iBAAiB,MAAM,EAAE;AAChD,SAAO;AACX;AAGO,SAAS,WAAW,QAAgB,OAAe,aAA0C;AAChG,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAmB;AAAA,IACrB,IAAI,MAAM,KAAK,SAAS,SAAS,CAAC;AAAA,IAClC;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,SAAS;AAAA,EACb;AAEA,OAAK,SAAS,KAAK,OAAO;AAC1B,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACV,SAAO;AACX;AAGO,SAAS,gBAAgB,QAAgB,WAAmB,QAAyB;AACxF,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAU,KAAK,SAAS,KAAK,QAAM,GAAG,OAAO,SAAS;AAC5D,MAAI,CAAC,QAAS,QAAO;AAErB,UAAQ,SAAS;AACjB,UAAQ,SAAS;AACjB,UAAQ,eAAc,oBAAI,KAAK,GAAE,YAAY;AAG7C,QAAM,OAAO,KAAK,SAAS,OAAO,QAAM,GAAG,WAAW,UAAU,GAAG,WAAW,SAAS,EAAE;AACzF,OAAK,WAAW,KAAK,MAAO,OAAO,KAAK,SAAS,SAAU,GAAG;AAG9D,MAAI,KAAK,SAAS,MAAM,QAAM,GAAG,WAAW,UAAU,GAAG,WAAW,SAAS,GAAG;AAC5E,SAAK,SAAS;AACd,SAAK,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC1C,WAAO,KAAK,WAAW,yBAAyB,KAAK,KAAK,GAAG;AAC7D,gBAAY,KAAK,kBAAkB,EAAE,QAAQ,KAAK,IAAI,OAAO,KAAK,MAAM,CAAC;AAAA,EAC7E,OAAO;AACH,gBAAY,KAAK,iBAAiB,EAAE,QAAQ,KAAK,IAAI,OAAO,KAAK,OAAO,UAAU,KAAK,UAAU,WAAW,OAAO,CAAC;AAAA,EACxH;AAEA,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACV,SAAO;AACX;AAGO,SAAS,YAAY,QAAgB,WAAmB,OAAwB;AACnF,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,UAAU,KAAK,SAAS,KAAK,QAAM,GAAG,OAAO,SAAS;AAC5D,MAAI,CAAC,QAAS,QAAO;AAErB,UAAQ;AACR,MAAI,QAAQ,WAAW,GAAG;AACtB,YAAQ,SAAS;AACjB,YAAQ,QAAQ;AAChB,gBAAY,KAAK,eAAe,EAAE,QAAQ,WAAW,OAAO,QAAQ,OAAO,OAAO,SAAS,QAAQ,QAAQ,CAAC;AAAA,EAChH,OAAO;AACH,YAAQ,SAAS;AAAA,EACrB;AAEA,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACV,SAAO;AACX;AAIO,SAAS,aAAa,QAAgB,WAA4B;AACrE,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,SAAS,KAAK,QAAM,GAAG,OAAO,SAAS;AAC5D,MAAI,CAAC,QAAS,QAAO;AACrB,UAAQ,SAAS;AACjB,UAAQ,QAAQ;AAChB,UAAQ,UAAU;AAClB,UAAQ,cAAc;AACtB,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACV,SAAO;AACX;AAGO,SAAS,cACZ,QACA,WACA,SACO;AACP,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,UAAU,KAAK,SAAS,KAAK,QAAM,GAAG,OAAO,SAAS;AAC5D,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO,QAAQ,UAAU,SAAU,SAAQ,QAAQ,QAAQ;AAC/D,MAAI,OAAO,QAAQ,gBAAgB,SAAU,SAAQ,cAAc,QAAQ;AAC3E,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACV,SAAO;AACX;AAGO,SAAS,gBAAyD;AACrE,QAAM,QAAQ,UAAU,EACnB,OAAO,OAAK,EAAE,WAAW,QAAQ,EACjC,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAE3C,QAAM,QAAiD,CAAC;AAExD,aAAW,QAAQ,OAAO;AAEtB,QAAI,KAAK,eAAe,KAAK,aAAa,KAAK,YAAa;AAG5D,UAAM,eAAe,IAAI;AAAA,MACrB,KAAK,SAAS,OAAO,QAAM,GAAG,WAAW,UAAU,GAAG,WAAW,SAAS,EAAE,IAAI,QAAM,GAAG,EAAE;AAAA,IAC/F;AAEA,eAAW,WAAW,KAAK,UAAU;AACjC,UAAI,QAAQ,WAAW,UAAW;AAGlC,YAAM,OAAO,QAAQ,aAAa,CAAC;AACnC,YAAM,YAAY,KAAK,MAAM,WAAS,aAAa,IAAI,KAAK,CAAC;AAC7D,UAAI,WAAW;AACX,cAAM,KAAK,EAAE,MAAM,QAAQ,CAAC;AAAA,MAChC;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAGO,SAAS,eAAe,QAAgB,MAAoB;AAC/D,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM;AAEX,OAAK,aAAa;AAClB,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AACxC,YAAU;AACd;AAGO,SAAS,kBAA0B;AACtC,QAAM,QAAQ,UAAU;AACxB,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,QAAM,QAAkB,CAAC,oBAAoB,EAAE;AAE/C,aAAW,QAAQ,MAAM,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,GAAG;AAC9D,UAAM,OAAO,KAAK,WAAW,cAAc,WAAM,KAAK,WAAW,WAAW,cAAO,KAAK,WAAW,WAAW,iBAAO;AACrH,UAAM,OAAO,KAAK,SAAS,OAAO,QAAM,GAAG,WAAW,MAAM,EAAE;AAC9D,UAAM,KAAK,GAAG,IAAI,MAAM,KAAK,KAAK,OAAO,KAAK,MAAM,YAAO,IAAI,IAAI,KAAK,SAAS,MAAM,cAAc,KAAK,QAAQ,IAAI;AACtH,QAAI,KAAK,SAAU,OAAM,KAAK,gBAAgB,KAAK,QAAQ,EAAE;AAC7D,QAAI,KAAK,YAAa,OAAM,KAAK,eAAe,KAAK,UAAU,QAAQ,CAAC,CAAC,OAAO,KAAK,YAAY,QAAQ,CAAC,CAAC,EAAE;AAAA,EACjH;AAEA,SAAO,MAAM,KAAK,IAAI;AAC1B;AAGO,SAAS,mBAAmB,WAA4D;AAC3F,QAAM,QAAQ,UAAU,EAAE,OAAO,OAAK,EAAE,WAAW,QAAQ;AAC3D,QAAM,UAAmD,CAAC;AAE1D,aAAW,QAAQ,OAAO;AACtB,eAAW,WAAW,KAAK,UAAU;AACjC,UAAI,QAAQ,WAAW,UAAW;AAClC,UAAI,CAAC,QAAQ,WAAW,QAAQ,QAAQ,SAAS,QAAS;AAC1D,UAAI,CAAC,QAAQ,QAAQ,MAAO;AAG5B,YAAM,UAAU,QAAQ,QAAQ;AAChC,YAAM,UAAU,QAAQ,SAAS,GAAG,IAC9B,UAAU,WAAW,QAAQ,MAAM,GAAG,EAAE,CAAC,IACzC,cAAc;AAEpB,UAAI,SAAS;AACT,gBAAQ,KAAK,EAAE,MAAM,QAAQ,CAAC;AAC9B,eAAO,KAAK,WAAW,2BAA2B,QAAQ,KAAK,YAAY,KAAK,KAAK,eAAe,SAAS,EAAE;AAAA,MACnH;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAGO,SAAS,kBAAkB,QAAgB,gBAAwB,OAAe,aAA0C;AAC/H,QAAM,OAAO,QAAQ,MAAM;AAC3B,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,cAAc;AACpB,MAAI,KAAK,SAAS,UAAU,aAAa;AACrC,WAAO,KAAK,WAAW,kCAAkC,KAAK,KAAK,gBAAW,WAAW,UAAU;AACnG,WAAO;AAAA,EACX;AAEA,QAAM,UAAmB;AAAA,IACrB,IAAI,UAAU,KAAK,SAAS,SAAS,CAAC;AAAA,IACtC;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW,CAAC,cAAc;AAAA,EAC9B;AAEA,OAAK,SAAS,KAAK,OAAO;AAC1B,OAAK,aAAY,oBAAI,KAAK,GAAE,YAAY;AAGxC,QAAM,OAAO,KAAK,SAAS,OAAO,QAAM,GAAG,WAAW,UAAU,GAAG,WAAW,SAAS,EAAE;AACzF,OAAK,WAAW,KAAK,MAAO,OAAO,KAAK,SAAS,SAAU,GAAG;AAE9D,YAAU;AACV,SAAO,KAAK,WAAW,6BAA6B,KAAK,KAAK,OAAO,KAAK,iBAAiB,cAAc,GAAG;AAC5G,cAAY,KAAK,sBAAsB,EAAE,QAAQ,WAAW,QAAQ,IAAI,OAAO,eAAe,CAAC;AAC/F,SAAO;AACX;AAGO,SAAS,cAAoB;AAChC,eAAa;AACb,YAAU;AACd;AAIO,SAAS,kBAAqE;AACjF,QAAM,QAAQ,UAAU;AACxB,QAAM,OAAO,oBAAI,IAAkB;AACnC,MAAI,SAAS;AAGb,QAAM,SAAS,CAAC,GAAG,KAAK,EAAE;AAAA,IAAK,CAAC,GAAG,MAC/B,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,EACpE;AAEA,aAAW,KAAK,QAAQ;AACpB,UAAM,MAAM,EAAE,MAAM,KAAK,EAAE,YAAY;AACvC,QAAI,CAAC,KAAK,IAAI,GAAG,GAAG;AAChB,WAAK,IAAI,KAAK,CAAC;AACf;AAAA,IACJ;AAEA,QAAI,EAAE,WAAW,UAAU;AACvB,QAAE,SAAS;AACX,QAAE,aAAY,oBAAI,KAAK,GAAE,YAAY;AACrC;AACA,aAAO,KAAK,WAAW,sCAAsC,EAAE,KAAK,MAAM,EAAE,EAAE,GAAG;AAAA,IACrF;AAAA,EACJ;AAEA,MAAI,SAAS,GAAG;AACZ,iBAAa;AACb,cAAU;AAAA,EACd;AACA,SAAO,EAAE,SAAS,MAAM,QAAQ,QAAQ,MAAM,KAAK,KAAK;AAC5D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/goals.ts"],"sourcesContent":["/**\n * TITAN — Goal Management System\n * Persistent goals with subtasks, scheduling, budget tracking, and progress monitoring.\n * Goals drive the autopilot system — each cycle picks the next actionable subtask.\n */\nimport { v4 as uuid } from 'uuid';\nimport { existsSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { titanEvents } from './daemon.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'Goals';\nconst GOALS_PATH = join(TITAN_HOME, 'goals.json');\nconst RATE_PATH = join(TITAN_HOME, 'goal-creation-rate.json');\n\n/** Safety limits — prevent runaway goal proliferation (SOMA or agent loops). */\nconst MAX_TOTAL_GOALS = 150;\nconst MAX_ACTIVE_GOALS = 50;\nconst MAX_GOALS_PER_HOUR = 10;\nconst RECENT_DEDUPE_HOURS = 24;\nconst SIMILARITY_THRESHOLD = 0.82; // Jaccard — catches \"Publish content: AI agents\" vs \"Publish content: tech\"\n\n/** Load rate-limit state from disk. */\nfunction loadRateState(): { creations: string[] } {\n if (!existsSync(RATE_PATH)) return { creations: [] };\n try {\n const raw = readFileSync(RATE_PATH, 'utf-8');\n const parsed = JSON.parse(raw) as { creations?: string[] };\n return { creations: Array.isArray(parsed?.creations) ? parsed.creations : [] };\n } catch {\n return { creations: [] };\n }\n}\n\nfunction saveRateState(state: { creations: string[] }): void {\n try {\n mkdirIfNotExists(TITAN_HOME);\n writeFileSync(RATE_PATH, JSON.stringify(state, null, 2), 'utf-8');\n } catch { /* non-critical */ }\n}\n\n/** Jaccard similarity for fuzzy dedupe. 0–1, higher = more similar. */\nfunction titleSimilarity(a: string, b: string): number {\n const tokenize = (s: string) => new Set(\n s.toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(w => w.length > 2)\n );\n const ta = tokenize(a);\n const tb = tokenize(b);\n if (ta.size === 0 || tb.size === 0) return 0;\n let intersection = 0;\n for (const t of ta) if (tb.has(t)) intersection++;\n const union = ta.size + tb.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/** Returns true if we should block creation due to rate limits. */\nfunction isRateLimited(force: boolean): { limited: boolean; reason?: string } {\n if (force) return { limited: false };\n const state = loadRateState();\n const now = Date.now();\n const hourMs = 60 * 60 * 1000;\n const recent = state.creations.filter(t => now - new Date(t).getTime() < hourMs);\n if (recent.length >= MAX_GOALS_PER_HOUR) {\n return { limited: true, reason: `rate limit: ${recent.length} goals created in the last hour (max ${MAX_GOALS_PER_HOUR})` };\n }\n recent.push(new Date().toISOString());\n saveRateState({ creations: recent });\n return { limited: false };\n}\n\nexport type GoalStatus = 'active' | 'paused' | 'completed' | 'failed';\nexport type SubtaskStatus = 'pending' | 'running' | 'done' | 'failed' | 'skipped';\n\nexport interface SubtaskTrigger {\n type: 'schedule' | 'event' | 'dependency' | 'manual';\n /** Event name to match (e.g., 'health:ollama:down', 'cron:stuck') */\n event?: string;\n /** Cron expression for scheduled triggers */\n schedule?: string;\n /** LLM-evaluated condition (e.g., \"when error rate exceeds 50%\") */\n condition?: string;\n}\n\nexport interface Subtask {\n id: string;\n title: string;\n description: string;\n status: SubtaskStatus;\n result?: string;\n error?: string;\n completedAt?: string;\n retries: number;\n /** Subtask IDs within the same goal that must complete before this one can start */\n dependsOn?: string[];\n /** Optional trigger — when set, subtask activates on matching events instead of linearly */\n trigger?: SubtaskTrigger;\n}\n\nexport interface Goal {\n id: string;\n title: string;\n description: string;\n status: GoalStatus;\n priority: number; // 1 = highest\n subtasks: Subtask[];\n schedule?: string; // cron expression (e.g., \"0 9 * * 1,4\" for Mon+Thu 9am)\n budgetLimit?: number; // max USD spend for this goal\n totalCost: number;\n progress: number; // 0-100 percentage\n createdAt: string;\n updatedAt: string;\n completedAt?: string;\n tags?: string[];\n /** Parent goal ID for ancestry chain (Command Post) */\n parentGoalId?: string;\n}\n\ninterface GoalsStore {\n goals: Goal[];\n lastUpdated: string;\n}\n\n/** In-memory cache of goals */\nlet goalsCache: Goal[] | null = null;\n\n/** Load goals from disk */\nfunction loadGoals(): Goal[] {\n if (goalsCache) return goalsCache;\n\n if (!existsSync(GOALS_PATH)) {\n goalsCache = [];\n return goalsCache;\n }\n\n try {\n const raw = readFileSync(GOALS_PATH, 'utf-8');\n const store = JSON.parse(raw) as GoalsStore;\n goalsCache = store.goals || [];\n return goalsCache;\n } catch (err) {\n logger.warn(COMPONENT, `Failed to load goals: ${(err as Error).message}`);\n goalsCache = [];\n return goalsCache;\n }\n}\n\n/** Save goals to disk */\nfunction saveGoals(): void {\n const goals = goalsCache || [];\n try {\n mkdirIfNotExists(TITAN_HOME);\n const store: GoalsStore = {\n goals,\n lastUpdated: new Date().toISOString(),\n };\n writeFileSync(GOALS_PATH, JSON.stringify(store, null, 2), 'utf-8');\n } catch (err) {\n logger.error(COMPONENT, `Failed to save goals: ${(err as Error).message}`);\n }\n}\n\n/** Create a new goal */\nexport function createGoal(options: {\n title: string;\n description: string;\n priority?: number;\n schedule?: string;\n budgetLimit?: number;\n tags?: string[];\n parentGoalId?: string;\n subtasks?: Array<{ title: string; description: string; dependsOn?: string[] }>;\n /** Bypass rate limits and soft caps (human-initiated only). */\n force?: boolean;\n}): Goal {\n const goals = loadGoals();\n\n // ── v5.0.0: Multi-layer dedupe + runaway prevention ──────────────\n\n // 1. Exact title match against ACTIVE goals (existing v4.10 behavior)\n const existingActive = goals.find(g =>\n g.status === 'active' && g.title.trim() === options.title.trim()\n );\n if (existingActive) {\n logger.info(COMPONENT, `createGoal dedupe: \"${options.title}\" already active as ${existingActive.id} — returning existing`);\n return existingActive;\n }\n\n // 2. Fuzzy similarity match against ACTIVE goals (catches \"Publish content: X\" variants)\n const fuzzyDup = goals.find(g =>\n g.status === 'active' && titleSimilarity(g.title, options.title) >= SIMILARITY_THRESHOLD\n );\n if (fuzzyDup) {\n logger.info(COMPONENT, `createGoal fuzzy dedupe: \"${options.title}\" similar to active goal \"${fuzzyDup.title}\" (${fuzzyDup.id}) — returning existing`);\n return fuzzyDup;\n }\n\n // 3. Recent exact match against ANY status (prevents rapid re-creation of completed/failed goals)\n const cutoffMs = RECENT_DEDUPE_HOURS * 60 * 60 * 1000;\n const recentDup = goals.find(g => {\n if (g.title.trim() !== options.title.trim()) return false;\n const age = Date.now() - new Date(g.createdAt).getTime();\n return age < cutoffMs;\n });\n if (recentDup) {\n logger.info(COMPONENT, `createGoal recent dedupe: \"${options.title}\" created ${recentDup.id} within ${RECENT_DEDUPE_HOURS}h — returning existing`);\n return recentDup;\n }\n\n // 4. Hard caps\n const activeCount = goals.filter(g => g.status === 'active').length;\n if (!options.force && activeCount >= MAX_ACTIVE_GOALS) {\n logger.warn(COMPONENT, `createGoal blocked: ${activeCount} active goals >= cap ${MAX_ACTIVE_GOALS}. Use force=true to override.`);\n throw new Error(`Goal cap exceeded: ${activeCount} active goals (max ${MAX_ACTIVE_GOALS}). Close some goals first.`);\n }\n if (!options.force && goals.length >= MAX_TOTAL_GOALS) {\n logger.warn(COMPONENT, `createGoal blocked: ${goals.length} total goals >= cap ${MAX_TOTAL_GOALS}. Use force=true to override.`);\n throw new Error(`Goal cap exceeded: ${goals.length} total goals (max ${MAX_TOTAL_GOALS}). Close some goals first.`);\n }\n\n // 5. Rate limit\n const rateCheck = isRateLimited(!!options.force);\n if (rateCheck.limited) {\n logger.warn(COMPONENT, `createGoal blocked: ${rateCheck.reason}`);\n throw new Error(`Goal creation rate limited: ${rateCheck.reason}`);\n }\n\n const subtasks: Subtask[] = (options.subtasks || []).map((st, i) => ({\n id: `st-${i + 1}`,\n title: st.title,\n description: st.description,\n status: 'pending' as SubtaskStatus,\n retries: 0,\n dependsOn: st.dependsOn,\n }));\n\n // Validate no circular dependencies (DFS cycle check)\n if (subtasks.some(st => st.dependsOn?.length)) {\n const idSet = new Set(subtasks.map(st => st.id));\n const adjList = new Map<string, string[]>();\n for (const st of subtasks) {\n adjList.set(st.id, (st.dependsOn || []).filter(d => idSet.has(d)));\n }\n const visited = new Set<string>();\n const inStack = new Set<string>();\n const hasCycle = (node: string): boolean => {\n if (inStack.has(node)) return true;\n if (visited.has(node)) return false;\n visited.add(node);\n inStack.add(node);\n for (const dep of adjList.get(node) || []) {\n if (hasCycle(dep)) return true;\n }\n inStack.delete(node);\n return false;\n };\n for (const st of subtasks) {\n if (hasCycle(st.id)) {\n throw new Error(`Circular dependency detected in subtask ${st.id}`);\n }\n }\n }\n\n const goal: Goal = {\n id: uuid().slice(0, 8),\n title: options.title,\n description: options.description,\n status: 'active',\n priority: options.priority || Math.min(goals.length + 1, 99),\n subtasks,\n schedule: options.schedule,\n budgetLimit: options.budgetLimit,\n totalCost: 0,\n progress: 0,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n tags: options.tags,\n parentGoalId: options.parentGoalId,\n };\n\n goals.push(goal);\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal created: \"${goal.title}\" (${goal.id}) with ${goal.subtasks.length} subtasks`);\n titanEvents.emit('goal:created', { goalId: goal.id, title: goal.title, subtasks: goal.subtasks.length });\n return goal;\n}\n\n/** Get all goals, optionally filtered by status */\nexport function listGoals(status?: GoalStatus): Goal[] {\n const goals = loadGoals();\n if (status) return goals.filter(g => g.status === status);\n return goals;\n}\n\n/** Get a single goal by ID */\nexport function getGoal(goalId: string): Goal | undefined {\n return loadGoals().find(g => g.id === goalId);\n}\n\n/** Update a goal's properties */\nexport function updateGoal(goalId: string, updates: {\n title?: string;\n description?: string;\n status?: GoalStatus;\n priority?: number;\n progress?: number;\n schedule?: string;\n budgetLimit?: number;\n tags?: string[];\n}): Goal | undefined {\n const goals = loadGoals();\n const goal = goals.find(g => g.id === goalId);\n if (!goal) return undefined;\n\n if (updates.title !== undefined) goal.title = updates.title;\n if (updates.description !== undefined) goal.description = updates.description;\n if (updates.status !== undefined) goal.status = updates.status;\n if (updates.priority !== undefined) goal.priority = updates.priority;\n if (updates.progress !== undefined) goal.progress = updates.progress;\n if (updates.schedule !== undefined) goal.schedule = updates.schedule;\n if (updates.budgetLimit !== undefined) goal.budgetLimit = updates.budgetLimit;\n if (updates.tags !== undefined) goal.tags = updates.tags;\n\n if (updates.status === 'completed') {\n goal.completedAt = new Date().toISOString();\n goal.progress = 100;\n }\n\n goal.updatedAt = new Date().toISOString();\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal updated: \"${goal.title}\" (${goal.id})`);\n return goal;\n}\n\n/** Delete a goal */\nexport function deleteGoal(goalId: string): boolean {\n const goals = loadGoals();\n const idx = goals.findIndex(g => g.id === goalId);\n if (idx === -1) return false;\n\n goals.splice(idx, 1);\n goalsCache = goals;\n saveGoals();\n\n logger.info(COMPONENT, `Goal deleted: ${goalId}`);\n return true;\n}\n\n/** Add a subtask to a goal */\nexport function addSubtask(goalId: string, title: string, description: string): Subtask | undefined {\n const goal = getGoal(goalId);\n if (!goal) return undefined;\n\n const subtask: Subtask = {\n id: `st-${goal.subtasks.length + 1}`,\n title,\n description,\n status: 'pending',\n retries: 0,\n };\n\n goal.subtasks.push(subtask);\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return subtask;\n}\n\n/** Complete a subtask and update goal progress */\nexport function completeSubtask(goalId: string, subtaskId: string, result: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n\n subtask.status = 'done';\n subtask.result = result;\n subtask.completedAt = new Date().toISOString();\n\n // Recalculate progress\n const done = goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').length;\n goal.progress = Math.round((done / goal.subtasks.length) * 100);\n\n // Auto-complete goal if all subtasks done\n if (goal.subtasks.every(st => st.status === 'done' || st.status === 'skipped')) {\n goal.status = 'completed';\n goal.completedAt = new Date().toISOString();\n logger.info(COMPONENT, `Goal auto-completed: \"${goal.title}\"`);\n titanEvents.emit('goal:completed', { goalId: goal.id, title: goal.title });\n } else {\n titanEvents.emit('goal:progress', { goalId: goal.id, title: goal.title, progress: goal.progress, subtaskId, result });\n }\n\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Fail a subtask (with retry logic) */\nexport function failSubtask(goalId: string, subtaskId: string, error: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n\n subtask.retries++;\n if (subtask.retries >= 3) {\n subtask.status = 'failed';\n subtask.error = error;\n titanEvents.emit('goal:failed', { goalId, subtaskId, title: subtask.title, error, retries: subtask.retries });\n } else {\n subtask.status = 'pending'; // Will retry\n }\n\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Retry a subtask: reset to pending, clear error, zero retry counter.\n * v4.1: UI path for \"Retry\" button on failed subtasks in WorkflowsPanel. */\nexport function retrySubtask(goalId: string, subtaskId: string): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n subtask.status = 'pending';\n subtask.error = undefined;\n subtask.retries = 0;\n subtask.completedAt = undefined;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Update a subtask's title and/or description. */\nexport function updateSubtask(\n goalId: string,\n subtaskId: string,\n updates: { title?: string; description?: string },\n): boolean {\n const goal = getGoal(goalId);\n if (!goal) return false;\n const subtask = goal.subtasks.find(st => st.id === subtaskId);\n if (!subtask) return false;\n if (typeof updates.title === 'string') subtask.title = updates.title;\n if (typeof updates.description === 'string') subtask.description = updates.description;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n return true;\n}\n\n/** Get the next ready subtasks across all active goals (sorted by priority) */\nexport function getReadyTasks(): Array<{ goal: Goal; subtask: Subtask }> {\n const goals = loadGoals()\n .filter(g => g.status === 'active')\n .sort((a, b) => a.priority - b.priority);\n\n const ready: Array<{ goal: Goal; subtask: Subtask }> = [];\n\n for (const goal of goals) {\n // Check budget\n if (goal.budgetLimit && goal.totalCost >= goal.budgetLimit) continue;\n\n // Build a set of completed subtask IDs for dependency checking\n const completedIds = new Set(\n goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').map(st => st.id)\n );\n\n for (const subtask of goal.subtasks) {\n if (subtask.status !== 'pending') continue;\n\n // Check all dependencies are satisfied\n const deps = subtask.dependsOn || [];\n const depsReady = deps.every(depId => completedIds.has(depId));\n if (depsReady) {\n ready.push({ goal, subtask });\n }\n }\n }\n\n return ready;\n}\n\n/** Record cost against a goal */\nexport function recordGoalCost(goalId: string, cost: number): void {\n const goal = getGoal(goalId);\n if (!goal) return;\n\n goal.totalCost += cost;\n goal.updatedAt = new Date().toISOString();\n saveGoals();\n}\n\n/** Get a summary of all goals for reporting */\nexport function getGoalsSummary(): string {\n const goals = loadGoals();\n if (goals.length === 0) return 'No goals defined.';\n\n const lines: string[] = ['## Goals Summary', ''];\n\n for (const goal of goals.sort((a, b) => a.priority - b.priority)) {\n const icon = goal.status === 'completed' ? '✅' : goal.status === 'active' ? '🎯' : goal.status === 'paused' ? '⏸️' : '❌';\n const done = goal.subtasks.filter(st => st.status === 'done').length;\n lines.push(`${icon} **${goal.title}** [${goal.status}] — ${done}/${goal.subtasks.length} subtasks (${goal.progress}%)`);\n if (goal.schedule) lines.push(` Schedule: ${goal.schedule}`);\n if (goal.budgetLimit) lines.push(` Budget: $${goal.totalCost.toFixed(2)} / $${goal.budgetLimit.toFixed(2)}`);\n }\n\n return lines.join('\\n');\n}\n\n/** Check if any subtasks match a given event and mark them as ready */\nexport function matchEventTriggers(eventName: string): Array<{ goal: Goal; subtask: Subtask }> {\n const goals = loadGoals().filter(g => g.status === 'active');\n const matched: Array<{ goal: Goal; subtask: Subtask }> = [];\n\n for (const goal of goals) {\n for (const subtask of goal.subtasks) {\n if (subtask.status !== 'pending') continue;\n if (!subtask.trigger || subtask.trigger.type !== 'event') continue;\n if (!subtask.trigger.event) continue;\n\n // Match exact event name or wildcard prefix (e.g., 'health:*' matches 'health:ollama:down')\n const pattern = subtask.trigger.event;\n const matches = pattern.endsWith('*')\n ? eventName.startsWith(pattern.slice(0, -1))\n : eventName === pattern;\n\n if (matches) {\n matched.push({ goal, subtask });\n logger.info(COMPONENT, `Event trigger matched: \"${subtask.title}\" (goal: ${goal.title}) on event: ${eventName}`);\n }\n }\n }\n\n return matched;\n}\n\n/** Dynamically add a subtask after another completes (for adaptive goal planning) */\nexport function addDynamicSubtask(goalId: string, afterSubtaskId: string, title: string, description: string): Subtask | undefined {\n const goal = getGoal(goalId);\n if (!goal) return undefined;\n\n const maxSubtasks = 30; // Safety cap\n if (goal.subtasks.length >= maxSubtasks) {\n logger.warn(COMPONENT, `Cannot add dynamic subtask to \"${goal.title}\" — max ${maxSubtasks} reached`);\n return undefined;\n }\n\n const subtask: Subtask = {\n id: `st-dyn-${goal.subtasks.length + 1}`,\n title,\n description,\n status: 'pending',\n retries: 0,\n dependsOn: [afterSubtaskId],\n };\n\n goal.subtasks.push(subtask);\n goal.updatedAt = new Date().toISOString();\n\n // Recalculate progress with new subtask\n const done = goal.subtasks.filter(st => st.status === 'done' || st.status === 'skipped').length;\n goal.progress = Math.round((done / goal.subtasks.length) * 100);\n\n saveGoals();\n logger.info(COMPONENT, `Dynamic subtask added to \"${goal.title}\": \"${title}\" (depends on ${afterSubtaskId})`);\n titanEvents.emit('goal:subtask:added', { goalId, subtaskId: subtask.id, title, afterSubtaskId });\n return subtask;\n}\n\n/** Force reload from disk (useful after external edits) */\nexport function reloadGoals(): void {\n goalsCache = null;\n loadGoals();\n}\n\n/** v5.0.0: Bulk close duplicate goals. Keeps the newest active goal for each\n * exact title and marks the rest as failed. Returns counts for logging. */\nexport function dedupeGoalsBulk(): { scanned: number; closed: number; kept: number } {\n const goals = loadGoals();\n const seen = new Map<string, Goal>(); // title -> newest kept goal\n let closed = 0;\n\n // Sort by createdAt desc so we keep the newest\n const sorted = [...goals].sort((a, b) =>\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n );\n\n for (const g of sorted) {\n const key = g.title.trim().toLowerCase();\n if (!seen.has(key)) {\n seen.set(key, g);\n continue;\n }\n // Duplicate — close it if active\n if (g.status === 'active') {\n g.status = 'failed';\n g.updatedAt = new Date().toISOString();\n closed++;\n logger.info(COMPONENT, `Bulk dedupe closed duplicate goal \"${g.title}\" (${g.id})`);\n }\n }\n\n if (closed > 0) {\n goalsCache = goals;\n saveGoals();\n }\n return { scanned: goals.length, closed, kept: seen.size };\n}\n"],"mappings":"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","names":[]}
|
package/dist/agent/peerAdvise.js
CHANGED
|
@@ -3,7 +3,7 @@ import logger from "../utils/logger.js";
|
|
|
3
3
|
import { structuredSpawn } from "./structuredSpawn.js";
|
|
4
4
|
const COMPONENT = "PeerAdvise";
|
|
5
5
|
const DEFAULT_ADVISOR = "sage";
|
|
6
|
-
const DEFAULT_TIMEOUT_MS =
|
|
6
|
+
const DEFAULT_TIMEOUT_MS = 3e4;
|
|
7
7
|
async function peerAdvise(opts) {
|
|
8
8
|
const advisor = opts.advisor ?? DEFAULT_ADVISOR;
|
|
9
9
|
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/peerAdvise.ts"],"sourcesContent":["/**\n * TITAN — Peer Advisor (v4.13+)\n *\n * Before an autonomous producer (canary-eval, self-repair daemon, auto-heal)\n * escalates a concern to Tony via an approval, it consults a peer specialist\n * and asks: should I really bother the human with this, or can the org figure\n * it out without escalating?\n *\n * The advisor is a single structured sub-agent call with a small schema. It\n * returns one of:\n * - escalate → file the approval as planned (human decision needed)\n * - dismiss → the concern is known/expected/already-fixed; drop it\n * - investigate → the concern is real but the org can act on it first;\n * caller should try its remediation path instead of\n * immediately bothering the human\n *\n * Fail-open: if the advisor call errors, returns null → caller escalates as\n * usual. Better to bother Tony than silently swallow a real problem.\n */\nimport logger from '../utils/logger.js';\nimport { structuredSpawn } from './structuredSpawn.js';\n\nconst COMPONENT = 'PeerAdvise';\n\nexport type PeerVerdict = 'escalate' | 'dismiss' | 'investigate';\n\nexport interface PeerAdvice {\n verdict: PeerVerdict;\n reason: string;\n confidence: number;\n advisorSpecialist: string;\n}\n\nexport interface PeerAdviseOpts {\n /** One-line description of what's triggering the potential escalation. */\n concern: string;\n /** Classification — canary_regression | self_repair | auto_heal | etc. */\n kind: string;\n /** Additional facts the advisor should consider. */\n context?: string;\n /**\n * Which specialist to ask. Default: 'sage' (critic/reviewer role).\n * Route by concern kind when it's obvious (code-failure → sage,\n * research-gap → scout, etc.). Unknown kinds get sage.\n */\n advisor?: 'sage' | 'analyst' | 'scout' | 'builder' | 'writer' | 'default';\n /** Max wait. Default
|
|
1
|
+
{"version":3,"sources":["../../src/agent/peerAdvise.ts"],"sourcesContent":["/**\n * TITAN — Peer Advisor (v4.13+)\n *\n * Before an autonomous producer (canary-eval, self-repair daemon, auto-heal)\n * escalates a concern to Tony via an approval, it consults a peer specialist\n * and asks: should I really bother the human with this, or can the org figure\n * it out without escalating?\n *\n * The advisor is a single structured sub-agent call with a small schema. It\n * returns one of:\n * - escalate → file the approval as planned (human decision needed)\n * - dismiss → the concern is known/expected/already-fixed; drop it\n * - investigate → the concern is real but the org can act on it first;\n * caller should try its remediation path instead of\n * immediately bothering the human\n *\n * Fail-open: if the advisor call errors, returns null → caller escalates as\n * usual. Better to bother Tony than silently swallow a real problem.\n */\nimport logger from '../utils/logger.js';\nimport { structuredSpawn } from './structuredSpawn.js';\n\nconst COMPONENT = 'PeerAdvise';\n\nexport type PeerVerdict = 'escalate' | 'dismiss' | 'investigate';\n\nexport interface PeerAdvice {\n verdict: PeerVerdict;\n reason: string;\n confidence: number;\n advisorSpecialist: string;\n}\n\nexport interface PeerAdviseOpts {\n /** One-line description of what's triggering the potential escalation. */\n concern: string;\n /** Classification — canary_regression | self_repair | auto_heal | etc. */\n kind: string;\n /** Additional facts the advisor should consider. */\n context?: string;\n /**\n * Which specialist to ask. Default: 'sage' (critic/reviewer role).\n * Route by concern kind when it's obvious (code-failure → sage,\n * research-gap → scout, etc.). Unknown kinds get sage.\n */\n advisor?: 'sage' | 'analyst' | 'scout' | 'builder' | 'writer' | 'default';\n /** Max wait. Default 30000 (30s) — advisor should be quick or fail open. */\n timeoutMs?: number;\n}\n\nconst DEFAULT_ADVISOR = 'sage';\n// v5.5.6: bumped from 20s. Observed sage runs often take 13-25s (one\n// round + thinking-fallback + tool turn), so 20s caused frequent\n// time-outs that fell open as 'escalate'. 30s gives normal runs\n// headroom while still bounding latency.\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\n/**\n * Consult a peer specialist about whether a concern warrants escalation.\n * Returns null on failure so the caller can fall back to filing the\n * approval unchanged.\n */\nexport async function peerAdvise(opts: PeerAdviseOpts): Promise<PeerAdvice | null> {\n const advisor = opts.advisor ?? DEFAULT_ADVISOR;\n const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const task = [\n `Another component of TITAN wants to bother Tony with an approval request. Before they do, they want your read as the peer advisor.`,\n '',\n `Concern kind: ${opts.kind}`,\n `Concern: ${opts.concern}`,\n opts.context ? `Context:\\n${opts.context}` : '',\n '',\n 'Decide ONE of three verdicts:',\n ' - escalate → human attention is genuinely needed right now',\n ' - dismiss → this is expected behaviour / already resolved / noise',\n ' - investigate → the org should try something automatic first (log and keep an eye on it; do not file approval)',\n '',\n 'Return a JSON object with fields: status (\"done\"), artifacts ([]), questions ([]), confidence (0-1), reasoning (1-2 sentences explaining your verdict), plus an extra field \"verdict\" containing exactly one of: escalate | dismiss | investigate.',\n 'Be a tough gatekeeper: escalate only when a human must look. When in doubt, lean dismiss or investigate.',\n ].filter(Boolean).join('\\n');\n\n const startedAt = Date.now();\n try {\n // Use Promise.race to enforce the timeout independent of subagent internals.\n const result = await Promise.race([\n structuredSpawn({\n specialistId: advisor,\n task,\n maxRounds: 2,\n }),\n new Promise<null>((resolve) => setTimeout(() => resolve(null), timeoutMs)),\n ]);\n if (!result) {\n logger.warn(COMPONENT, `${advisor} advisor timed out after ${timeoutMs}ms — failing open (escalate)`);\n return null;\n }\n const raw = result.rawResponse || '';\n // Pull 'verdict' out of the raw JSON if present\n let verdict: PeerVerdict = 'escalate';\n const m = raw.match(/\"verdict\"\\s*:\\s*\"(escalate|dismiss|investigate)\"/i);\n if (m) verdict = m[1].toLowerCase() as PeerVerdict;\n const advice: PeerAdvice = {\n verdict,\n reason: result.reasoning || 'no reason provided',\n confidence: result.confidence,\n advisorSpecialist: advisor,\n };\n logger.info(COMPONENT, `${advisor} verdict=${advice.verdict} confidence=${advice.confidence.toFixed(2)} reason=\"${advice.reason.slice(0, 100)}\" durationMs=${Date.now() - startedAt}`);\n return advice;\n } catch (err) {\n logger.warn(COMPONENT, `peer advise threw: ${(err as Error).message} — failing open (escalate)`);\n return null;\n }\n}\n"],"mappings":";AAmBA,OAAO,YAAY;AACnB,SAAS,uBAAuB;AAEhC,MAAM,YAAY;AA4BlB,MAAM,kBAAkB;AAKxB,MAAM,qBAAqB;AAO3B,eAAsB,WAAW,MAAkD;AAC/E,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,YAAY,KAAK,aAAa;AAEpC,QAAM,OAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA,iBAAiB,KAAK,IAAI;AAAA,IAC1B,YAAY,KAAK,OAAO;AAAA,IACxB,KAAK,UAAU;AAAA,EAAa,KAAK,OAAO,KAAK;AAAA,IAC7C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AAE3B,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI;AAEA,UAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,MAC9B,gBAAgB;AAAA,QACZ,cAAc;AAAA,QACd;AAAA,QACA,WAAW;AAAA,MACf,CAAC;AAAA,MACD,IAAI,QAAc,CAAC,YAAY,WAAW,MAAM,QAAQ,IAAI,GAAG,SAAS,CAAC;AAAA,IAC7E,CAAC;AACD,QAAI,CAAC,QAAQ;AACT,aAAO,KAAK,WAAW,GAAG,OAAO,4BAA4B,SAAS,mCAA8B;AACpG,aAAO;AAAA,IACX;AACA,UAAM,MAAM,OAAO,eAAe;AAElC,QAAI,UAAuB;AAC3B,UAAM,IAAI,IAAI,MAAM,mDAAmD;AACvE,QAAI,EAAG,WAAU,EAAE,CAAC,EAAE,YAAY;AAClC,UAAM,SAAqB;AAAA,MACvB;AAAA,MACA,QAAQ,OAAO,aAAa;AAAA,MAC5B,YAAY,OAAO;AAAA,MACnB,mBAAmB;AAAA,IACvB;AACA,WAAO,KAAK,WAAW,GAAG,OAAO,YAAY,OAAO,OAAO,eAAe,OAAO,WAAW,QAAQ,CAAC,CAAC,YAAY,OAAO,OAAO,MAAM,GAAG,GAAG,CAAC,gBAAgB,KAAK,IAAI,IAAI,SAAS,EAAE;AACrL,WAAO;AAAA,EACX,SAAS,KAAK;AACV,WAAO,KAAK,WAAW,sBAAuB,IAAc,OAAO,iCAA4B;AAC/F,WAAO;AAAA,EACX;AACJ;","names":[]}
|
package/dist/agent/planner.js
CHANGED
|
@@ -3,14 +3,14 @@ import { v4 as uuid } from "uuid";
|
|
|
3
3
|
import { existsSync, readFileSync, writeFileSync, readdirSync } from "fs";
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { TITAN_HOME } from "../utils/constants.js";
|
|
6
|
-
import {
|
|
6
|
+
import { mkdirIfNotExists } from "../utils/helpers.js";
|
|
7
7
|
import { registerTool } from "./toolRunner.js";
|
|
8
8
|
import logger from "../utils/logger.js";
|
|
9
9
|
const COMPONENT = "Planner";
|
|
10
10
|
const activePlans = /* @__PURE__ */ new Map();
|
|
11
11
|
const PLANS_DIR = join(TITAN_HOME, "plans");
|
|
12
12
|
function createPlan(goal, tasks) {
|
|
13
|
-
|
|
13
|
+
mkdirIfNotExists(PLANS_DIR);
|
|
14
14
|
const plan = {
|
|
15
15
|
id: uuid().slice(0, 8),
|
|
16
16
|
goal,
|
|
@@ -135,7 +135,7 @@ function getActivePlans() {
|
|
|
135
135
|
}
|
|
136
136
|
function savePlan(plan) {
|
|
137
137
|
try {
|
|
138
|
-
|
|
138
|
+
mkdirIfNotExists(PLANS_DIR);
|
|
139
139
|
writeFileSync(join(PLANS_DIR, `${plan.id}.json`), JSON.stringify(plan, null, 2), "utf-8");
|
|
140
140
|
} catch {
|
|
141
141
|
}
|
|
@@ -166,7 +166,7 @@ function checkpointPlan(planId) {
|
|
|
166
166
|
savedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
167
167
|
};
|
|
168
168
|
try {
|
|
169
|
-
|
|
169
|
+
mkdirIfNotExists(PLANS_DIR);
|
|
170
170
|
writeFileSync(
|
|
171
171
|
join(PLANS_DIR, `${planId}.checkpoint.json`),
|
|
172
172
|
JSON.stringify(checkpoint, null, 2),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/agent/planner.ts"],"sourcesContent":["/**\n * TITAN — Task Planner\n * Autonomous goal decomposition with dependency graphs.\n * Unlike Auto-GPT (which drifts) or CrewAI (which requires manual role setup),\n * TITAN automatically breaks down complex goals into executable sub-tasks\n * with dependency tracking and parallel execution.\n */\nimport { v4 as uuid } from 'uuid';\nimport { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { ensureDir } from '../utils/helpers.js';\nimport { registerTool } from './toolRunner.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'Planner';\n\nexport type TaskStatus = 'pending' | 'running' | 'done' | 'failed' | 'blocked';\n\nexport interface PlanTask {\n id: string;\n title: string;\n description: string;\n status: TaskStatus;\n dependsOn: string[]; // task IDs this depends on\n toolHint?: string; // suggested tool to use\n result?: string;\n error?: string;\n startedAt?: string;\n completedAt?: string;\n retries: number;\n /** Nesting level for hierarchical plans (0 = root) */\n level?: number;\n /** Reference to a sub-plan for compound/hierarchical tasks */\n subPlanId?: string;\n}\n\nexport interface Plan {\n id: string;\n goal: string;\n tasks: PlanTask[];\n status: 'active' | 'completed' | 'failed';\n createdAt: string;\n completedAt?: string;\n}\n\nconst activePlans: Map<string, Plan> = new Map();\nconst PLANS_DIR = join(TITAN_HOME, 'plans');\n\n/** Create a plan from a decomposed goal */\nexport function createPlan(goal: string, tasks: Array<{\n title: string;\n description: string;\n dependsOn?: string[];\n toolHint?: string;\n}>): Plan {\n ensureDir(PLANS_DIR);\n\n const plan: Plan = {\n id: uuid().slice(0, 8),\n goal,\n tasks: tasks.map((t, i) => ({\n id: `task-${i + 1}`,\n title: t.title,\n description: t.description,\n status: 'pending' as TaskStatus,\n dependsOn: t.dependsOn || [],\n toolHint: t.toolHint,\n retries: 0,\n })),\n status: 'active',\n createdAt: new Date().toISOString(),\n };\n\n activePlans.set(plan.id, plan);\n savePlan(plan);\n logger.info(COMPONENT, `Plan created: \"${goal}\" with ${plan.tasks.length} tasks`);\n return plan;\n}\n\n/** Get tasks that are ready to execute (all dependencies met) */\nexport function getReadyTasks(planId: string): PlanTask[] {\n const plan = activePlans.get(planId);\n if (!plan || plan.status !== 'active') return [];\n\n return plan.tasks.filter((task) => {\n if (task.status !== 'pending') return false;\n // All dependencies must be 'done'\n return task.dependsOn.every((depId) => {\n const dep = plan.tasks.find((t) => t.id === depId);\n return dep?.status === 'done';\n });\n });\n}\n\n/** Start a task */\nexport function startTask(planId: string, taskId: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.status = 'running';\n task.startedAt = new Date().toISOString();\n savePlan(plan);\n }\n}\n\n/** Complete a task with result */\nexport function completeTask(planId: string, taskId: string, result: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.status = 'done';\n task.result = result;\n task.completedAt = new Date().toISOString();\n\n // Check if all tasks done\n if (plan.tasks.every((t) => t.status === 'done')) {\n plan.status = 'completed';\n plan.completedAt = new Date().toISOString();\n logger.info(COMPONENT, `Plan \"${plan.goal}\" completed successfully`);\n }\n\n // Unblock waiting tasks\n for (const waiting of plan.tasks) {\n if (waiting.status === 'blocked' && waiting.dependsOn.includes(taskId)) {\n const allDepsDone = waiting.dependsOn.every((d) => plan.tasks.find((t) => t.id === d)?.status === 'done');\n if (allDepsDone) {\n waiting.status = 'pending';\n }\n }\n }\n\n savePlan(plan);\n }\n}\n\n/** Fail a task */\nexport function failTask(planId: string, taskId: string, error: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.retries++;\n if (task.retries >= 3) {\n task.status = 'failed';\n task.error = error;\n\n // Block any tasks that depend on this one\n for (const t of plan.tasks) {\n if (t.dependsOn.includes(taskId) && t.status === 'pending') {\n t.status = 'blocked';\n }\n }\n\n // Check if plan should fail\n const blockedOrFailed = plan.tasks.filter((t) => t.status === 'failed' || t.status === 'blocked');\n if (blockedOrFailed.length > 0 && plan.tasks.every((t) => ['done', 'failed', 'blocked'].includes(t.status))) {\n plan.status = 'failed';\n }\n\n logger.error(COMPONENT, `Task \"${task.title}\" failed after ${task.retries} retries: ${error}`);\n } else {\n task.status = 'pending'; // Retry\n logger.warn(COMPONENT, `Task \"${task.title}\" retry ${task.retries}/3: ${error}`);\n }\n savePlan(plan);\n }\n}\n\n/** Get plan status summary */\nexport function getPlanStatus(planId: string): string {\n const plan = activePlans.get(planId);\n if (!plan) return 'Plan not found.';\n\n const counts = { pending: 0, running: 0, done: 0, failed: 0, blocked: 0 };\n for (const t of plan.tasks) counts[t.status]++;\n\n const lines = [\n `📋 Plan: ${plan.goal} (${plan.status})`,\n `Progress: ${counts.done}/${plan.tasks.length} tasks completed`,\n '',\n ];\n\n for (const t of plan.tasks) {\n const icon = t.status === 'done' ? '✅' : t.status === 'running' ? '🔄' : t.status === 'failed' ? '❌' : t.status === 'blocked' ? '🚫' : '⏳';\n lines.push(`${icon} ${t.id}: ${t.title} [${t.status}]${t.result ? ` → ${t.result.slice(0, 50)}` : ''}${t.error ? ` ⚠️ ${t.error.slice(0, 50)}` : ''}`);\n }\n\n return lines.join('\\n');\n}\n\n/** List all plans */\nexport function listPlans(): Array<{ id: string; goal: string; status: string; taskCount: number; progress: number }> {\n return Array.from(activePlans.values()).map((p) => ({\n id: p.id,\n goal: p.goal,\n status: p.status,\n taskCount: p.tasks.length,\n progress: p.tasks.filter((t) => t.status === 'done').length,\n }));\n}\n\n/** Get a plan by ID */\nexport function getPlan(planId: string): Plan | undefined {\n return activePlans.get(planId);\n}\n\n/** Get all active plans (status = 'active'). Used by taskQueue for aggregation. */\nexport function getActivePlans(): Plan[] {\n return Array.from(activePlans.values()).filter(p => p.status === 'active');\n}\n\nfunction savePlan(plan: Plan): void {\n try {\n ensureDir(PLANS_DIR);\n writeFileSync(join(PLANS_DIR, `${plan.id}.json`), JSON.stringify(plan, null, 2), 'utf-8');\n } catch {\n // Non-critical\n }\n}\n\n/** Load persisted plans on startup */\nexport function loadPlans(): void {\n if (!existsSync(PLANS_DIR)) return;\n try {\n const files = readdirSync(PLANS_DIR).filter((f: string) => f.endsWith('.json'));\n for (const file of files) {\n const plan = JSON.parse(readFileSync(join(PLANS_DIR, file), 'utf-8')) as Plan;\n if (plan.status === 'active') {\n activePlans.set(plan.id, plan);\n }\n }\n logger.info(COMPONENT, `Loaded ${activePlans.size} active plans`);\n } catch {\n // Non-critical\n }\n}\n\n// ── Checkpoint/Resume (DeerFlow-inspired crash recovery) ─────────\n\nexport interface PlanCheckpoint {\n planId: string;\n lastCompletedTaskId: string | null;\n intermediateResults: Record<string, string>;\n savedAt: string;\n}\n\n/** Save a checkpoint of the current plan state for crash recovery */\nexport function checkpointPlan(planId: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n\n const checkpoint: PlanCheckpoint = {\n planId,\n lastCompletedTaskId: plan.tasks.filter(t => t.status === 'done').pop()?.id || null,\n intermediateResults: Object.fromEntries(\n plan.tasks.filter(t => t.result).map(t => [t.id, t.result!])\n ),\n savedAt: new Date().toISOString(),\n };\n\n try {\n ensureDir(PLANS_DIR);\n writeFileSync(\n join(PLANS_DIR, `${planId}.checkpoint.json`),\n JSON.stringify(checkpoint, null, 2),\n 'utf-8'\n );\n logger.debug(COMPONENT, `Checkpoint saved for plan ${planId}`);\n } catch {\n // Non-critical — checkpoint failure shouldn't break execution\n }\n}\n\n/** Load a checkpoint for a plan */\nexport function loadCheckpoint(planId: string): PlanCheckpoint | null {\n const path = join(PLANS_DIR, `${planId}.checkpoint.json`);\n try {\n if (existsSync(path)) {\n return JSON.parse(readFileSync(path, 'utf-8')) as PlanCheckpoint;\n }\n } catch {\n logger.warn(COMPONENT, `Corrupt checkpoint for plan ${planId}, ignoring`);\n }\n return null;\n}\n\n/** Resume a plan from its last checkpoint. Returns the plan if resumable, null otherwise. */\nexport function resumePlan(planId: string): Plan | null {\n const plan = activePlans.get(planId);\n if (!plan || plan.status !== 'active') return null;\n\n const checkpoint = loadCheckpoint(planId);\n if (!checkpoint) return null;\n\n // Restore intermediate results into tasks\n for (const task of plan.tasks) {\n if (checkpoint.intermediateResults[task.id] && task.status !== 'done') {\n task.result = checkpoint.intermediateResults[task.id];\n task.status = 'done';\n task.completedAt = checkpoint.savedAt;\n }\n }\n\n // Re-evaluate blocked tasks\n for (const task of plan.tasks) {\n if (task.status === 'blocked' || task.status === 'pending') {\n const allDepsDone = task.dependsOn.every(depId =>\n plan.tasks.find(t => t.id === depId)?.status === 'done'\n );\n if (allDepsDone) task.status = 'pending';\n }\n }\n\n savePlan(plan);\n logger.info(COMPONENT, `Plan \"${plan.goal}\" resumed from checkpoint (last completed: ${checkpoint.lastCompletedTaskId})`);\n return plan;\n}\n\n/** Get all plans with available checkpoints (for resume on startup) */\nexport function getResumablePlans(): Array<{ planId: string; goal: string; checkpoint: PlanCheckpoint }> {\n const resumable: Array<{ planId: string; goal: string; checkpoint: PlanCheckpoint }> = [];\n for (const [id, plan] of activePlans.entries()) {\n if (plan.status === 'active') {\n const cp = loadCheckpoint(id);\n if (cp) resumable.push({ planId: id, goal: plan.goal, checkpoint: cp });\n }\n }\n return resumable;\n}\n\n/** Register the planner as an LLM-invocable tool */\nexport function registerPlannerTool(): void {\n registerTool({\n name: 'plan_task',\n description: 'Decompose a complex goal into a structured plan with sub-tasks and dependencies. Returns a task dependency graph that can be executed step by step.',\n parameters: {\n type: 'object',\n properties: {\n goal: {\n type: 'string',\n description: 'The goal or complex task to decompose into sub-tasks',\n },\n },\n required: ['goal'],\n },\n execute: async (args: Record<string, unknown>) => {\n const goal = String(args.goal || '');\n if (!goal) return 'Error: No goal provided. Please specify a goal to plan.';\n\n // Decompose the goal into logical sub-tasks\n const steps = goal.split(/[,;]|\\band\\b|\\bthen\\b/i)\n .map(s => s.trim())\n .filter(s => s.length > 0);\n\n const tasks = steps.length > 1\n ? steps.map((step, i) => ({\n title: step.slice(0, 80),\n description: step,\n dependsOn: i > 0 ? [`task-${i}`] : [],\n }))\n : [\n { title: `Research: ${goal.slice(0, 60)}`, description: `Gather information needed for: ${goal}`, dependsOn: [] as string[] },\n { title: `Execute: ${goal.slice(0, 60)}`, description: `Carry out the main work: ${goal}`, dependsOn: ['task-1'] },\n { title: `Verify: ${goal.slice(0, 60)}`, description: `Confirm completion and quality of: ${goal}`, dependsOn: ['task-2'] },\n ];\n\n const plan = createPlan(goal, tasks);\n return getPlanStatus(plan.id);\n },\n });\n logger.info(COMPONENT, 'Registered plan_task tool');\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/agent/planner.ts"],"sourcesContent":["/**\n * TITAN — Task Planner\n * Autonomous goal decomposition with dependency graphs.\n * Unlike Auto-GPT (which drifts) or CrewAI (which requires manual role setup),\n * TITAN automatically breaks down complex goals into executable sub-tasks\n * with dependency tracking and parallel execution.\n */\nimport { v4 as uuid } from 'uuid';\nimport { existsSync, readFileSync, writeFileSync, readdirSync } from 'fs';\nimport { join } from 'path';\nimport { TITAN_HOME } from '../utils/constants.js';\nimport { mkdirIfNotExists } from '../utils/helpers.js';\nimport { registerTool } from './toolRunner.js';\nimport logger from '../utils/logger.js';\n\nconst COMPONENT = 'Planner';\n\nexport type TaskStatus = 'pending' | 'running' | 'done' | 'failed' | 'blocked';\n\nexport interface PlanTask {\n id: string;\n title: string;\n description: string;\n status: TaskStatus;\n dependsOn: string[]; // task IDs this depends on\n toolHint?: string; // suggested tool to use\n result?: string;\n error?: string;\n startedAt?: string;\n completedAt?: string;\n retries: number;\n /** Nesting level for hierarchical plans (0 = root) */\n level?: number;\n /** Reference to a sub-plan for compound/hierarchical tasks */\n subPlanId?: string;\n}\n\nexport interface Plan {\n id: string;\n goal: string;\n tasks: PlanTask[];\n status: 'active' | 'completed' | 'failed';\n createdAt: string;\n completedAt?: string;\n}\n\nconst activePlans: Map<string, Plan> = new Map();\nconst PLANS_DIR = join(TITAN_HOME, 'plans');\n\n/** Create a plan from a decomposed goal */\nexport function createPlan(goal: string, tasks: Array<{\n title: string;\n description: string;\n dependsOn?: string[];\n toolHint?: string;\n}>): Plan {\n mkdirIfNotExists(PLANS_DIR);\n\n const plan: Plan = {\n id: uuid().slice(0, 8),\n goal,\n tasks: tasks.map((t, i) => ({\n id: `task-${i + 1}`,\n title: t.title,\n description: t.description,\n status: 'pending' as TaskStatus,\n dependsOn: t.dependsOn || [],\n toolHint: t.toolHint,\n retries: 0,\n })),\n status: 'active',\n createdAt: new Date().toISOString(),\n };\n\n activePlans.set(plan.id, plan);\n savePlan(plan);\n logger.info(COMPONENT, `Plan created: \"${goal}\" with ${plan.tasks.length} tasks`);\n return plan;\n}\n\n/** Get tasks that are ready to execute (all dependencies met) */\nexport function getReadyTasks(planId: string): PlanTask[] {\n const plan = activePlans.get(planId);\n if (!plan || plan.status !== 'active') return [];\n\n return plan.tasks.filter((task) => {\n if (task.status !== 'pending') return false;\n // All dependencies must be 'done'\n return task.dependsOn.every((depId) => {\n const dep = plan.tasks.find((t) => t.id === depId);\n return dep?.status === 'done';\n });\n });\n}\n\n/** Start a task */\nexport function startTask(planId: string, taskId: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.status = 'running';\n task.startedAt = new Date().toISOString();\n savePlan(plan);\n }\n}\n\n/** Complete a task with result */\nexport function completeTask(planId: string, taskId: string, result: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.status = 'done';\n task.result = result;\n task.completedAt = new Date().toISOString();\n\n // Check if all tasks done\n if (plan.tasks.every((t) => t.status === 'done')) {\n plan.status = 'completed';\n plan.completedAt = new Date().toISOString();\n logger.info(COMPONENT, `Plan \"${plan.goal}\" completed successfully`);\n }\n\n // Unblock waiting tasks\n for (const waiting of plan.tasks) {\n if (waiting.status === 'blocked' && waiting.dependsOn.includes(taskId)) {\n const allDepsDone = waiting.dependsOn.every((d) => plan.tasks.find((t) => t.id === d)?.status === 'done');\n if (allDepsDone) {\n waiting.status = 'pending';\n }\n }\n }\n\n savePlan(plan);\n }\n}\n\n/** Fail a task */\nexport function failTask(planId: string, taskId: string, error: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n const task = plan.tasks.find((t) => t.id === taskId);\n if (task) {\n task.retries++;\n if (task.retries >= 3) {\n task.status = 'failed';\n task.error = error;\n\n // Block any tasks that depend on this one\n for (const t of plan.tasks) {\n if (t.dependsOn.includes(taskId) && t.status === 'pending') {\n t.status = 'blocked';\n }\n }\n\n // Check if plan should fail\n const blockedOrFailed = plan.tasks.filter((t) => t.status === 'failed' || t.status === 'blocked');\n if (blockedOrFailed.length > 0 && plan.tasks.every((t) => ['done', 'failed', 'blocked'].includes(t.status))) {\n plan.status = 'failed';\n }\n\n logger.error(COMPONENT, `Task \"${task.title}\" failed after ${task.retries} retries: ${error}`);\n } else {\n task.status = 'pending'; // Retry\n logger.warn(COMPONENT, `Task \"${task.title}\" retry ${task.retries}/3: ${error}`);\n }\n savePlan(plan);\n }\n}\n\n/** Get plan status summary */\nexport function getPlanStatus(planId: string): string {\n const plan = activePlans.get(planId);\n if (!plan) return 'Plan not found.';\n\n const counts = { pending: 0, running: 0, done: 0, failed: 0, blocked: 0 };\n for (const t of plan.tasks) counts[t.status]++;\n\n const lines = [\n `📋 Plan: ${plan.goal} (${plan.status})`,\n `Progress: ${counts.done}/${plan.tasks.length} tasks completed`,\n '',\n ];\n\n for (const t of plan.tasks) {\n const icon = t.status === 'done' ? '✅' : t.status === 'running' ? '🔄' : t.status === 'failed' ? '❌' : t.status === 'blocked' ? '🚫' : '⏳';\n lines.push(`${icon} ${t.id}: ${t.title} [${t.status}]${t.result ? ` → ${t.result.slice(0, 50)}` : ''}${t.error ? ` ⚠️ ${t.error.slice(0, 50)}` : ''}`);\n }\n\n return lines.join('\\n');\n}\n\n/** List all plans */\nexport function listPlans(): Array<{ id: string; goal: string; status: string; taskCount: number; progress: number }> {\n return Array.from(activePlans.values()).map((p) => ({\n id: p.id,\n goal: p.goal,\n status: p.status,\n taskCount: p.tasks.length,\n progress: p.tasks.filter((t) => t.status === 'done').length,\n }));\n}\n\n/** Get a plan by ID */\nexport function getPlan(planId: string): Plan | undefined {\n return activePlans.get(planId);\n}\n\n/** Get all active plans (status = 'active'). Used by taskQueue for aggregation. */\nexport function getActivePlans(): Plan[] {\n return Array.from(activePlans.values()).filter(p => p.status === 'active');\n}\n\nfunction savePlan(plan: Plan): void {\n try {\n mkdirIfNotExists(PLANS_DIR);\n writeFileSync(join(PLANS_DIR, `${plan.id}.json`), JSON.stringify(plan, null, 2), 'utf-8');\n } catch {\n // Non-critical\n }\n}\n\n/** Load persisted plans on startup */\nexport function loadPlans(): void {\n if (!existsSync(PLANS_DIR)) return;\n try {\n const files = readdirSync(PLANS_DIR).filter((f: string) => f.endsWith('.json'));\n for (const file of files) {\n const plan = JSON.parse(readFileSync(join(PLANS_DIR, file), 'utf-8')) as Plan;\n if (plan.status === 'active') {\n activePlans.set(plan.id, plan);\n }\n }\n logger.info(COMPONENT, `Loaded ${activePlans.size} active plans`);\n } catch {\n // Non-critical\n }\n}\n\n// ── Checkpoint/Resume (DeerFlow-inspired crash recovery) ─────────\n\nexport interface PlanCheckpoint {\n planId: string;\n lastCompletedTaskId: string | null;\n intermediateResults: Record<string, string>;\n savedAt: string;\n}\n\n/** Save a checkpoint of the current plan state for crash recovery */\nexport function checkpointPlan(planId: string): void {\n const plan = activePlans.get(planId);\n if (!plan) return;\n\n const checkpoint: PlanCheckpoint = {\n planId,\n lastCompletedTaskId: plan.tasks.filter(t => t.status === 'done').pop()?.id || null,\n intermediateResults: Object.fromEntries(\n plan.tasks.filter(t => t.result).map(t => [t.id, t.result!])\n ),\n savedAt: new Date().toISOString(),\n };\n\n try {\n mkdirIfNotExists(PLANS_DIR);\n writeFileSync(\n join(PLANS_DIR, `${planId}.checkpoint.json`),\n JSON.stringify(checkpoint, null, 2),\n 'utf-8'\n );\n logger.debug(COMPONENT, `Checkpoint saved for plan ${planId}`);\n } catch {\n // Non-critical — checkpoint failure shouldn't break execution\n }\n}\n\n/** Load a checkpoint for a plan */\nexport function loadCheckpoint(planId: string): PlanCheckpoint | null {\n const path = join(PLANS_DIR, `${planId}.checkpoint.json`);\n try {\n if (existsSync(path)) {\n return JSON.parse(readFileSync(path, 'utf-8')) as PlanCheckpoint;\n }\n } catch {\n logger.warn(COMPONENT, `Corrupt checkpoint for plan ${planId}, ignoring`);\n }\n return null;\n}\n\n/** Resume a plan from its last checkpoint. Returns the plan if resumable, null otherwise. */\nexport function resumePlan(planId: string): Plan | null {\n const plan = activePlans.get(planId);\n if (!plan || plan.status !== 'active') return null;\n\n const checkpoint = loadCheckpoint(planId);\n if (!checkpoint) return null;\n\n // Restore intermediate results into tasks\n for (const task of plan.tasks) {\n if (checkpoint.intermediateResults[task.id] && task.status !== 'done') {\n task.result = checkpoint.intermediateResults[task.id];\n task.status = 'done';\n task.completedAt = checkpoint.savedAt;\n }\n }\n\n // Re-evaluate blocked tasks\n for (const task of plan.tasks) {\n if (task.status === 'blocked' || task.status === 'pending') {\n const allDepsDone = task.dependsOn.every(depId =>\n plan.tasks.find(t => t.id === depId)?.status === 'done'\n );\n if (allDepsDone) task.status = 'pending';\n }\n }\n\n savePlan(plan);\n logger.info(COMPONENT, `Plan \"${plan.goal}\" resumed from checkpoint (last completed: ${checkpoint.lastCompletedTaskId})`);\n return plan;\n}\n\n/** Get all plans with available checkpoints (for resume on startup) */\nexport function getResumablePlans(): Array<{ planId: string; goal: string; checkpoint: PlanCheckpoint }> {\n const resumable: Array<{ planId: string; goal: string; checkpoint: PlanCheckpoint }> = [];\n for (const [id, plan] of activePlans.entries()) {\n if (plan.status === 'active') {\n const cp = loadCheckpoint(id);\n if (cp) resumable.push({ planId: id, goal: plan.goal, checkpoint: cp });\n }\n }\n return resumable;\n}\n\n/** Register the planner as an LLM-invocable tool */\nexport function registerPlannerTool(): void {\n registerTool({\n name: 'plan_task',\n description: 'Decompose a complex goal into a structured plan with sub-tasks and dependencies. Returns a task dependency graph that can be executed step by step.',\n parameters: {\n type: 'object',\n properties: {\n goal: {\n type: 'string',\n description: 'The goal or complex task to decompose into sub-tasks',\n },\n },\n required: ['goal'],\n },\n execute: async (args: Record<string, unknown>) => {\n const goal = String(args.goal || '');\n if (!goal) return 'Error: No goal provided. Please specify a goal to plan.';\n\n // Decompose the goal into logical sub-tasks\n const steps = goal.split(/[,;]|\\band\\b|\\bthen\\b/i)\n .map(s => s.trim())\n .filter(s => s.length > 0);\n\n const tasks = steps.length > 1\n ? steps.map((step, i) => ({\n title: step.slice(0, 80),\n description: step,\n dependsOn: i > 0 ? [`task-${i}`] : [],\n }))\n : [\n { title: `Research: ${goal.slice(0, 60)}`, description: `Gather information needed for: ${goal}`, dependsOn: [] as string[] },\n { title: `Execute: ${goal.slice(0, 60)}`, description: `Carry out the main work: ${goal}`, dependsOn: ['task-1'] },\n { title: `Verify: ${goal.slice(0, 60)}`, description: `Confirm completion and quality of: ${goal}`, dependsOn: ['task-2'] },\n ];\n\n const plan = createPlan(goal, tasks);\n return getPlanStatus(plan.id);\n },\n });\n logger.info(COMPONENT, 'Registered plan_task tool');\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { existsSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { TITAN_HOME } from "../utils/constants.js";
|
|
5
|
-
import { readJsonFile, writeJsonFile,
|
|
5
|
+
import { readJsonFile, writeJsonFile, mkdirIfNotExists } from "../utils/helpers.js";
|
|
6
6
|
import logger from "../utils/logger.js";
|
|
7
7
|
const COMPONENT = "UserProfile";
|
|
8
8
|
const PROFILE_PATH = join(TITAN_HOME, "user-profile.json");
|
|
@@ -20,7 +20,7 @@ function createDefaultProfile() {
|
|
|
20
20
|
let cachedProfile = null;
|
|
21
21
|
function loadProfile() {
|
|
22
22
|
if (cachedProfile) return cachedProfile;
|
|
23
|
-
|
|
23
|
+
mkdirIfNotExists(TITAN_HOME);
|
|
24
24
|
if (existsSync(PROFILE_PATH)) {
|
|
25
25
|
const loaded = readJsonFile(PROFILE_PATH);
|
|
26
26
|
if (loaded) {
|