@mastra/server 1.60.0-alpha.9 → 1.60.0
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/CHANGELOG.md +133 -0
- package/dist/{a2a-Eeib3vfP.cjs → a2a-BtXFFv-0.cjs} +4 -4
- package/dist/{a2a-Eeib3vfP.cjs.map → a2a-BtXFFv-0.cjs.map} +1 -1
- package/dist/{a2a-B5m54dOP.js → a2a-DZhtQeFL.js} +3 -3
- package/dist/{a2a-B5m54dOP.js.map → a2a-DZhtQeFL.js.map} +1 -1
- package/dist/{agent-versions-xeysPGel.cjs → agent-versions-MYjO6Wl1.cjs} +2 -2
- package/dist/{agent-versions-xeysPGel.cjs.map → agent-versions-MYjO6Wl1.cjs.map} +1 -1
- package/dist/{agent-versions-CWEnD62A.js → agent-versions-mFXaw5ma.js} +2 -2
- package/dist/{agent-versions-CWEnD62A.js.map → agent-versions-mFXaw5ma.js.map} +1 -1
- package/dist/{api-schema-manifest-BKTXRheC.js → api-schema-manifest-Bx_zU5qw.js} +2 -2
- package/dist/{api-schema-manifest-BKTXRheC.js.map → api-schema-manifest-Bx_zU5qw.js.map} +1 -1
- package/dist/{api-schema-manifest-BbNdh5Ck.cjs → api-schema-manifest-DPgfugJT.cjs} +4 -3
- package/dist/{api-schema-manifest-BbNdh5Ck.cjs.map → api-schema-manifest-DPgfugJT.cjs.map} +1 -1
- package/dist/{background-tasks-C5G2jJax.cjs → background-tasks-8M9W_27g.cjs} +2 -2
- package/dist/{background-tasks-C5G2jJax.cjs.map → background-tasks-8M9W_27g.cjs.map} +1 -1
- package/dist/{builder-registry-CyaUg_iP.cjs → builder-registry-Dcd_ApmT.cjs} +3 -3
- package/dist/{builder-registry-CyaUg_iP.cjs.map → builder-registry-Dcd_ApmT.cjs.map} +1 -1
- package/dist/{builder-registry-CqLsr39q.js → builder-registry-DnEa4qnF.js} +2 -2
- package/dist/{builder-registry-CqLsr39q.js.map → builder-registry-DnEa4qnF.js.map} +1 -1
- package/dist/{channels-BnFQESMf.js → channels-BO3Zd38V.js} +2 -2
- package/dist/{channels-BnFQESMf.js.map → channels-BO3Zd38V.js.map} +1 -1
- package/dist/{channels-Dzy6VM3w.cjs → channels-D9WRnKzU.cjs} +3 -3
- package/dist/{channels-Dzy6VM3w.cjs.map → channels-D9WRnKzU.cjs.map} +1 -1
- package/dist/{constants-CutMu4A_.js → constants-0jFCWoex.js} +13 -2
- package/dist/constants-0jFCWoex.js.map +1 -0
- package/dist/{constants-CXPpy-Ef.cjs → constants-4IJp_uzj.cjs} +18 -1
- package/dist/constants-4IJp_uzj.cjs.map +1 -0
- package/dist/{conversations-CcFLCCeF.cjs → conversations-PF0eKhIu.cjs} +3 -3
- package/dist/{conversations-CcFLCCeF.cjs.map → conversations-PF0eKhIu.cjs.map} +1 -1
- package/dist/{dist-CAVC0nWG.cjs → dist-2zVeGGHi.cjs} +3 -2
- package/dist/{dist-CAVC0nWG.cjs.map → dist-2zVeGGHi.cjs.map} +1 -1
- package/dist/{dist-D7GkGue6.cjs → dist-8-Z5v77M.cjs} +3 -2
- package/dist/{dist-D7GkGue6.cjs.map → dist-8-Z5v77M.cjs.map} +1 -1
- package/dist/{dist-SKhVwZMV.cjs → dist-Be7Caz3Z.cjs} +3 -2
- package/dist/{dist-SKhVwZMV.cjs.map → dist-Be7Caz3Z.cjs.map} +1 -1
- package/dist/{dist-18h28zlO.cjs → dist-BfVTO0pC.cjs} +3 -2
- package/dist/{dist-18h28zlO.cjs.map → dist-BfVTO0pC.cjs.map} +1 -1
- package/dist/{dist-BD0I5lxM.js → dist-CHJcZQdS.js} +2 -2
- package/dist/{dist-BD0I5lxM.js.map → dist-CHJcZQdS.js.map} +1 -1
- package/dist/{dist-BpRGQqjE.cjs → dist-CJKQBH69.cjs} +2 -2
- package/dist/{dist-BpRGQqjE.cjs.map → dist-CJKQBH69.cjs.map} +1 -1
- package/dist/{dist-sUhxlnJz.js → dist-CRgxcDTg.js} +2 -2
- package/dist/{dist-sUhxlnJz.js.map → dist-CRgxcDTg.js.map} +1 -1
- package/dist/{dist-JdnTASYe.js → dist-CscF1cF8.js} +2 -2
- package/dist/{dist-JdnTASYe.js.map → dist-CscF1cF8.js.map} +1 -1
- package/dist/{dist-DNaReo7-.js → dist-Cw-T1gX6.js} +2754 -304
- package/dist/dist-Cw-T1gX6.js.map +1 -0
- package/dist/{dist-DBP9kw_8.cjs → dist-D4NzuG3G.cjs} +3 -2
- package/dist/{dist-DBP9kw_8.cjs.map → dist-D4NzuG3G.cjs.map} +1 -1
- package/dist/{dist-C2O8fRb-.cjs → dist-DERatX43.cjs} +2755 -305
- package/dist/dist-DERatX43.cjs.map +1 -0
- package/dist/{dist-mcwHCl2a.js → dist-F_Ql1co6.js} +2 -2
- package/dist/{dist-mcwHCl2a.js.map → dist-F_Ql1co6.js.map} +1 -1
- package/dist/{dist-C-9xUY65.js → dist-Jn3uXsoB.js} +2 -2
- package/dist/{dist-C-9xUY65.js.map → dist-Jn3uXsoB.js.map} +1 -1
- package/dist/{dist-DyBO3IVt.js → dist-bAFqx06T.js} +2 -2
- package/dist/{dist-DyBO3IVt.js.map → dist-bAFqx06T.js.map} +1 -1
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/{dynamic-workflows-C-6vmau5.cjs → dynamic-workflows-BZ5ru36x.cjs} +3 -3
- package/dist/{dynamic-workflows-C-6vmau5.cjs.map → dynamic-workflows-BZ5ru36x.cjs.map} +1 -1
- package/dist/{dynamic-workflows-B0TE8mjA.js → dynamic-workflows-C6U0Rdoc.js} +2 -2
- package/dist/{dynamic-workflows-B0TE8mjA.js.map → dynamic-workflows-C6U0Rdoc.js.map} +1 -1
- package/dist/{editor-builder-1L3OIY4K.cjs → editor-builder-BmRQift0.cjs} +2 -2
- package/dist/{editor-builder-1L3OIY4K.cjs.map → editor-builder-BmRQift0.cjs.map} +1 -1
- package/dist/{helpers-C54OMiDG.cjs → helpers-BWxRRShz.cjs} +2 -2
- package/dist/{helpers-C54OMiDG.cjs.map → helpers-BWxRRShz.cjs.map} +1 -1
- package/dist/{helpers-Da9nPOFL.js → helpers-DBAYsA50.js} +2 -2
- package/dist/{helpers-Da9nPOFL.js.map → helpers-DBAYsA50.js.map} +1 -1
- package/dist/index.cjs +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/{observability-new-endpoints-BC-dasRY.cjs → observability-new-endpoints-gRCFhnRr.cjs} +2 -2
- package/dist/{observability-new-endpoints-BC-dasRY.cjs.map → observability-new-endpoints-gRCFhnRr.cjs.map} +1 -1
- package/dist/{probe-image-size-C2F59z8Z.cjs → probe-image-size-CDCRrXNo.cjs} +140 -33
- package/dist/probe-image-size-CDCRrXNo.cjs.map +1 -0
- package/dist/{probe-image-size-mXCWYNrz.js → probe-image-size-Tf8sNZhU.js} +137 -33
- package/dist/probe-image-size-Tf8sNZhU.js.map +1 -0
- package/dist/{responses-BI25doe1.cjs → responses-CKNdSRkS.cjs} +2 -2
- package/dist/{responses-BI25doe1.cjs.map → responses-CKNdSRkS.cjs.map} +1 -1
- package/dist/{rolldown-runtime-CVvi-lCc.cjs → rolldown-runtime-Bd6kNlEP.cjs} +21 -0
- package/dist/{rolldown-runtime-DuvcJU0W.js → rolldown-runtime-maW3aOIk.js} +10 -1
- package/dist/{route-builder-BAAedfru.cjs → route-builder-CWsok5ci.cjs} +2 -2
- package/dist/{route-builder-BAAedfru.cjs.map → route-builder-CWsok5ci.cjs.map} +1 -1
- package/dist/{routes-iUe0w9eL.js → routes-Bh2p-WqG.js} +5 -5
- package/dist/{routes-iUe0w9eL.js.map → routes-Bh2p-WqG.js.map} +1 -1
- package/dist/{routes-mK_LlDMo.cjs → routes-CdbboDwv.cjs} +10 -10
- package/dist/{routes-mK_LlDMo.cjs.map → routes-CdbboDwv.cjs.map} +1 -1
- package/dist/{schedules-DOK225ZZ.cjs → schedules-7YUg_TRM.cjs} +2 -2
- package/dist/{schedules-DOK225ZZ.cjs.map → schedules-7YUg_TRM.cjs.map} +1 -1
- package/dist/{schema-Bv9OdW1f-CHHI-NTr.cjs → schema-Bv9OdW1f-CxTiW8RD.cjs} +2 -2
- package/dist/{schema-Bv9OdW1f-CHHI-NTr.cjs.map → schema-Bv9OdW1f-CxTiW8RD.cjs.map} +1 -1
- package/dist/schema-CNKnRmv1.cjs +1 -0
- package/dist/{scorer-versions-CdVjOtQO.js → scorer-versions-D0_KP67E.js} +2 -2
- package/dist/{scorer-versions-CdVjOtQO.js.map → scorer-versions-D0_KP67E.js.map} +1 -1
- package/dist/{scorer-versions-CYXtxMTU.cjs → scorer-versions-mL--H4LL.cjs} +2 -2
- package/dist/{scorer-versions-CYXtxMTU.cjs.map → scorer-versions-mL--H4LL.cjs.map} +1 -1
- package/dist/server/a2a/store.cjs +1 -0
- package/dist/server/a2a/store.cjs.map +1 -1
- package/dist/server/auth/index.cjs +3 -2
- package/dist/server/auth/index.js +2 -2
- package/dist/server/browser-stream/index.cjs +1 -0
- package/dist/server/browser-stream/index.cjs.map +1 -1
- package/dist/server/constants.d.ts +11 -0
- package/dist/server/constants.d.ts.map +1 -1
- package/dist/server/handlers/a2a.cjs +2 -1
- package/dist/server/handlers/a2a.js +1 -1
- package/dist/server/handlers/agent-builder.cjs +4 -4
- package/dist/server/handlers/agent-builder.js +3 -3
- package/dist/server/handlers/agent-controller.cjs +53 -36
- package/dist/server/handlers/agent-controller.cjs.map +1 -1
- package/dist/server/handlers/agent-controller.d.ts +22 -2
- package/dist/server/handlers/agent-controller.d.ts.map +1 -1
- package/dist/server/handlers/agent-controller.js +51 -35
- package/dist/server/handlers/agent-controller.js.map +1 -1
- package/dist/server/handlers/agent-versions.cjs +4 -3
- package/dist/server/handlers/agent-versions.cjs.map +1 -1
- package/dist/server/handlers/agent-versions.js +2 -2
- package/dist/server/handlers/agents.cjs +8 -8
- package/dist/server/handlers/agents.d.ts +8 -0
- package/dist/server/handlers/agents.d.ts.map +1 -1
- package/dist/server/handlers/agents.js +5 -5
- package/dist/server/handlers/auth.cjs +16 -7
- package/dist/server/handlers/auth.cjs.map +1 -1
- package/dist/server/handlers/auth.d.ts +10 -4
- package/dist/server/handlers/auth.d.ts.map +1 -1
- package/dist/server/handlers/auth.js +14 -6
- package/dist/server/handlers/auth.js.map +1 -1
- package/dist/server/handlers/author-enrichment.cjs +1 -0
- package/dist/server/handlers/author-enrichment.cjs.map +1 -1
- package/dist/server/handlers/authorship.cjs +2 -1
- package/dist/server/handlers/authorship.cjs.map +1 -1
- package/dist/server/handlers/authorship.js +1 -1
- package/dist/server/handlers/background-tasks.cjs +2 -1
- package/dist/server/handlers/builder-registry.cjs +2 -1
- package/dist/server/handlers/builder-registry.js +1 -1
- package/dist/server/handlers/channels.cjs +2 -1
- package/dist/server/handlers/channels.js +1 -1
- package/dist/server/handlers/conversations.cjs +4 -4
- package/dist/server/handlers/conversations.js +2 -2
- package/dist/server/handlers/datasets.cjs +3 -2
- package/dist/server/handlers/datasets.cjs.map +1 -1
- package/dist/server/handlers/datasets.d.ts +6 -6
- package/dist/server/handlers/datasets.js +1 -1
- package/dist/server/handlers/dynamic-workflows.cjs +2 -1
- package/dist/server/handlers/dynamic-workflows.js +1 -1
- package/dist/server/handlers/editor-builder.cjs +2 -1
- package/dist/server/handlers/error.cjs +1 -0
- package/dist/server/handlers/error.cjs.map +1 -1
- package/dist/server/handlers/favorites-enrichment.cjs +2 -1
- package/dist/server/handlers/favorites-enrichment.cjs.map +1 -1
- package/dist/server/handlers/gateway-memory-client.cjs +1 -0
- package/dist/server/handlers/gateway-memory-client.cjs.map +1 -1
- package/dist/server/handlers/logs.cjs +3 -3
- package/dist/server/handlers/logs.js +2 -2
- package/dist/server/handlers/mcp-client-versions.cjs +3 -2
- package/dist/server/handlers/mcp-client-versions.cjs.map +1 -1
- package/dist/server/handlers/mcp-client-versions.js +1 -1
- package/dist/server/handlers/mcp.cjs +2 -2
- package/dist/server/handlers/mcp.js +1 -1
- package/dist/server/handlers/memory.cjs +3 -3
- package/dist/server/handlers/memory.js +2 -2
- package/dist/server/handlers/observability-list-query-schemas.cjs +1 -0
- package/dist/server/handlers/observability-list-query-schemas.cjs.map +1 -1
- package/dist/server/handlers/observability-new-endpoints.cjs +2 -1
- package/dist/server/handlers/observability-shared.cjs +2 -1
- package/dist/server/handlers/observability-shared.cjs.map +1 -1
- package/dist/server/handlers/observability-storage-schemas.cjs +1 -1
- package/dist/server/handlers/observability.cjs +8 -5
- package/dist/server/handlers/observability.cjs.map +1 -1
- package/dist/server/handlers/observability.d.ts.map +1 -1
- package/dist/server/handlers/observability.js +7 -4
- package/dist/server/handlers/observability.js.map +1 -1
- package/dist/server/handlers/plans.cjs +3 -3
- package/dist/server/handlers/plans.js +2 -2
- package/dist/server/handlers/processor-providers.cjs +2 -1
- package/dist/server/handlers/processor-providers.cjs.map +1 -1
- package/dist/server/handlers/processors.cjs +2 -1
- package/dist/server/handlers/processors.cjs.map +1 -1
- package/dist/server/handlers/prompt-block-versions.cjs +3 -2
- package/dist/server/handlers/prompt-block-versions.cjs.map +1 -1
- package/dist/server/handlers/prompt-block-versions.js +1 -1
- package/dist/server/handlers/responses.adapter.cjs +1 -0
- package/dist/server/handlers/responses.adapter.cjs.map +1 -1
- package/dist/server/handlers/responses.cjs +4 -4
- package/dist/server/handlers/responses.js +2 -2
- package/dist/server/handlers/responses.storage.cjs +2 -1
- package/dist/server/handlers/responses.storage.cjs.map +1 -1
- package/dist/server/handlers/responses.storage.js +1 -1
- package/dist/server/handlers/schedules-workflows-shim.cjs +1 -1
- package/dist/server/handlers/schedules.cjs +2 -1
- package/dist/server/handlers/scorer-versions.cjs +4 -3
- package/dist/server/handlers/scorer-versions.cjs.map +1 -1
- package/dist/server/handlers/scorer-versions.js +2 -2
- package/dist/server/handlers/scores.cjs +2 -2
- package/dist/server/handlers/scores.js +1 -1
- package/dist/server/handlers/skills-sh-shared.cjs +1 -0
- package/dist/server/handlers/skills-sh-shared.cjs.map +1 -1
- package/dist/server/handlers/stored-agent-favorites.cjs +5 -4
- package/dist/server/handlers/stored-agent-favorites.cjs.map +1 -1
- package/dist/server/handlers/stored-agent-favorites.js +2 -2
- package/dist/server/handlers/stored-agents.cjs +7 -5
- package/dist/server/handlers/stored-agents.cjs.map +1 -1
- package/dist/server/handlers/stored-agents.d.ts +32 -0
- package/dist/server/handlers/stored-agents.d.ts.map +1 -1
- package/dist/server/handlers/stored-agents.js +4 -3
- package/dist/server/handlers/stored-agents.js.map +1 -1
- package/dist/server/handlers/stored-mcp-clients.cjs +3 -2
- package/dist/server/handlers/stored-mcp-clients.cjs.map +1 -1
- package/dist/server/handlers/stored-mcp-clients.js +1 -1
- package/dist/server/handlers/stored-prompt-blocks.cjs +3 -2
- package/dist/server/handlers/stored-prompt-blocks.cjs.map +1 -1
- package/dist/server/handlers/stored-prompt-blocks.js +1 -1
- package/dist/server/handlers/stored-scorers.cjs +4 -3
- package/dist/server/handlers/stored-scorers.cjs.map +1 -1
- package/dist/server/handlers/stored-scorers.js +2 -2
- package/dist/server/handlers/stored-skill-favorites.cjs +4 -3
- package/dist/server/handlers/stored-skill-favorites.cjs.map +1 -1
- package/dist/server/handlers/stored-skill-favorites.js +1 -1
- package/dist/server/handlers/stored-skills.cjs +4 -3
- package/dist/server/handlers/stored-skills.cjs.map +1 -1
- package/dist/server/handlers/stored-skills.js +1 -1
- package/dist/server/handlers/stored-workspaces.cjs +3 -2
- package/dist/server/handlers/stored-workspaces.cjs.map +1 -1
- package/dist/server/handlers/stored-workspaces.js +1 -1
- package/dist/server/handlers/system.cjs +3 -2
- package/dist/server/handlers/system.cjs.map +1 -1
- package/dist/server/handlers/system.js +1 -1
- package/dist/server/handlers/test-utils.cjs +1 -0
- package/dist/server/handlers/test-utils.cjs.map +1 -1
- package/dist/server/handlers/tool-providers.cjs +3 -2
- package/dist/server/handlers/tool-providers.cjs.map +1 -1
- package/dist/server/handlers/tool-providers.js +1 -1
- package/dist/server/handlers/tool-schema-overrides.cjs +1 -0
- package/dist/server/handlers/tool-schema-overrides.cjs.map +1 -1
- package/dist/server/handlers/tools.cjs +6 -6
- package/dist/server/handlers/tools.js +3 -3
- package/dist/server/handlers/utils.cjs +2 -1
- package/dist/server/handlers/utils.js +1 -1
- package/dist/server/handlers/validate-agent-instructions.cjs +2 -1
- package/dist/server/handlers/validate-agent-instructions.cjs.map +1 -1
- package/dist/server/handlers/validate-agent-instructions.js +1 -1
- package/dist/server/handlers/validate-avatar.cjs +1 -0
- package/dist/server/handlers/validate-avatar.cjs.map +1 -1
- package/dist/server/handlers/vector.cjs +2 -2
- package/dist/server/handlers/vector.js +1 -1
- package/dist/server/handlers/version-helpers.cjs +1 -0
- package/dist/server/handlers/version-helpers.cjs.map +1 -1
- package/dist/server/handlers/voice.cjs +1 -1
- package/dist/server/handlers/voice.js +1 -1
- package/dist/server/handlers/workflows.cjs +4 -4
- package/dist/server/handlers/workflows.js +3 -3
- package/dist/server/handlers/workspace.cjs +2 -2
- package/dist/server/handlers/workspace.js +1 -1
- package/dist/server/handlers.cjs +3 -2
- package/dist/server/handlers.js +2 -2
- package/dist/server/schemas/datasets.d.ts +3 -3
- package/dist/server/schemas/index.cjs +7 -6
- package/dist/server/schemas/index.js +4 -4
- package/dist/server/schemas/stored-agents.d.ts +40 -7
- package/dist/server/schemas/stored-agents.d.ts.map +1 -1
- package/dist/server/server-adapter/index.cjs +6 -5
- package/dist/server/server-adapter/index.cjs.map +1 -1
- package/dist/server/server-adapter/index.js +4 -4
- package/dist/server/server-adapter/routes/datasets.d.ts +6 -6
- package/dist/{stored-agents-CPxfYRH9.cjs → stored-agents-D6JEb3zN.cjs} +15 -3
- package/dist/stored-agents-D6JEb3zN.cjs.map +1 -0
- package/dist/{stored-agents-BRBZM-Xl.js → stored-agents-DMW5wrF7.js} +15 -3
- package/dist/stored-agents-DMW5wrF7.js.map +1 -0
- package/dist/{stored-scorers-B__LF0Cy.js → stored-scorers-BA4suzgn.js} +2 -2
- package/dist/{stored-scorers-B__LF0Cy.js.map → stored-scorers-BA4suzgn.js.map} +1 -1
- package/dist/{stored-scorers-Cml7jPJv.cjs → stored-scorers-D8IwVM0S.cjs} +2 -2
- package/dist/{stored-scorers-Cml7jPJv.cjs.map → stored-scorers-D8IwVM0S.cjs.map} +1 -1
- package/dist/{sync-djJ8Lmds.js → sync-BG15Yae1.js} +22 -22
- package/dist/{sync-djJ8Lmds.js.map → sync-BG15Yae1.js.map} +1 -1
- package/dist/{sync-BHatXKfg.cjs → sync-C4LbbSKR.cjs} +22 -22
- package/dist/{sync-BHatXKfg.cjs.map → sync-C4LbbSKR.cjs.map} +1 -1
- package/dist/{utils-CljhO7OY.js → utils-B2vd77Fi.js} +2 -2
- package/dist/{utils-CljhO7OY.js.map → utils-B2vd77Fi.js.map} +1 -1
- package/dist/{utils-BkPZAGxS.cjs → utils-CmYnjLcY.cjs} +4 -4
- package/dist/{utils-BkPZAGxS.cjs.map → utils-CmYnjLcY.cjs.map} +1 -1
- package/dist/{utils-CXbhpYYv.cjs → utils-DJMUhfvY.cjs} +3 -3
- package/dist/{utils-CXbhpYYv.cjs.map → utils-DJMUhfvY.cjs.map} +1 -1
- package/dist/{utils-qMLbyf2U.js → utils-Hz8Hc2cd.js} +2 -2
- package/dist/{utils-qMLbyf2U.js.map → utils-Hz8Hc2cd.js.map} +1 -1
- package/package.json +9 -9
- package/dist/constants-CXPpy-Ef.cjs.map +0 -1
- package/dist/constants-CutMu4A_.js.map +0 -1
- package/dist/dist-C2O8fRb-.cjs.map +0 -1
- package/dist/dist-DNaReo7-.js.map +0 -1
- package/dist/probe-image-size-C2F59z8Z.cjs.map +0 -1
- package/dist/probe-image-size-mXCWYNrz.js.map +0 -1
- package/dist/schema-DkBbires.cjs +0 -1
- package/dist/stored-agents-BRBZM-Xl.js.map +0 -1
- package/dist/stored-agents-CPxfYRH9.cjs.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
2
|
-
const require_schema_Bv9OdW1f = require("./schema-Bv9OdW1f-
|
|
3
|
-
require("./schema-
|
|
4
|
-
const require_sync$1 = require("./sync-
|
|
5
|
-
const require_dist = require("./dist-
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-Bd6kNlEP.cjs");
|
|
2
|
+
const require_schema_Bv9OdW1f = require("./schema-Bv9OdW1f-CxTiW8RD.cjs");
|
|
3
|
+
require("./schema-CNKnRmv1.cjs");
|
|
4
|
+
const require_sync$1 = require("./sync-C4LbbSKR.cjs");
|
|
5
|
+
const require_dist = require("./dist-2zVeGGHi.cjs");
|
|
6
6
|
let zod_v4 = require("zod/v4");
|
|
7
7
|
zod_v4 = require_rolldown_runtime.__toESM(zod_v4, 1);
|
|
8
8
|
let _mastra_core_schema = require("@mastra/core/schema");
|
|
@@ -23,13 +23,13 @@ let _mastra_core_request_context = require("@mastra/core/request-context");
|
|
|
23
23
|
let _mastra_core_processors = require("@mastra/core/processors");
|
|
24
24
|
let _mastra_core_workflows = require("@mastra/core/workflows");
|
|
25
25
|
let fs = require("fs");
|
|
26
|
+
let os = require("os");
|
|
26
27
|
let path = require("path");
|
|
27
28
|
let module$1 = require("module");
|
|
28
29
|
let diagnostics_channel = require("diagnostics_channel");
|
|
29
30
|
let async_hooks = require("async_hooks");
|
|
30
31
|
let child_process = require("child_process");
|
|
31
32
|
let fs_promises = require("fs/promises");
|
|
32
|
-
let os = require("os");
|
|
33
33
|
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/async-mutex/0.5.0/4b32f2ae13cd0d7acb694455f7c2810d59202098580506b1730c21c7ab02798f/node_modules/async-mutex/index.mjs
|
|
34
34
|
const E_CANCELED = /* @__PURE__ */ new Error("request for lock canceled");
|
|
35
35
|
var __awaiter$2 = function(thisArg, _arguments, P, generator) {
|
|
@@ -4693,7 +4693,7 @@ function splitLines(text) {
|
|
|
4693
4693
|
return result;
|
|
4694
4694
|
}
|
|
4695
4695
|
//#endregion
|
|
4696
|
-
//#region ../memory/dist/src-
|
|
4696
|
+
//#region ../memory/dist/src-aTfbkxBl.js
|
|
4697
4697
|
var __defProp$3 = Object.defineProperty;
|
|
4698
4698
|
var __exportAll = (all, no_symbols) => {
|
|
4699
4699
|
let target = {};
|
|
@@ -19240,6 +19240,2388 @@ createIdGenerator$3({
|
|
|
19240
19240
|
prefix: "aiobj",
|
|
19241
19241
|
size: 24
|
|
19242
19242
|
});
|
|
19243
|
+
const BUILT_IN_SLUGS = /* @__PURE__ */ new Set([
|
|
19244
|
+
"current-task",
|
|
19245
|
+
"suggested-response",
|
|
19246
|
+
"thread-title"
|
|
19247
|
+
]);
|
|
19248
|
+
const EXTRACTED_VALUES_TAG = "extracted-values";
|
|
19249
|
+
const RESERVED_XML_TAGS = /* @__PURE__ */ new Set([
|
|
19250
|
+
"observations",
|
|
19251
|
+
"observation",
|
|
19252
|
+
EXTRACTED_VALUES_TAG,
|
|
19253
|
+
"thread",
|
|
19254
|
+
"message",
|
|
19255
|
+
"messages",
|
|
19256
|
+
"conversation",
|
|
19257
|
+
"history",
|
|
19258
|
+
"system",
|
|
19259
|
+
"user",
|
|
19260
|
+
"assistant",
|
|
19261
|
+
"tool",
|
|
19262
|
+
...BUILT_IN_SLUGS
|
|
19263
|
+
]);
|
|
19264
|
+
const BUILT_IN_EXTRACTOR_SLUGS = [...BUILT_IN_SLUGS];
|
|
19265
|
+
function isBuiltInExtractorSlug(slug) {
|
|
19266
|
+
return BUILT_IN_SLUGS.has(slug);
|
|
19267
|
+
}
|
|
19268
|
+
function slugifyExtractorName(name) {
|
|
19269
|
+
let normalized = "";
|
|
19270
|
+
let previousWasSeparator = false;
|
|
19271
|
+
for (const char of name.trim().toLowerCase()) {
|
|
19272
|
+
const code = char.charCodeAt(0);
|
|
19273
|
+
if (code >= 97 && code <= 122 || code >= 48 && code <= 57) {
|
|
19274
|
+
normalized += char;
|
|
19275
|
+
previousWasSeparator = false;
|
|
19276
|
+
continue;
|
|
19277
|
+
}
|
|
19278
|
+
if (char === "'" || char === "\"" || char === "`") continue;
|
|
19279
|
+
if (!previousWasSeparator && normalized.length > 0) {
|
|
19280
|
+
normalized += "-";
|
|
19281
|
+
previousWasSeparator = true;
|
|
19282
|
+
}
|
|
19283
|
+
}
|
|
19284
|
+
return normalized.endsWith("-") ? normalized.slice(0, -1) : normalized;
|
|
19285
|
+
}
|
|
19286
|
+
function assertValidSlug(slug, name) {
|
|
19287
|
+
if (!slug) throw new Error(`Extractor name "${name}" must produce a non-empty slug.`);
|
|
19288
|
+
const first = slug.charCodeAt(0);
|
|
19289
|
+
const last = slug.charCodeAt(slug.length - 1);
|
|
19290
|
+
const startsWithLetter = first >= 97 && first <= 122;
|
|
19291
|
+
const endsWithLetterOrNumber = last >= 97 && last <= 122 || last >= 48 && last <= 57;
|
|
19292
|
+
const hasOnlySlugCharacters = [...slug].every((char) => {
|
|
19293
|
+
const code = char.charCodeAt(0);
|
|
19294
|
+
return code >= 97 && code <= 122 || code >= 48 && code <= 57 || char === "-";
|
|
19295
|
+
});
|
|
19296
|
+
if (!startsWithLetter || !endsWithLetterOrNumber || !hasOnlySlugCharacters) throw new Error(`Extractor name "${name}" produced invalid slug "${slug}".`);
|
|
19297
|
+
}
|
|
19298
|
+
var Extractor = class Extractor {
|
|
19299
|
+
name;
|
|
19300
|
+
slug;
|
|
19301
|
+
instructions;
|
|
19302
|
+
schema;
|
|
19303
|
+
mode;
|
|
19304
|
+
includePreviousExtraction;
|
|
19305
|
+
metadataKeyPath;
|
|
19306
|
+
onExtracted;
|
|
19307
|
+
retryStructuredExtractionOnEmptyObject;
|
|
19308
|
+
/** @internal */
|
|
19309
|
+
internal;
|
|
19310
|
+
instructionsConfig;
|
|
19311
|
+
schemaConfig;
|
|
19312
|
+
constructor(config, internal = false) {
|
|
19313
|
+
const name = config.name.trim();
|
|
19314
|
+
const instructions = typeof config.instructions === "string" ? config.instructions.trim() : void 0;
|
|
19315
|
+
const slug = slugifyExtractorName(name);
|
|
19316
|
+
const isHook = config.mode === "hook";
|
|
19317
|
+
if (!name) throw new Error("Extractor name is required.");
|
|
19318
|
+
if (!isHook && !config.instructions) throw new Error(`Extractor "${name}" must include instructions.`);
|
|
19319
|
+
if (instructions !== void 0 && !instructions) throw new Error(`Extractor "${name}" must include instructions.`);
|
|
19320
|
+
if (isHook && !config.onExtracted) throw new Error(`Hook extractor "${name}" must include an onExtracted handler.`);
|
|
19321
|
+
if (isHook && (config.instructions || config.schema)) throw new Error(`Hook extractor "${name}" cannot include instructions or a schema.`);
|
|
19322
|
+
assertValidSlug(slug, name);
|
|
19323
|
+
if (!internal && RESERVED_XML_TAGS.has(slug)) throw new Error(`Extractor slug "${slug}" is reserved by Observational Memory.`);
|
|
19324
|
+
this.name = name;
|
|
19325
|
+
this.slug = slug;
|
|
19326
|
+
this.instructionsConfig = config.instructions ?? "";
|
|
19327
|
+
this.schemaConfig = config.schema;
|
|
19328
|
+
this.instructions = instructions ?? "";
|
|
19329
|
+
this.schema = isHook ? zod.z.unknown() : typeof config.schema === "function" ? zod.z.string() : config.schema ?? zod.z.string();
|
|
19330
|
+
this.mode = isHook ? "hook" : internal || !config.schema ? "inline" : "structured";
|
|
19331
|
+
this.includePreviousExtraction = isHook ? false : config.includePreviousExtraction ?? true;
|
|
19332
|
+
this.metadataKeyPath = isHook ? false : config.metadataKeyPath ?? `extracted.${slug}`;
|
|
19333
|
+
this.onExtracted = config.onExtracted;
|
|
19334
|
+
this.retryStructuredExtractionOnEmptyObject = config.retryStructuredExtractionOnEmptyObject ?? false;
|
|
19335
|
+
this.internal = internal;
|
|
19336
|
+
}
|
|
19337
|
+
async resolve(context) {
|
|
19338
|
+
if (this.mode === "hook") return this;
|
|
19339
|
+
const instructions = typeof this.instructionsConfig === "function" ? (await this.instructionsConfig(context)).trim() : this.instructionsConfig.trim();
|
|
19340
|
+
if (!instructions) throw new Error(`Extractor "${this.name}" must include instructions.`);
|
|
19341
|
+
const schema = typeof this.schemaConfig === "function" ? await this.schemaConfig(context) : this.schemaConfig;
|
|
19342
|
+
return new Extractor({
|
|
19343
|
+
name: this.name,
|
|
19344
|
+
instructions,
|
|
19345
|
+
...schema ? { schema } : {},
|
|
19346
|
+
includePreviousExtraction: this.includePreviousExtraction,
|
|
19347
|
+
metadataKeyPath: this.metadataKeyPath,
|
|
19348
|
+
onExtracted: this.onExtracted,
|
|
19349
|
+
retryStructuredExtractionOnEmptyObject: this.retryStructuredExtractionOnEmptyObject
|
|
19350
|
+
}, this.internal);
|
|
19351
|
+
}
|
|
19352
|
+
};
|
|
19353
|
+
async function resolveExtractors(extractors, context) {
|
|
19354
|
+
return Promise.all(extractors.map((extractor) => extractor.resolve(context)));
|
|
19355
|
+
}
|
|
19356
|
+
function validateExtractorList(extractors) {
|
|
19357
|
+
const seen = /* @__PURE__ */ new Map();
|
|
19358
|
+
for (const extractor of extractors) {
|
|
19359
|
+
assertValidSlug(extractor.slug, extractor.name);
|
|
19360
|
+
if (!extractor.internal && RESERVED_XML_TAGS.has(extractor.slug)) throw new Error(`Extractor slug "${extractor.slug}" is reserved by Observational Memory.`);
|
|
19361
|
+
const previous = seen.get(extractor.slug);
|
|
19362
|
+
if (previous) throw new Error(`Duplicate extractor slug "${extractor.slug}" from "${previous}" and "${extractor.name}".`);
|
|
19363
|
+
seen.set(extractor.slug, extractor.name);
|
|
19364
|
+
}
|
|
19365
|
+
return [...extractors];
|
|
19366
|
+
}
|
|
19367
|
+
function isJsonLike(value) {
|
|
19368
|
+
return /^(?:[\[{"-]|\d|true\b|false\b|null\b)/.test(value.trim());
|
|
19369
|
+
}
|
|
19370
|
+
function candidateValues(raw) {
|
|
19371
|
+
const trimmed = raw.trim();
|
|
19372
|
+
const candidates = [];
|
|
19373
|
+
const add = (value) => {
|
|
19374
|
+
if (!candidates.some((candidate) => Object.is(candidate, value))) candidates.push(value);
|
|
19375
|
+
};
|
|
19376
|
+
if (isJsonLike(trimmed)) try {
|
|
19377
|
+
add(JSON.parse(trimmed));
|
|
19378
|
+
} catch {}
|
|
19379
|
+
add(trimmed);
|
|
19380
|
+
if (!isJsonLike(trimmed)) try {
|
|
19381
|
+
add(JSON.parse(trimmed));
|
|
19382
|
+
} catch {}
|
|
19383
|
+
return candidates;
|
|
19384
|
+
}
|
|
19385
|
+
function parseExtractorValue(extractor, raw) {
|
|
19386
|
+
const failures = [];
|
|
19387
|
+
for (const candidate of candidateValues(raw)) {
|
|
19388
|
+
const parsed = extractor.schema.safeParse(candidate);
|
|
19389
|
+
if (parsed.success) return parsed.data;
|
|
19390
|
+
failures.push(parsed.error.message);
|
|
19391
|
+
}
|
|
19392
|
+
throw new Error(`Extractor "${extractor.slug}" output did not match its schema: ${failures[0] ?? "invalid value"}`);
|
|
19393
|
+
}
|
|
19394
|
+
function parseExtractedValuesObject(raw) {
|
|
19395
|
+
const trimmed = raw.trim();
|
|
19396
|
+
if (!trimmed || trimmed.startsWith("Write only the extracted values JSON object here.")) return;
|
|
19397
|
+
const parsed = JSON.parse(trimmed);
|
|
19398
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${EXTRACTED_VALUES_TAG} must contain a JSON object.`);
|
|
19399
|
+
return parsed;
|
|
19400
|
+
}
|
|
19401
|
+
function parseExtractedValues(output, extractors) {
|
|
19402
|
+
const values = {};
|
|
19403
|
+
const failures = [];
|
|
19404
|
+
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19405
|
+
const regex = new RegExp(`<${EXTRACTED_VALUES_TAG}>([\\s\\S]*?)<\\/${EXTRACTED_VALUES_TAG}>`, "gi");
|
|
19406
|
+
const matches = [...output.matchAll(regex)];
|
|
19407
|
+
for (const match of matches) try {
|
|
19408
|
+
const extractedValues = parseExtractedValuesObject(match[1] ?? "");
|
|
19409
|
+
if (!extractedValues) continue;
|
|
19410
|
+
for (const extractor of inlineExtractors) {
|
|
19411
|
+
if (!Object.prototype.hasOwnProperty.call(extractedValues, extractor.slug)) continue;
|
|
19412
|
+
const rawValue = extractedValues[extractor.slug];
|
|
19413
|
+
if (rawValue === void 0 || rawValue === null || rawValue === "") continue;
|
|
19414
|
+
const parsed = extractor.schema.safeParse(rawValue);
|
|
19415
|
+
if (parsed.success) values[extractor.slug] = parsed.data;
|
|
19416
|
+
else failures.push({
|
|
19417
|
+
slug: extractor.slug,
|
|
19418
|
+
error: parsed.error.message
|
|
19419
|
+
});
|
|
19420
|
+
}
|
|
19421
|
+
} catch (error) {
|
|
19422
|
+
failures.push({
|
|
19423
|
+
slug: EXTRACTED_VALUES_TAG,
|
|
19424
|
+
error: error instanceof Error ? error.message : String(error)
|
|
19425
|
+
});
|
|
19426
|
+
}
|
|
19427
|
+
for (const extractor of inlineExtractors) {
|
|
19428
|
+
if (Object.prototype.hasOwnProperty.call(values, extractor.slug)) continue;
|
|
19429
|
+
const tagRegex = new RegExp(`<${extractor.slug}>([\\s\\S]*?)<\\/${extractor.slug}>`, "gi");
|
|
19430
|
+
const rawValue = [...output.matchAll(tagRegex)].at(-1)?.[1]?.trim();
|
|
19431
|
+
if (!rawValue) continue;
|
|
19432
|
+
try {
|
|
19433
|
+
values[extractor.slug] = parseExtractorValue(extractor, rawValue);
|
|
19434
|
+
} catch (error) {
|
|
19435
|
+
failures.push({
|
|
19436
|
+
slug: extractor.slug,
|
|
19437
|
+
error: error instanceof Error ? error.message : String(error)
|
|
19438
|
+
});
|
|
19439
|
+
}
|
|
19440
|
+
}
|
|
19441
|
+
return {
|
|
19442
|
+
values,
|
|
19443
|
+
failures
|
|
19444
|
+
};
|
|
19445
|
+
}
|
|
19446
|
+
function stripExtractorSections(output, extractors) {
|
|
19447
|
+
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19448
|
+
let stripped = output.replace(new RegExp(`[ \\t]*<${EXTRACTED_VALUES_TAG}>[\\s\\S]*?<\\/${EXTRACTED_VALUES_TAG}>\\s*`, "gi"), "");
|
|
19449
|
+
for (const extractor of inlineExtractors) stripped = stripped.replace(new RegExp(`[ \\t]*<${extractor.slug}>[\\s\\S]*?<\\/${extractor.slug}>\\s*`, "gi"), "");
|
|
19450
|
+
return stripped;
|
|
19451
|
+
}
|
|
19452
|
+
function buildExtractorOutputSections(extractors) {
|
|
19453
|
+
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19454
|
+
if (inlineExtractors.length === 0) return "";
|
|
19455
|
+
return `Additional optional XML sections:\nIf the observations include information relevant to any of these tags, output that tag after <observations> and include the relevant information.\n${inlineExtractors.map((extractor) => `<${extractor.slug}>
|
|
19456
|
+
${extractor.instructions}
|
|
19457
|
+
Include this section when the observations contain relevant information for <${extractor.slug}>. Write only that information inside the tag.
|
|
19458
|
+
</${extractor.slug}>`).join("\n\n")}`;
|
|
19459
|
+
}
|
|
19460
|
+
function renderPriorValue(value) {
|
|
19461
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
19462
|
+
}
|
|
19463
|
+
function buildExtractorPriorLines(extractors, priorExtractedValues) {
|
|
19464
|
+
if (!priorExtractedValues) return [];
|
|
19465
|
+
const lines = [];
|
|
19466
|
+
for (const extractor of extractors) {
|
|
19467
|
+
if (!extractor.includePreviousExtraction) continue;
|
|
19468
|
+
const value = priorExtractedValues[extractor.slug];
|
|
19469
|
+
if (value === void 0 || value === null || value === "") continue;
|
|
19470
|
+
lines.push(`<${extractor.slug}>\n${renderPriorValue(value)}\n</${extractor.slug}>`);
|
|
19471
|
+
}
|
|
19472
|
+
return lines;
|
|
19473
|
+
}
|
|
19474
|
+
const SUBCONSCIOUS_ACTIVITY_STATE_ID = "subconscious-activity";
|
|
19475
|
+
async function getActivityTarget(store, event, scope) {
|
|
19476
|
+
if (event.recordType === "node") {
|
|
19477
|
+
const node = await store.getNode(event.recordId);
|
|
19478
|
+
if (!node || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope)) return {
|
|
19479
|
+
id: event.recordId,
|
|
19480
|
+
type: "node"
|
|
19481
|
+
};
|
|
19482
|
+
return {
|
|
19483
|
+
id: node.id,
|
|
19484
|
+
name: node.name,
|
|
19485
|
+
type: "node"
|
|
19486
|
+
};
|
|
19487
|
+
}
|
|
19488
|
+
const record = await store.getKnowledge({
|
|
19489
|
+
id: event.recordId,
|
|
19490
|
+
includeDeleted: true
|
|
19491
|
+
});
|
|
19492
|
+
const node = record ? await store.getNode(record.node) : void 0;
|
|
19493
|
+
if (!node || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope)) return {
|
|
19494
|
+
id: event.recordId,
|
|
19495
|
+
type: "node"
|
|
19496
|
+
};
|
|
19497
|
+
return {
|
|
19498
|
+
id: node.id,
|
|
19499
|
+
name: node.name,
|
|
19500
|
+
type: "node"
|
|
19501
|
+
};
|
|
19502
|
+
}
|
|
19503
|
+
async function buildSubconsciousActivitySnapshot(input) {
|
|
19504
|
+
const events = await input.store.listActivity({
|
|
19505
|
+
scope: input.scope,
|
|
19506
|
+
limit: input.recentUpdates
|
|
19507
|
+
});
|
|
19508
|
+
const resolvedUpdates = await Promise.all(events.map(async (event) => {
|
|
19509
|
+
const target = await getActivityTarget(input.store, event, input.scope);
|
|
19510
|
+
return {
|
|
19511
|
+
action: event.action,
|
|
19512
|
+
type: event.recordType,
|
|
19513
|
+
name: target.name,
|
|
19514
|
+
targetId: target.id,
|
|
19515
|
+
targetType: target.type,
|
|
19516
|
+
createdAt: event.createdAt.toISOString()
|
|
19517
|
+
};
|
|
19518
|
+
}));
|
|
19519
|
+
const hotByRecord = /* @__PURE__ */ new Map();
|
|
19520
|
+
for (const update of resolvedUpdates) {
|
|
19521
|
+
if (!update.name) continue;
|
|
19522
|
+
const key = `${update.targetType}:${update.targetId}`;
|
|
19523
|
+
const existing = hotByRecord.get(key);
|
|
19524
|
+
if (existing) existing.updates += 1;
|
|
19525
|
+
else hotByRecord.set(key, {
|
|
19526
|
+
type: update.targetType,
|
|
19527
|
+
name: update.name,
|
|
19528
|
+
updates: 1
|
|
19529
|
+
});
|
|
19530
|
+
}
|
|
19531
|
+
const hot = [...hotByRecord.values()].sort((a, b) => b.updates - a.updates || a.name.localeCompare(b.name)).slice(0, input.recentUpdates);
|
|
19532
|
+
const updates = resolvedUpdates.map((update) => ({
|
|
19533
|
+
action: update.action,
|
|
19534
|
+
type: update.type,
|
|
19535
|
+
...update.name ? { name: update.name } : {},
|
|
19536
|
+
createdAt: update.createdAt
|
|
19537
|
+
}));
|
|
19538
|
+
const errors = input.errors?.filter(Boolean).slice(0, input.recentUpdates);
|
|
19539
|
+
return {
|
|
19540
|
+
updates,
|
|
19541
|
+
hot,
|
|
19542
|
+
...errors?.length ? { errors } : {}
|
|
19543
|
+
};
|
|
19544
|
+
}
|
|
19545
|
+
function renderSubconsciousActivity(snapshot) {
|
|
19546
|
+
const lines = snapshot.updates.map((update) => {
|
|
19547
|
+
const target = update.name ? `${update.type} [[${update.name}]]` : update.type;
|
|
19548
|
+
return `- ${update.action}: ${target}`;
|
|
19549
|
+
});
|
|
19550
|
+
const hot = snapshot.hot.map((record) => `[[${record.name}]] (${record.updates})`).join(", ");
|
|
19551
|
+
return [
|
|
19552
|
+
hot ? `Hot: ${hot}` : "Hot: none",
|
|
19553
|
+
"Recent updates:",
|
|
19554
|
+
...lines.length ? lines : ["- none"],
|
|
19555
|
+
...snapshot.errors?.length ? ["Errors:", ...snapshot.errors.map((error) => `- ${error}`)] : []
|
|
19556
|
+
].join("\n");
|
|
19557
|
+
}
|
|
19558
|
+
async function publishSubconsciousError(input) {
|
|
19559
|
+
await input.writer?.custom({
|
|
19560
|
+
type: "data-subconscious-error",
|
|
19561
|
+
data: {
|
|
19562
|
+
error: input.error,
|
|
19563
|
+
agent: input.agent
|
|
19564
|
+
}
|
|
19565
|
+
});
|
|
19566
|
+
if (!input.sendStateSignal) return;
|
|
19567
|
+
const snapshot = {
|
|
19568
|
+
updates: [],
|
|
19569
|
+
hot: [],
|
|
19570
|
+
errors: [input.error]
|
|
19571
|
+
};
|
|
19572
|
+
const contents = renderSubconsciousActivity(snapshot);
|
|
19573
|
+
await input.sendStateSignal({
|
|
19574
|
+
id: SUBCONSCIOUS_ACTIVITY_STATE_ID,
|
|
19575
|
+
mode: "snapshot",
|
|
19576
|
+
cacheKey: (0, crypto$1.createHash)("sha256").update(contents).digest("hex"),
|
|
19577
|
+
tagName: "state",
|
|
19578
|
+
attributes: { id: SUBCONSCIOUS_ACTIVITY_STATE_ID },
|
|
19579
|
+
metadata: { origin: "subconscious" },
|
|
19580
|
+
contents,
|
|
19581
|
+
value: snapshot
|
|
19582
|
+
});
|
|
19583
|
+
}
|
|
19584
|
+
async function publishSubconsciousActivity(input) {
|
|
19585
|
+
if (!input.sendStateSignal) return void 0;
|
|
19586
|
+
const snapshot = await buildSubconsciousActivitySnapshot(input);
|
|
19587
|
+
const contents = renderSubconsciousActivity(snapshot);
|
|
19588
|
+
const cacheKey = (0, crypto$1.createHash)("sha256").update(contents).digest("hex");
|
|
19589
|
+
await input.sendStateSignal({
|
|
19590
|
+
id: SUBCONSCIOUS_ACTIVITY_STATE_ID,
|
|
19591
|
+
mode: "snapshot",
|
|
19592
|
+
cacheKey,
|
|
19593
|
+
tagName: "state",
|
|
19594
|
+
attributes: { id: SUBCONSCIOUS_ACTIVITY_STATE_ID },
|
|
19595
|
+
metadata: { origin: "subconscious" },
|
|
19596
|
+
contents,
|
|
19597
|
+
value: snapshot
|
|
19598
|
+
});
|
|
19599
|
+
return snapshot;
|
|
19600
|
+
}
|
|
19601
|
+
/** Processor id and state-signal id for the pinned-knowledge lane. */
|
|
19602
|
+
const SUBCONSCIOUS_PINS_STATE_ID = "subconscious-pins";
|
|
19603
|
+
/** Snapshot tag the model sees; the delta tag appends `-update`. */
|
|
19604
|
+
const PINNED_SNAPSHOT_TAG = "pinned-knowledge";
|
|
19605
|
+
const PINNED_DELTA_TAG = "pinned-knowledge-update";
|
|
19606
|
+
/** Reserved node holding the pin set. One record, at one fixed scope level. */
|
|
19607
|
+
const PINNED_NODE_NAME = "pinned";
|
|
19608
|
+
const PINNED_NODE_KIND = "system";
|
|
19609
|
+
const PINNED_NODE_SCOPE_LEVEL = "resource";
|
|
19610
|
+
const DEFAULT_PINNED_MAX_CHARACTERS = 2e3;
|
|
19611
|
+
const MAX_PINNED_MAX_CHARACTERS = 8e3;
|
|
19612
|
+
const PIN_IDENTITY = "subconscious:pin";
|
|
19613
|
+
function pinnedNodeScope(scope, maxScope) {
|
|
19614
|
+
return (0, _mastra_core_storage.expandKnowledgeScope)(scope, maxScope === "thread" ? "thread" : PINNED_NODE_SCOPE_LEVEL);
|
|
19615
|
+
}
|
|
19616
|
+
async function resolvePinnedNodeId(store, scope) {
|
|
19617
|
+
return (await store.resolveNode({
|
|
19618
|
+
name: PINNED_NODE_NAME,
|
|
19619
|
+
scope
|
|
19620
|
+
}))?.id;
|
|
19621
|
+
}
|
|
19622
|
+
/** Reuse the node wherever it is visible; otherwise create it. `createNode` is an idempotent upsert on (name, scope). */
|
|
19623
|
+
async function ensurePinnedNodeId(store, scope, maxScope) {
|
|
19624
|
+
const existing = await resolvePinnedNodeId(store, scope);
|
|
19625
|
+
if (existing) return existing;
|
|
19626
|
+
return (await store.createNode({
|
|
19627
|
+
name: PINNED_NODE_NAME,
|
|
19628
|
+
kind: PINNED_NODE_KIND,
|
|
19629
|
+
scope: pinnedNodeScope(scope, maxScope)
|
|
19630
|
+
})).id;
|
|
19631
|
+
}
|
|
19632
|
+
/**
|
|
19633
|
+
* Assembles the current pin set.
|
|
19634
|
+
*
|
|
19635
|
+
* Reads use the FULL visible scope context, never a level-narrowed write scope: visibility is
|
|
19636
|
+
* subset containment, so querying at the node's level would drop pins written at narrower
|
|
19637
|
+
* levels. Deleted records are excluded explicitly.
|
|
19638
|
+
*/
|
|
19639
|
+
async function listPinnedKnowledge(input) {
|
|
19640
|
+
const nodeId = await resolvePinnedNodeId(input.store, input.scope);
|
|
19641
|
+
if (!nodeId) return { pins: [] };
|
|
19642
|
+
const pins = [];
|
|
19643
|
+
let after;
|
|
19644
|
+
do {
|
|
19645
|
+
const page = await input.store.listKnowledgeAbout({
|
|
19646
|
+
node: nodeId,
|
|
19647
|
+
scope: input.scope,
|
|
19648
|
+
after,
|
|
19649
|
+
includeDeleted: false
|
|
19650
|
+
});
|
|
19651
|
+
pins.push(...page.records);
|
|
19652
|
+
after = page.nextCursor;
|
|
19653
|
+
} while (after);
|
|
19654
|
+
return {
|
|
19655
|
+
nodeId,
|
|
19656
|
+
pins
|
|
19657
|
+
};
|
|
19658
|
+
}
|
|
19659
|
+
function totalCharacters(pins) {
|
|
19660
|
+
return pins.reduce((sum, pin) => sum + pin.text.length, 0);
|
|
19661
|
+
}
|
|
19662
|
+
function assertBudget(options, pins, incomingText, replacing) {
|
|
19663
|
+
const kept = replacing ? pins.filter((pin) => pin.id !== replacing.id) : pins;
|
|
19664
|
+
if (!replacing && kept.length >= options.maxPins) throw new Error(`Pin limit reached: the set holds at most ${options.maxPins}. Unpin something first.`);
|
|
19665
|
+
if (totalCharacters(kept) + incomingText.length > options.maxCharacters) throw new Error(`Pin budget exceeded: the pin set is limited to ${options.maxCharacters} characters in total.`);
|
|
19666
|
+
}
|
|
19667
|
+
function clampPinLevel(level) {
|
|
19668
|
+
return level === "org" ? "resource" : level;
|
|
19669
|
+
}
|
|
19670
|
+
function resolveWriteScope$1(options, level) {
|
|
19671
|
+
let effective = clampPinLevel(level ?? options.defaultScope);
|
|
19672
|
+
if (!level && options.maxScope === "thread") effective = "thread";
|
|
19673
|
+
const scope = (0, _mastra_core_storage.expandKnowledgeScope)(options.scope, effective);
|
|
19674
|
+
(0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, options.maxScope);
|
|
19675
|
+
return scope;
|
|
19676
|
+
}
|
|
19677
|
+
const scopeLevelSchema$1 = {
|
|
19678
|
+
type: "string",
|
|
19679
|
+
enum: ["resource", "thread"]
|
|
19680
|
+
};
|
|
19681
|
+
/** Shared pin write path used by the tool and capture-time pinning. */
|
|
19682
|
+
async function writePinnedKnowledge(store, options, text, level, metadata) {
|
|
19683
|
+
const { pins } = await listPinnedKnowledge({
|
|
19684
|
+
store,
|
|
19685
|
+
scope: options.scope
|
|
19686
|
+
});
|
|
19687
|
+
assertBudget(options, pins, text);
|
|
19688
|
+
const nodeId = await ensurePinnedNodeId(store, options.scope, options.maxScope);
|
|
19689
|
+
return store.appendKnowledge({
|
|
19690
|
+
node: nodeId,
|
|
19691
|
+
text,
|
|
19692
|
+
scope: resolveWriteScope$1(options, level),
|
|
19693
|
+
sourceThreadId: options.sourceThreadId,
|
|
19694
|
+
maxScope: options.maxScope,
|
|
19695
|
+
metadata,
|
|
19696
|
+
resolutionScope: options.scope,
|
|
19697
|
+
defaultScope: (0, _mastra_core_storage.expandKnowledgeScope)(options.scope, options.defaultScope)
|
|
19698
|
+
});
|
|
19699
|
+
}
|
|
19700
|
+
async function getStore$1(memory) {
|
|
19701
|
+
const store = await memory.storage.getStore("knowledge");
|
|
19702
|
+
if (!store) throw new Error("Pinned knowledge requires a configured knowledge storage domain.");
|
|
19703
|
+
return store;
|
|
19704
|
+
}
|
|
19705
|
+
async function requirePin(store, recordId, options) {
|
|
19706
|
+
const record = await store.getKnowledge({
|
|
19707
|
+
id: recordId,
|
|
19708
|
+
includeDeleted: false
|
|
19709
|
+
});
|
|
19710
|
+
if (!record) throw new Error(`Pin not found: ${recordId}`);
|
|
19711
|
+
const nodeId = await resolvePinnedNodeId(store, options.scope);
|
|
19712
|
+
if (!nodeId || record.node !== nodeId) throw new Error(`Record is not a pin: ${recordId}`);
|
|
19713
|
+
if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(record.scope, options.scope)) throw new Error("Pin is outside the visible scope.");
|
|
19714
|
+
return record;
|
|
19715
|
+
}
|
|
19716
|
+
/**
|
|
19717
|
+
* Pin lifecycle tools. Pin appends a record on the reserved node; unpin soft-deletes it
|
|
19718
|
+
* (auditable, restorable); edit is remove plus append because knowledge records are immutable,
|
|
19719
|
+
* so an edited pin carries a new record id.
|
|
19720
|
+
*/
|
|
19721
|
+
function createPinnedTools(memory, options) {
|
|
19722
|
+
return {
|
|
19723
|
+
knowledge_pin: (0, _mastra_core_tools.createTool)({
|
|
19724
|
+
id: "knowledge_pin",
|
|
19725
|
+
description: "Pin knowledge that must stay in context every turn without being asked for. Pins cost context permanently; pin only what is unconditionally relevant.",
|
|
19726
|
+
inputSchema: {
|
|
19727
|
+
type: "object",
|
|
19728
|
+
properties: {
|
|
19729
|
+
text: {
|
|
19730
|
+
type: "string",
|
|
19731
|
+
minLength: 1
|
|
19732
|
+
},
|
|
19733
|
+
scope: scopeLevelSchema$1,
|
|
19734
|
+
reason: {
|
|
19735
|
+
type: "string",
|
|
19736
|
+
minLength: 1,
|
|
19737
|
+
description: "One short sentence: why this must stay in context permanently."
|
|
19738
|
+
}
|
|
19739
|
+
},
|
|
19740
|
+
required: ["text"],
|
|
19741
|
+
additionalProperties: false
|
|
19742
|
+
},
|
|
19743
|
+
execute: async (input) => {
|
|
19744
|
+
const value = input;
|
|
19745
|
+
return writePinnedKnowledge(await getStore$1(memory), options, value.text, value.scope, value.reason ? { reason: value.reason } : void 0);
|
|
19746
|
+
}
|
|
19747
|
+
}),
|
|
19748
|
+
knowledge_unpin: (0, _mastra_core_tools.createTool)({
|
|
19749
|
+
id: "knowledge_unpin",
|
|
19750
|
+
description: "Remove a pin. The underlying knowledge record is soft-deleted and drops out of the pinned context.",
|
|
19751
|
+
inputSchema: {
|
|
19752
|
+
type: "object",
|
|
19753
|
+
properties: { recordId: {
|
|
19754
|
+
type: "string",
|
|
19755
|
+
minLength: 1
|
|
19756
|
+
} },
|
|
19757
|
+
required: ["recordId"],
|
|
19758
|
+
additionalProperties: false
|
|
19759
|
+
},
|
|
19760
|
+
execute: async (input) => {
|
|
19761
|
+
const store = await getStore$1(memory);
|
|
19762
|
+
const record = await requirePin(store, input.recordId, options);
|
|
19763
|
+
return store.removeKnowledge({
|
|
19764
|
+
id: record.id,
|
|
19765
|
+
deletedBy: PIN_IDENTITY
|
|
19766
|
+
});
|
|
19767
|
+
}
|
|
19768
|
+
}),
|
|
19769
|
+
knowledge_edit_pin: (0, _mastra_core_tools.createTool)({
|
|
19770
|
+
id: "knowledge_edit_pin",
|
|
19771
|
+
description: "Replace the text of an existing pin. The replacement carries a new knowledge record id.",
|
|
19772
|
+
inputSchema: {
|
|
19773
|
+
type: "object",
|
|
19774
|
+
properties: {
|
|
19775
|
+
recordId: {
|
|
19776
|
+
type: "string",
|
|
19777
|
+
minLength: 1
|
|
19778
|
+
},
|
|
19779
|
+
text: {
|
|
19780
|
+
type: "string",
|
|
19781
|
+
minLength: 1
|
|
19782
|
+
},
|
|
19783
|
+
reason: {
|
|
19784
|
+
type: "string",
|
|
19785
|
+
minLength: 1,
|
|
19786
|
+
description: "One short sentence: why this must stay in context permanently."
|
|
19787
|
+
}
|
|
19788
|
+
},
|
|
19789
|
+
required: ["recordId", "text"],
|
|
19790
|
+
additionalProperties: false
|
|
19791
|
+
},
|
|
19792
|
+
execute: async (input) => {
|
|
19793
|
+
const value = input;
|
|
19794
|
+
const store = await getStore$1(memory);
|
|
19795
|
+
const record = await requirePin(store, value.recordId, options);
|
|
19796
|
+
const { pins } = await listPinnedKnowledge({
|
|
19797
|
+
store,
|
|
19798
|
+
scope: options.scope
|
|
19799
|
+
});
|
|
19800
|
+
assertBudget(options, pins, value.text, record);
|
|
19801
|
+
await store.removeKnowledge({
|
|
19802
|
+
id: record.id,
|
|
19803
|
+
deletedBy: PIN_IDENTITY
|
|
19804
|
+
});
|
|
19805
|
+
return store.appendKnowledge({
|
|
19806
|
+
node: record.node,
|
|
19807
|
+
text: value.text,
|
|
19808
|
+
scope: record.scope,
|
|
19809
|
+
sourceThreadId: options.sourceThreadId,
|
|
19810
|
+
maxScope: record.maxScope,
|
|
19811
|
+
metadata: value.reason ? {
|
|
19812
|
+
...record.metadata,
|
|
19813
|
+
reason: value.reason
|
|
19814
|
+
} : record.metadata,
|
|
19815
|
+
resolutionScope: options.scope,
|
|
19816
|
+
defaultScope: (0, _mastra_core_storage.expandKnowledgeScope)(options.scope, options.defaultScope)
|
|
19817
|
+
});
|
|
19818
|
+
}
|
|
19819
|
+
})
|
|
19820
|
+
};
|
|
19821
|
+
}
|
|
19822
|
+
/**
|
|
19823
|
+
* Resolves the resource rung of a subconscious knowledge scope.
|
|
19824
|
+
*
|
|
19825
|
+
* When the request context carries a `knowledgeResourceId` override, every
|
|
19826
|
+
* scope resolver anchors the resource rung on it instead of the run's
|
|
19827
|
+
* resourceId. This lets a host (for example, the factory) share one knowledge
|
|
19828
|
+
* graph across many runs of the same project while leaving thread identity and
|
|
19829
|
+
* observational memory untouched. Without the override, behavior is unchanged:
|
|
19830
|
+
* the fallback (the run's resourceId) is used as-is.
|
|
19831
|
+
*/
|
|
19832
|
+
function resolveKnowledgeResourceId(requestContext, fallback) {
|
|
19833
|
+
const override = requestContext?.get?.("knowledgeResourceId");
|
|
19834
|
+
if (typeof override === "string" && override.trim()) return override;
|
|
19835
|
+
return fallback;
|
|
19836
|
+
}
|
|
19837
|
+
const CAPTURE_GUIDANCE_PAGE = "capture-guidance";
|
|
19838
|
+
const MAX_CAPTURE_GUIDANCE_LENGTH = 4e3;
|
|
19839
|
+
const SCOPE_ORDER = {
|
|
19840
|
+
org: 0,
|
|
19841
|
+
resource: 1,
|
|
19842
|
+
thread: 2
|
|
19843
|
+
};
|
|
19844
|
+
const subconsciousCaptureSchema = zod.z.object({ nodes: zod.z.array(zod.z.object({
|
|
19845
|
+
name: zod.z.string().trim().min(1),
|
|
19846
|
+
kind: zod.z.string().trim().min(1),
|
|
19847
|
+
scope: zod.z.enum([
|
|
19848
|
+
"org",
|
|
19849
|
+
"resource",
|
|
19850
|
+
"thread"
|
|
19851
|
+
]).optional(),
|
|
19852
|
+
records: zod.z.array(zod.z.object({
|
|
19853
|
+
text: zod.z.string().trim().min(1),
|
|
19854
|
+
scope: zod.z.enum([
|
|
19855
|
+
"org",
|
|
19856
|
+
"resource",
|
|
19857
|
+
"thread"
|
|
19858
|
+
]).optional(),
|
|
19859
|
+
when: zod.z.string().trim().min(1).optional(),
|
|
19860
|
+
reason: zod.z.string().trim().min(1)
|
|
19861
|
+
}))
|
|
19862
|
+
})) });
|
|
19863
|
+
const subconsciousCapturePinningSchema = zod.z.object({ nodes: zod.z.array(zod.z.object({
|
|
19864
|
+
name: zod.z.string().trim().min(1),
|
|
19865
|
+
kind: zod.z.string().trim().min(1),
|
|
19866
|
+
scope: zod.z.enum([
|
|
19867
|
+
"org",
|
|
19868
|
+
"resource",
|
|
19869
|
+
"thread"
|
|
19870
|
+
]).optional(),
|
|
19871
|
+
records: zod.z.array(zod.z.object({
|
|
19872
|
+
text: zod.z.string().trim().min(1),
|
|
19873
|
+
scope: zod.z.enum([
|
|
19874
|
+
"org",
|
|
19875
|
+
"resource",
|
|
19876
|
+
"thread"
|
|
19877
|
+
]).optional(),
|
|
19878
|
+
when: zod.z.string().trim().min(1).optional(),
|
|
19879
|
+
reason: zod.z.string().trim().min(1),
|
|
19880
|
+
pin: zod.z.boolean().optional()
|
|
19881
|
+
}))
|
|
19882
|
+
})) });
|
|
19883
|
+
const CAPTURE_PINNING_INSTRUCTIONS = `Mark pin: true only for durable user preferences or hard constraints that should apply in every future session without being asked for.`;
|
|
19884
|
+
const CAPTURE_INSTRUCTIONS = `Extract durable, explicitly stated knowledge from the observations.
|
|
19885
|
+
Return nodes with short stable names, a freeform kind, and knowledge records nested under the node each record is about.
|
|
19886
|
+
Use common kinds such as person, task, event, project, organization, or document when they fit.
|
|
19887
|
+
Set node scope to the narrowest level where that identity and content should be shared. Omit it to use the configured default scope.
|
|
19888
|
+
Knowledge records must be grounded in the conversation, concise, and written as prose. Do not infer unstated information.
|
|
19889
|
+
Wrap every named node mentioned in record text in [[wikilinks]].
|
|
19890
|
+
Set a record scope only when the conversation establishes where it applies. Use org for organization-wide records, resource for records shared across this resource's conversations, and thread for conversation-private records.
|
|
19891
|
+
Omit scope when uncertain; omitted record scopes stay private to the current thread.
|
|
19892
|
+
Emit when only when the conversation anchors the referred time. Resolve relative dates against the current date and use ISO 8601.
|
|
19893
|
+
Capture what was learned through the work, not what the session was told: skip records that merely restate standing instructions, configured rules, or the text of the task or issue the session was handed. The exception is an explicit request from the user to remember something, which is always captured even when it duplicates an existing instruction.`;
|
|
19894
|
+
const CAPTURE_REASON_INSTRUCTIONS = `Every record requires a reason: the concrete why behind capturing it, in one short sentence - what it cost to learn or when it will matter again (and for pinned records, why it must stay in context). Never write generic filler such as "seemed relevant" or "useful context".`;
|
|
19895
|
+
function clampScope(level, ceiling) {
|
|
19896
|
+
return ceiling && SCOPE_ORDER[level] < SCOPE_ORDER[ceiling] ? ceiling : level;
|
|
19897
|
+
}
|
|
19898
|
+
function requireScopeContext(context) {
|
|
19899
|
+
const organizationId = context.requestContext?.get("organizationId");
|
|
19900
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) throw new Error("Subconscious requires requestContext.organizationId to derive scoped knowledge. Set organizationId on the request context for this conversation.");
|
|
19901
|
+
const resourceId = resolveKnowledgeResourceId(context.requestContext, context.resourceId);
|
|
19902
|
+
if (!resourceId) throw new Error("Subconscious requires resourceId to derive scoped knowledge.");
|
|
19903
|
+
if (!context.threadId) throw new Error("Subconscious requires threadId to derive scoped knowledge.");
|
|
19904
|
+
return [
|
|
19905
|
+
`org:${organizationId}`,
|
|
19906
|
+
`resource:${resourceId}`,
|
|
19907
|
+
`thread:${context.threadId}`
|
|
19908
|
+
];
|
|
19909
|
+
}
|
|
19910
|
+
async function getKnowledgeStore$1(context) {
|
|
19911
|
+
if (!context.memory) throw new Error("Subconscious capture requires an active Memory instance.");
|
|
19912
|
+
const store = await context.memory.storage.getStore("knowledge");
|
|
19913
|
+
if (!store) throw new Error("Subconscious requires a knowledge storage domain. Configure a storage adapter that provides stores.knowledge.");
|
|
19914
|
+
return store;
|
|
19915
|
+
}
|
|
19916
|
+
function parseWhen(value) {
|
|
19917
|
+
if (!value) return void 0;
|
|
19918
|
+
const when = new Date(value);
|
|
19919
|
+
if (Number.isNaN(when.getTime())) throw new Error(`Invalid Subconscious record time: ${value}`);
|
|
19920
|
+
return when;
|
|
19921
|
+
}
|
|
19922
|
+
var SubconsciousCaptureExtractor = class extends Extractor {
|
|
19923
|
+
constructor(options) {
|
|
19924
|
+
const capturePinning = options.pins !== false && options.pins !== void 0 && options.pins.capturePinning;
|
|
19925
|
+
const pinNotes = /* @__PURE__ */ new WeakMap();
|
|
19926
|
+
const defaultImplementation = async (context) => {
|
|
19927
|
+
const scopeContext = requireScopeContext(context);
|
|
19928
|
+
const store = await getKnowledgeStore$1(context);
|
|
19929
|
+
const droppedPins = [];
|
|
19930
|
+
for (const extractedNode of context.current.nodes) {
|
|
19931
|
+
const nodeScope = (0, _mastra_core_storage.expandKnowledgeScope)(scopeContext, clampScope(extractedNode.scope ?? options.defaultScope, options.maxScope));
|
|
19932
|
+
const node = await store.createNode({
|
|
19933
|
+
name: extractedNode.name,
|
|
19934
|
+
kind: extractedNode.kind,
|
|
19935
|
+
scope: nodeScope
|
|
19936
|
+
});
|
|
19937
|
+
for (const extractedKnowledge of extractedNode.records) {
|
|
19938
|
+
if (capturePinning && extractedKnowledge.pin === true && options.pins) {
|
|
19939
|
+
try {
|
|
19940
|
+
await writePinnedKnowledge(store, {
|
|
19941
|
+
scope: scopeContext,
|
|
19942
|
+
sourceThreadId: context.threadId,
|
|
19943
|
+
defaultScope: options.defaultScope,
|
|
19944
|
+
maxScope: options.maxScope,
|
|
19945
|
+
maxPins: options.pins.maxPins,
|
|
19946
|
+
maxCharacters: options.pins.maxCharacters
|
|
19947
|
+
}, extractedKnowledge.text, extractedKnowledge.scope, extractedKnowledge.reason ? { reason: extractedKnowledge.reason } : void 0);
|
|
19948
|
+
} catch (error) {
|
|
19949
|
+
droppedPins.push(`Capture-time pin dropped: ${error instanceof Error ? error.message : String(error)}`);
|
|
19950
|
+
}
|
|
19951
|
+
continue;
|
|
19952
|
+
}
|
|
19953
|
+
const knowledgeLevel = clampScope(extractedKnowledge.scope ?? "thread", options.maxScope);
|
|
19954
|
+
await store.appendKnowledge({
|
|
19955
|
+
node,
|
|
19956
|
+
text: extractedKnowledge.text,
|
|
19957
|
+
scope: (0, _mastra_core_storage.expandKnowledgeScope)(scopeContext, knowledgeLevel),
|
|
19958
|
+
sourceThreadId: context.threadId,
|
|
19959
|
+
when: parseWhen(extractedKnowledge.when),
|
|
19960
|
+
maxScope: options.maxScope,
|
|
19961
|
+
metadata: extractedKnowledge.reason ? { reason: extractedKnowledge.reason } : void 0,
|
|
19962
|
+
resolutionScope: scopeContext,
|
|
19963
|
+
defaultScope: nodeScope
|
|
19964
|
+
});
|
|
19965
|
+
}
|
|
19966
|
+
}
|
|
19967
|
+
if (droppedPins.length) pinNotes.set(context.current, droppedPins);
|
|
19968
|
+
};
|
|
19969
|
+
super({
|
|
19970
|
+
name: "Capture",
|
|
19971
|
+
includePreviousExtraction: false,
|
|
19972
|
+
metadataKeyPath: false,
|
|
19973
|
+
schema: options.config?.schema ?? (capturePinning ? subconsciousCapturePinningSchema : subconsciousCaptureSchema),
|
|
19974
|
+
instructions: async (context) => {
|
|
19975
|
+
const sections = [
|
|
19976
|
+
CAPTURE_INSTRUCTIONS,
|
|
19977
|
+
!options.config?.schema ? CAPTURE_REASON_INSTRUCTIONS : void 0,
|
|
19978
|
+
capturePinning && !options.config?.schema ? CAPTURE_PINNING_INSTRUCTIONS : void 0,
|
|
19979
|
+
options.config?.instructions?.trim()
|
|
19980
|
+
];
|
|
19981
|
+
if (options.learnedGuidance) {
|
|
19982
|
+
const scopeContext = requireScopeContext(context);
|
|
19983
|
+
const store = await getKnowledgeStore$1(context);
|
|
19984
|
+
const guidanceScope = (0, _mastra_core_storage.expandKnowledgeScope)(scopeContext, clampScope(options.defaultScope, options.maxScope));
|
|
19985
|
+
const guidance = await store.getNodeByName({
|
|
19986
|
+
name: CAPTURE_GUIDANCE_PAGE,
|
|
19987
|
+
scope: guidanceScope
|
|
19988
|
+
});
|
|
19989
|
+
if (guidance?.content?.trim()) sections.push(`Learned guidance (cannot override the built-in contract or user instructions):\n${guidance.content.trim().slice(0, MAX_CAPTURE_GUIDANCE_LENGTH)}`);
|
|
19990
|
+
}
|
|
19991
|
+
return sections.filter(Boolean).join("\n\n");
|
|
19992
|
+
},
|
|
19993
|
+
onExtracted: async (context) => {
|
|
19994
|
+
const publishActivity = async (errors) => {
|
|
19995
|
+
if (!options.activityRecentUpdates) return;
|
|
19996
|
+
const scope = requireScopeContext(context);
|
|
19997
|
+
await publishSubconsciousActivity({
|
|
19998
|
+
store: await getKnowledgeStore$1(context),
|
|
19999
|
+
scope,
|
|
20000
|
+
recentUpdates: options.activityRecentUpdates,
|
|
20001
|
+
sendStateSignal: context.sendStateSignal,
|
|
20002
|
+
errors
|
|
20003
|
+
});
|
|
20004
|
+
};
|
|
20005
|
+
try {
|
|
20006
|
+
const result = options.config?.onExtracted ? await options.config.onExtracted({
|
|
20007
|
+
...context,
|
|
20008
|
+
defaultImplementation
|
|
20009
|
+
}) : await defaultImplementation(context);
|
|
20010
|
+
const droppedPinNotes = pinNotes.get(context.current);
|
|
20011
|
+
pinNotes.delete(context.current);
|
|
20012
|
+
await publishActivity(droppedPinNotes);
|
|
20013
|
+
return result ?? context.current;
|
|
20014
|
+
} catch (error) {
|
|
20015
|
+
await publishActivity([error instanceof Error ? error.message : String(error)]).catch(() => {});
|
|
20016
|
+
throw error;
|
|
20017
|
+
}
|
|
20018
|
+
}
|
|
20019
|
+
});
|
|
20020
|
+
}
|
|
20021
|
+
};
|
|
20022
|
+
const DEFAULT_LIMIT = 10;
|
|
20023
|
+
const MAX_LIMIT = 50;
|
|
20024
|
+
function resolveScope$3(context) {
|
|
20025
|
+
const organizationId = context?.requestContext?.get("organizationId");
|
|
20026
|
+
const resourceId = resolveKnowledgeResourceId(context?.requestContext, context?.agent?.resourceId);
|
|
20027
|
+
const threadId = context?.agent?.threadId;
|
|
20028
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) throw new Error("Knowledge tools require requestContext.organizationId.");
|
|
20029
|
+
if (!resourceId) throw new Error("Knowledge tools require an active resourceId.");
|
|
20030
|
+
if (!threadId) throw new Error("Knowledge tools require an active threadId.");
|
|
20031
|
+
return [
|
|
20032
|
+
`org:${organizationId}`,
|
|
20033
|
+
`resource:${resourceId}`,
|
|
20034
|
+
`thread:${threadId}`
|
|
20035
|
+
];
|
|
20036
|
+
}
|
|
20037
|
+
async function getKnowledgeStore(memory) {
|
|
20038
|
+
const store = await memory.storage.getStore("knowledge");
|
|
20039
|
+
if (!store) throw new Error("Knowledge tools require a configured knowledge storage domain.");
|
|
20040
|
+
return store;
|
|
20041
|
+
}
|
|
20042
|
+
function normalizeLimit(limit) {
|
|
20043
|
+
return Math.min(Math.max(limit ?? DEFAULT_LIMIT, 1), MAX_LIMIT);
|
|
20044
|
+
}
|
|
20045
|
+
function serializeRecord(record) {
|
|
20046
|
+
return {
|
|
20047
|
+
id: record.id,
|
|
20048
|
+
text: record.text,
|
|
20049
|
+
scope: record.scope,
|
|
20050
|
+
sourceThreadId: record.sourceThreadId,
|
|
20051
|
+
capturedAt: record.capturedAt.toISOString(),
|
|
20052
|
+
when: record.when?.toISOString()
|
|
20053
|
+
};
|
|
20054
|
+
}
|
|
20055
|
+
function serializeNode(node) {
|
|
20056
|
+
return {
|
|
20057
|
+
id: node.id,
|
|
20058
|
+
type: node.type,
|
|
20059
|
+
name: node.name,
|
|
20060
|
+
kind: node.kind,
|
|
20061
|
+
content: node.content,
|
|
20062
|
+
scope: node.scope,
|
|
20063
|
+
version: node.version,
|
|
20064
|
+
updatedAt: node.updatedAt.toISOString()
|
|
20065
|
+
};
|
|
20066
|
+
}
|
|
20067
|
+
async function loadSemanticResult(store, scope, candidate) {
|
|
20068
|
+
const type = candidate.metadata?.document_type;
|
|
20069
|
+
if (type === "node") {
|
|
20070
|
+
const node = await store.getNode(candidate.id.slice(15));
|
|
20071
|
+
if (!node || node.mergedInto || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope)) return null;
|
|
20072
|
+
return {
|
|
20073
|
+
type: "node",
|
|
20074
|
+
id: node.id,
|
|
20075
|
+
recordId: node.id,
|
|
20076
|
+
name: node.name,
|
|
20077
|
+
text: `${node.name}\n${node.content ?? ""}`,
|
|
20078
|
+
scope: node.scope,
|
|
20079
|
+
semanticScore: candidate.score
|
|
20080
|
+
};
|
|
20081
|
+
}
|
|
20082
|
+
if (type === "record") {
|
|
20083
|
+
const record = await store.getKnowledge({ id: candidate.id.slice(17) });
|
|
20084
|
+
if (!record || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(record.scope, scope)) return null;
|
|
20085
|
+
const node = await store.getNode(record.node);
|
|
20086
|
+
const parentVisible = Boolean(node && !node.mergedInto && (0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope));
|
|
20087
|
+
return {
|
|
20088
|
+
type: "record",
|
|
20089
|
+
id: record.id,
|
|
20090
|
+
recordId: parentVisible ? node.id : record.id,
|
|
20091
|
+
name: parentVisible ? node.name : "(private node)",
|
|
20092
|
+
text: record.text,
|
|
20093
|
+
scope: record.scope,
|
|
20094
|
+
semanticScore: candidate.score
|
|
20095
|
+
};
|
|
20096
|
+
}
|
|
20097
|
+
return null;
|
|
20098
|
+
}
|
|
20099
|
+
function mergeHybridResults(lexical, semantic, limit) {
|
|
20100
|
+
const ranked = /* @__PURE__ */ new Map();
|
|
20101
|
+
lexical.forEach((result, index) => {
|
|
20102
|
+
ranked.set(`${result.type}:${result.id}`, {
|
|
20103
|
+
...result,
|
|
20104
|
+
score: 1 / (60 + index + 1),
|
|
20105
|
+
sources: ["lexical"]
|
|
20106
|
+
});
|
|
20107
|
+
});
|
|
20108
|
+
semantic.forEach((result, index) => {
|
|
20109
|
+
const key = `${result.type}:${result.id}`;
|
|
20110
|
+
const existing = ranked.get(key);
|
|
20111
|
+
const reciprocalRank = 1 / (60 + index + 1);
|
|
20112
|
+
ranked.set(key, {
|
|
20113
|
+
...result,
|
|
20114
|
+
score: (existing?.score ?? 0) + reciprocalRank,
|
|
20115
|
+
sources: existing ? ["lexical", "semantic"] : ["semantic"],
|
|
20116
|
+
semanticScore: result.semanticScore
|
|
20117
|
+
});
|
|
20118
|
+
});
|
|
20119
|
+
return [...ranked.values()].sort((left, right) => right.score - left.score || left.id.localeCompare(right.id)).slice(0, limit);
|
|
20120
|
+
}
|
|
20121
|
+
function createKnowledgeTools(memory, fixedScope) {
|
|
20122
|
+
return {
|
|
20123
|
+
knowledge_search: (0, _mastra_core_tools.createTool)({
|
|
20124
|
+
id: "knowledge_search",
|
|
20125
|
+
description: "Search durable scoped knowledge across nodes and knowledge records using lexical and semantic retrieval.",
|
|
20126
|
+
inputSchema: {
|
|
20127
|
+
type: "object",
|
|
20128
|
+
properties: {
|
|
20129
|
+
query: {
|
|
20130
|
+
type: "string",
|
|
20131
|
+
minLength: 1,
|
|
20132
|
+
description: "The knowledge to search for."
|
|
20133
|
+
},
|
|
20134
|
+
limit: {
|
|
20135
|
+
type: "integer",
|
|
20136
|
+
minimum: 1,
|
|
20137
|
+
maximum: MAX_LIMIT,
|
|
20138
|
+
description: "Maximum results. Defaults to 10."
|
|
20139
|
+
}
|
|
20140
|
+
},
|
|
20141
|
+
required: ["query"],
|
|
20142
|
+
additionalProperties: false
|
|
20143
|
+
},
|
|
20144
|
+
execute: async (input, context) => {
|
|
20145
|
+
const { query, limit: requestedLimit } = input;
|
|
20146
|
+
const scope = fixedScope ?? resolveScope$3(context);
|
|
20147
|
+
const limit = normalizeLimit(requestedLimit);
|
|
20148
|
+
const store = await getKnowledgeStore(memory);
|
|
20149
|
+
const semanticCandidates = await memory.getKnowledgeSemanticIndex().then((index) => index.search(query, scope, limit * 2));
|
|
20150
|
+
return {
|
|
20151
|
+
query,
|
|
20152
|
+
results: mergeHybridResults(await store.search({
|
|
20153
|
+
query,
|
|
20154
|
+
scope,
|
|
20155
|
+
limit: limit * 2
|
|
20156
|
+
}), (await Promise.all(semanticCandidates.map((candidate) => loadSemanticResult(store, scope, candidate)))).filter((result) => Boolean(result)), limit)
|
|
20157
|
+
};
|
|
20158
|
+
}
|
|
20159
|
+
}),
|
|
20160
|
+
knowledge_read: (0, _mastra_core_tools.createTool)({
|
|
20161
|
+
id: "knowledge_read",
|
|
20162
|
+
description: "Read a knowledge node, its content, and knowledge records about or linked to it by name or ID.",
|
|
20163
|
+
inputSchema: {
|
|
20164
|
+
type: "object",
|
|
20165
|
+
properties: {
|
|
20166
|
+
id: {
|
|
20167
|
+
type: "string",
|
|
20168
|
+
minLength: 1
|
|
20169
|
+
},
|
|
20170
|
+
name: {
|
|
20171
|
+
type: "string",
|
|
20172
|
+
minLength: 1
|
|
20173
|
+
},
|
|
20174
|
+
relationship: {
|
|
20175
|
+
type: "string",
|
|
20176
|
+
enum: [
|
|
20177
|
+
"about",
|
|
20178
|
+
"mentioning",
|
|
20179
|
+
"related"
|
|
20180
|
+
],
|
|
20181
|
+
description: "Knowledge relationship to query. Defaults to about."
|
|
20182
|
+
},
|
|
20183
|
+
cursor: {
|
|
20184
|
+
type: "string",
|
|
20185
|
+
minLength: 1,
|
|
20186
|
+
description: "Return knowledge records after this record ULID."
|
|
20187
|
+
},
|
|
20188
|
+
limit: {
|
|
20189
|
+
type: "integer",
|
|
20190
|
+
minimum: 1,
|
|
20191
|
+
maximum: MAX_LIMIT
|
|
20192
|
+
}
|
|
20193
|
+
},
|
|
20194
|
+
additionalProperties: false
|
|
20195
|
+
},
|
|
20196
|
+
execute: async (input, context) => {
|
|
20197
|
+
const { id, name, relationship = "about", cursor, limit: requestedLimit } = input;
|
|
20198
|
+
if (!id && !name) throw new Error("knowledge_read requires id or name.");
|
|
20199
|
+
const scope = fixedScope ?? resolveScope$3(context);
|
|
20200
|
+
const store = await getKnowledgeStore(memory);
|
|
20201
|
+
const node = id ? await store.getNode(id) : await store.resolveNode({
|
|
20202
|
+
name,
|
|
20203
|
+
scope
|
|
20204
|
+
});
|
|
20205
|
+
if (!node || node.mergedInto || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope)) return { found: false };
|
|
20206
|
+
const result = await (relationship === "related" ? store.listKnowledgeRelatedTo : relationship === "mentioning" ? store.listKnowledgeMentioning : store.listKnowledgeAbout).call(store, {
|
|
20207
|
+
node,
|
|
20208
|
+
scope,
|
|
20209
|
+
after: cursor,
|
|
20210
|
+
limit: normalizeLimit(requestedLimit)
|
|
20211
|
+
});
|
|
20212
|
+
return {
|
|
20213
|
+
found: true,
|
|
20214
|
+
node: serializeNode(node),
|
|
20215
|
+
records: result.records.map(serializeRecord),
|
|
20216
|
+
nextCursor: result.nextCursor
|
|
20217
|
+
};
|
|
20218
|
+
}
|
|
20219
|
+
}),
|
|
20220
|
+
knowledge_browse: (0, _mastra_core_tools.createTool)({
|
|
20221
|
+
id: "knowledge_browse",
|
|
20222
|
+
description: "Browse visible knowledge nodes by scope and name prefix, or follow a node’s mentions and backlinks.",
|
|
20223
|
+
inputSchema: {
|
|
20224
|
+
type: "object",
|
|
20225
|
+
properties: {
|
|
20226
|
+
namePrefix: { type: "string" },
|
|
20227
|
+
kind: {
|
|
20228
|
+
type: "string",
|
|
20229
|
+
description: "Optional node kind filter."
|
|
20230
|
+
},
|
|
20231
|
+
hasContent: {
|
|
20232
|
+
type: "boolean",
|
|
20233
|
+
description: "Filter nodes by whether they have long-form content."
|
|
20234
|
+
},
|
|
20235
|
+
node: {
|
|
20236
|
+
type: "string",
|
|
20237
|
+
minLength: 1,
|
|
20238
|
+
description: "When set, return knowledge related to this node."
|
|
20239
|
+
},
|
|
20240
|
+
cursor: {
|
|
20241
|
+
type: "string",
|
|
20242
|
+
minLength: 1
|
|
20243
|
+
},
|
|
20244
|
+
limit: {
|
|
20245
|
+
type: "integer",
|
|
20246
|
+
minimum: 1,
|
|
20247
|
+
maximum: MAX_LIMIT
|
|
20248
|
+
}
|
|
20249
|
+
},
|
|
20250
|
+
additionalProperties: false
|
|
20251
|
+
},
|
|
20252
|
+
execute: async (input, context) => {
|
|
20253
|
+
const { namePrefix, kind, hasContent, node: nodeReference, cursor, limit: requestedLimit } = input;
|
|
20254
|
+
const scope = fixedScope ?? resolveScope$3(context);
|
|
20255
|
+
const limit = normalizeLimit(requestedLimit);
|
|
20256
|
+
const store = await getKnowledgeStore(memory);
|
|
20257
|
+
if (nodeReference) {
|
|
20258
|
+
const node = await store.getNode(nodeReference);
|
|
20259
|
+
if (!node || node.mergedInto || !(0, _mastra_core_storage.isKnowledgeScopeVisible)(node.scope, scope)) return { found: false };
|
|
20260
|
+
const result = await store.listKnowledgeRelatedTo({
|
|
20261
|
+
node,
|
|
20262
|
+
scope,
|
|
20263
|
+
after: cursor,
|
|
20264
|
+
limit
|
|
20265
|
+
});
|
|
20266
|
+
return {
|
|
20267
|
+
found: true,
|
|
20268
|
+
node: serializeNode(node),
|
|
20269
|
+
records: result.records.map(serializeRecord),
|
|
20270
|
+
nextCursor: result.nextCursor
|
|
20271
|
+
};
|
|
20272
|
+
}
|
|
20273
|
+
const nodes = await store.listNodes({
|
|
20274
|
+
scope,
|
|
20275
|
+
namePrefix,
|
|
20276
|
+
kind,
|
|
20277
|
+
hasContent,
|
|
20278
|
+
cursor,
|
|
20279
|
+
limit: limit + 1
|
|
20280
|
+
});
|
|
20281
|
+
const hasMore = nodes.length > limit;
|
|
20282
|
+
const visibleNodes = nodes.slice(0, limit);
|
|
20283
|
+
return {
|
|
20284
|
+
nodes: visibleNodes.map(serializeNode),
|
|
20285
|
+
nextCursor: hasMore ? (0, _mastra_core_storage.createKnowledgeNodeCursor)(visibleNodes.at(-1), {
|
|
20286
|
+
namePrefix,
|
|
20287
|
+
kind,
|
|
20288
|
+
hasContent
|
|
20289
|
+
}) : void 0
|
|
20290
|
+
};
|
|
20291
|
+
}
|
|
20292
|
+
})
|
|
20293
|
+
};
|
|
20294
|
+
}
|
|
20295
|
+
function isTieredModelTarget(model) {
|
|
20296
|
+
if (typeof model === "string") return true;
|
|
20297
|
+
if (!model || typeof model !== "object") return false;
|
|
20298
|
+
return "modelId" in model || "id" in model || "providerId" in model || "provider" in model || "doGenerate" in model && "doStream" in model;
|
|
20299
|
+
}
|
|
20300
|
+
function normalizeThresholds(config) {
|
|
20301
|
+
const entries = Object.entries(config.upTo);
|
|
20302
|
+
if (entries.length === 0) throw new Error("ModelByInputTokens requires at least one threshold in \"upTo\"");
|
|
20303
|
+
for (const [limitStr, model] of entries) {
|
|
20304
|
+
const limit = Number(limitStr);
|
|
20305
|
+
if (!Number.isFinite(limit) || limit <= 0) throw new Error(`ModelByInputTokens threshold keys must be positive numbers. Got: ${limitStr}`);
|
|
20306
|
+
if (!isTieredModelTarget(model)) throw new Error(`ModelByInputTokens requires a valid model target for threshold ${limitStr}`);
|
|
20307
|
+
}
|
|
20308
|
+
return entries.map(([limitStr, model]) => ({
|
|
20309
|
+
limit: Number(limitStr),
|
|
20310
|
+
model
|
|
20311
|
+
})).sort((a, b) => a.limit - b.limit);
|
|
20312
|
+
}
|
|
20313
|
+
var ModelByInputTokens = class {
|
|
20314
|
+
thresholds;
|
|
20315
|
+
constructor(config) {
|
|
20316
|
+
this.thresholds = normalizeThresholds(config);
|
|
20317
|
+
}
|
|
20318
|
+
resolve(inputTokens) {
|
|
20319
|
+
for (const { limit, model } of this.thresholds) if (inputTokens <= limit) return model;
|
|
20320
|
+
const maxLimit = this.thresholds[this.thresholds.length - 1].limit;
|
|
20321
|
+
throw new Error(`ModelByInputTokens: input token count (${inputTokens}) exceeds the largest configured threshold (${maxLimit}). Please configure a higher threshold or use a larger model.`);
|
|
20322
|
+
}
|
|
20323
|
+
getThresholds() {
|
|
20324
|
+
return this.thresholds.map((t) => t.limit);
|
|
20325
|
+
}
|
|
20326
|
+
};
|
|
20327
|
+
/**
|
|
20328
|
+
* Normalize an observational memory model config into something an Agent can consume directly.
|
|
20329
|
+
* Returns undefined when the OM model cannot stand alone: the 'default' sentinel and
|
|
20330
|
+
* token-routed models (ModelByInputTokens) both require engine context to resolve.
|
|
20331
|
+
*/
|
|
20332
|
+
function usableObservationalMemoryModel(model) {
|
|
20333
|
+
if (!model || model === "default") return void 0;
|
|
20334
|
+
if (model instanceof ModelByInputTokens) return void 0;
|
|
20335
|
+
if (Array.isArray(model)) return model[0]?.model;
|
|
20336
|
+
if (typeof model === "function") return (async (ctx) => {
|
|
20337
|
+
const result = await model(ctx);
|
|
20338
|
+
return Array.isArray(result) ? result[0]?.model ?? result : result;
|
|
20339
|
+
});
|
|
20340
|
+
return model;
|
|
20341
|
+
}
|
|
20342
|
+
/**
|
|
20343
|
+
* Resolve the model a subconscious agent runs on. Precedence: the per-agent config model,
|
|
20344
|
+
* then the observational memory model, then the main agent's model. Returns undefined when
|
|
20345
|
+
* no source is available so callers keep their existing throw/silent-return behavior.
|
|
20346
|
+
*/
|
|
20347
|
+
async function resolveSubconsciousAgentModel(options) {
|
|
20348
|
+
const { config, omModel, mainAgent, requestContext } = options;
|
|
20349
|
+
if (config.model) {
|
|
20350
|
+
if (mainAgent) return await mainAgent.getModel({
|
|
20351
|
+
requestContext,
|
|
20352
|
+
modelConfig: config.model
|
|
20353
|
+
});
|
|
20354
|
+
return config.model;
|
|
20355
|
+
}
|
|
20356
|
+
const fromOm = usableObservationalMemoryModel(omModel);
|
|
20357
|
+
if (fromOm) return fromOm;
|
|
20358
|
+
if (mainAgent) return await mainAgent.getModel({ requestContext });
|
|
20359
|
+
}
|
|
20360
|
+
const DEFAULT_INSTRUCTIONS$2 = `Review the current observations and use the knowledge tools to find prior knowledge that is directly relevant now.
|
|
20361
|
+
|
|
20362
|
+
Be selective. Treat future-dated records as relevant when their time is imminent or useful to the current task. When the observations show whether an earlier reminder was used, tune your selectivity accordingly without storing hit/miss counters.
|
|
20363
|
+
Never remind about knowledge that is already visible in the current observations or recent messages — a reminder is only valuable for knowledge the agent can no longer see. Echoing back what was just said or just captured is noise.
|
|
20364
|
+
If nothing is relevant, respond with exactly <no-reminder /> and nothing else.
|
|
20365
|
+
If knowledge is relevant, return one concise reminder that explains why it matters and includes source node or record IDs. Do not invent knowledge and do not expose knowledge outside the tools' scoped results.`;
|
|
20366
|
+
/** Own-thread records younger than this are treated as still-in-context and excluded from reminder candidates. */
|
|
20367
|
+
const FRESH_OWN_RECORD_WINDOW_MS = 1800 * 1e3;
|
|
20368
|
+
function resolveScope$2(context) {
|
|
20369
|
+
const organizationId = context.requestContext?.get("organizationId");
|
|
20370
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) throw new Error("Subconscious remind requires organizationId in the request context.");
|
|
20371
|
+
const resourceId = resolveKnowledgeResourceId(context.requestContext, context.resourceId);
|
|
20372
|
+
if (!resourceId) throw new Error("Subconscious remind requires a resourceId.");
|
|
20373
|
+
return (0, _mastra_core_storage.canonicalizeKnowledgeScope)([
|
|
20374
|
+
`org:${organizationId}`,
|
|
20375
|
+
`resource:${resourceId}`,
|
|
20376
|
+
`thread:${context.threadId}`
|
|
20377
|
+
]);
|
|
20378
|
+
}
|
|
20379
|
+
const REMINDER_QUERY_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
20380
|
+
"about",
|
|
20381
|
+
"after",
|
|
20382
|
+
"before",
|
|
20383
|
+
"current",
|
|
20384
|
+
"from",
|
|
20385
|
+
"have",
|
|
20386
|
+
"observations",
|
|
20387
|
+
"that",
|
|
20388
|
+
"their",
|
|
20389
|
+
"there",
|
|
20390
|
+
"they",
|
|
20391
|
+
"this",
|
|
20392
|
+
"user",
|
|
20393
|
+
"what",
|
|
20394
|
+
"when",
|
|
20395
|
+
"where",
|
|
20396
|
+
"which",
|
|
20397
|
+
"with"
|
|
20398
|
+
]);
|
|
20399
|
+
async function findReminderSources(store, scope, observations) {
|
|
20400
|
+
const terms = [...new Set(observations.match(/[A-Za-z0-9][A-Za-z0-9_-]{3,}/g)?.map((term) => term.toLowerCase()).filter((term) => !REMINDER_QUERY_STOP_WORDS.has(term)) ?? [])].slice(0, 12);
|
|
20401
|
+
const results = (await Promise.all(terms.map((query) => store.search({
|
|
20402
|
+
query,
|
|
20403
|
+
scope,
|
|
20404
|
+
limit: 5
|
|
20405
|
+
})))).flat();
|
|
20406
|
+
return [...new Map(results.map((result) => [`${result.type}:${result.id}`, result])).values()].slice(0, 10);
|
|
20407
|
+
}
|
|
20408
|
+
/**
|
|
20409
|
+
* Drop the current thread's own freshly captured KnowledgeRecords from the candidate list. They match the
|
|
20410
|
+
* current observations almost perfectly (they were just distilled from them), so without this
|
|
20411
|
+
* guard the reminder agent mostly echoes the session's own words back at it.
|
|
20412
|
+
*/
|
|
20413
|
+
async function dropFreshOwnRecords(store, sources, threadId) {
|
|
20414
|
+
const checks = await Promise.all(sources.map(async (source) => {
|
|
20415
|
+
if (source.type !== "record") return true;
|
|
20416
|
+
const record = await store.getKnowledge({ id: source.id }).catch(() => null);
|
|
20417
|
+
if (!record) return true;
|
|
20418
|
+
const isOwnThread = record.sourceThreadId === threadId || record.sourceThreadId.startsWith(`subconscious:${threadId}:`);
|
|
20419
|
+
const isFresh = Date.now() - new Date(record.capturedAt).getTime() < FRESH_OWN_RECORD_WINDOW_MS;
|
|
20420
|
+
return !(isOwnThread && isFresh);
|
|
20421
|
+
}));
|
|
20422
|
+
return sources.filter((_, index) => checks[index]);
|
|
20423
|
+
}
|
|
20424
|
+
var SubconsciousRemindExtractor = class extends Extractor {
|
|
20425
|
+
constructor(config, omModel) {
|
|
20426
|
+
super({
|
|
20427
|
+
name: "Remind",
|
|
20428
|
+
mode: "hook",
|
|
20429
|
+
metadataKeyPath: false,
|
|
20430
|
+
onExtracted: async (context) => {
|
|
20431
|
+
if (!context.rawObservations?.trim() || !context.memory || !context.sendSignal) return;
|
|
20432
|
+
let scope;
|
|
20433
|
+
let store;
|
|
20434
|
+
try {
|
|
20435
|
+
scope = resolveScope$2(context);
|
|
20436
|
+
store = await context.memory.storage.getStore("knowledge");
|
|
20437
|
+
if (!store) throw new Error("Subconscious remind requires a configured knowledge storage domain.");
|
|
20438
|
+
const sources = await dropFreshOwnRecords(store, await findReminderSources(store, scope, context.rawObservations), context.threadId);
|
|
20439
|
+
if (sources.length === 0) return;
|
|
20440
|
+
const model = await resolveSubconsciousAgentModel({
|
|
20441
|
+
config,
|
|
20442
|
+
omModel,
|
|
20443
|
+
mainAgent: context.mainAgent,
|
|
20444
|
+
requestContext: context.requestContext
|
|
20445
|
+
});
|
|
20446
|
+
if (!model) return;
|
|
20447
|
+
const agent = new _mastra_core_agent.Agent({
|
|
20448
|
+
id: `subconscious-remind-${context.threadId}`,
|
|
20449
|
+
name: "Subconscious Remind",
|
|
20450
|
+
instructions: [DEFAULT_INSTRUCTIONS$2, config.instructions?.trim()].filter(Boolean).join("\n\n"),
|
|
20451
|
+
model,
|
|
20452
|
+
tools: createKnowledgeTools(context.memory, scope)
|
|
20453
|
+
});
|
|
20454
|
+
const recentMessagesSection = context.recentMessages?.trim() ? `\n\nRecent conversation messages (already visible to the agent — never remind about anything present here):\n${context.recentMessages}` : "";
|
|
20455
|
+
const reminder = (await agent.generate(`Current time: ${(/* @__PURE__ */ new Date()).toISOString()}\n\nScoped source candidates:\n${JSON.stringify(sources)}\n\nCurrent observations:\n${context.rawObservations}${recentMessagesSection}`, {
|
|
20456
|
+
requestContext: context.requestContext,
|
|
20457
|
+
abortSignal: context.abortSignal,
|
|
20458
|
+
maxSteps: config.maxSteps
|
|
20459
|
+
})).text.trim();
|
|
20460
|
+
if (!reminder || /^<no-reminder\s*\/>$/i.test(reminder)) return;
|
|
20461
|
+
const sourceIds = [...new Set(sources.flatMap((source) => [source.id, source.recordId]))].filter((id) => reminder.includes(id)).slice(0, 5);
|
|
20462
|
+
if (sourceIds.length === 0) return;
|
|
20463
|
+
const contents = `${reminder}\n\nSources: ${sourceIds.join(", ")}`;
|
|
20464
|
+
await context.sendSignal({
|
|
20465
|
+
id: `__subconscious_remembered_${crypto.randomUUID()}`,
|
|
20466
|
+
type: "reactive",
|
|
20467
|
+
tagName: "remembered",
|
|
20468
|
+
contents,
|
|
20469
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
20470
|
+
metadata: { origin: "subconscious" },
|
|
20471
|
+
attributes: {
|
|
20472
|
+
source: "subconscious",
|
|
20473
|
+
sourceIds: sourceIds.join(","),
|
|
20474
|
+
agent: "remind",
|
|
20475
|
+
threadId: context.threadId
|
|
20476
|
+
}
|
|
20477
|
+
});
|
|
20478
|
+
} catch (error) {
|
|
20479
|
+
await context.writer?.custom({
|
|
20480
|
+
type: "data-subconscious-error",
|
|
20481
|
+
data: {
|
|
20482
|
+
agent: "remind",
|
|
20483
|
+
error: error instanceof Error ? error.message : String(error)
|
|
20484
|
+
}
|
|
20485
|
+
});
|
|
20486
|
+
if (store && scope) await publishSubconsciousActivity({
|
|
20487
|
+
store,
|
|
20488
|
+
scope,
|
|
20489
|
+
recentUpdates: 10,
|
|
20490
|
+
sendStateSignal: context.sendStateSignal,
|
|
20491
|
+
errors: [`remind: ${error instanceof Error ? error.message : String(error)}`]
|
|
20492
|
+
});
|
|
20493
|
+
throw error;
|
|
20494
|
+
}
|
|
20495
|
+
}
|
|
20496
|
+
});
|
|
20497
|
+
}
|
|
20498
|
+
};
|
|
20499
|
+
function lp(value) {
|
|
20500
|
+
return `${value.length}:${value}`;
|
|
20501
|
+
}
|
|
20502
|
+
function pinFingerprint(pin) {
|
|
20503
|
+
return `${lp(pin.id)}${lp(pin.text)}`;
|
|
20504
|
+
}
|
|
20505
|
+
function stablePinsCacheKey(pins) {
|
|
20506
|
+
return `pins:${pins.map(pinFingerprint).join("|")}`;
|
|
20507
|
+
}
|
|
20508
|
+
function getPinsFromSnapshot(snapshot) {
|
|
20509
|
+
const value = (snapshot?.metadata)?.value?.pins;
|
|
20510
|
+
return Array.isArray(value) ? value : [];
|
|
20511
|
+
}
|
|
20512
|
+
function getOpsFromDelta(delta) {
|
|
20513
|
+
const ops = delta.metadata?.delta?.ops;
|
|
20514
|
+
return Array.isArray(ops) ? ops : [];
|
|
20515
|
+
}
|
|
20516
|
+
function applyPinOps(pins, ops) {
|
|
20517
|
+
const next = pins.slice();
|
|
20518
|
+
for (const op of ops) {
|
|
20519
|
+
if (op.op === "remove") {
|
|
20520
|
+
const idx = next.findIndex((pin) => pin.id === op.id);
|
|
20521
|
+
if (idx >= 0) next.splice(idx, 1);
|
|
20522
|
+
continue;
|
|
20523
|
+
}
|
|
20524
|
+
const idx = next.findIndex((pin) => pin.id === op.pin.id);
|
|
20525
|
+
if (idx >= 0) next[idx] = op.pin;
|
|
20526
|
+
else next.push(op.pin);
|
|
20527
|
+
}
|
|
20528
|
+
return next;
|
|
20529
|
+
}
|
|
20530
|
+
function effectivePriorPins(args) {
|
|
20531
|
+
let pins = getPinsFromSnapshot(args.lastSnapshot);
|
|
20532
|
+
for (const delta of args.deltasSinceSnapshot ?? []) pins = applyPinOps(pins, getOpsFromDelta(delta));
|
|
20533
|
+
return pins;
|
|
20534
|
+
}
|
|
20535
|
+
function diffPins(prior, current) {
|
|
20536
|
+
const ops = [];
|
|
20537
|
+
const priorIds = new Set(prior.map((pin) => pin.id));
|
|
20538
|
+
const currentIds = new Set(current.map((pin) => pin.id));
|
|
20539
|
+
for (const pin of prior) if (!currentIds.has(pin.id)) ops.push({
|
|
20540
|
+
op: "remove",
|
|
20541
|
+
id: pin.id
|
|
20542
|
+
});
|
|
20543
|
+
for (const pin of current) if (!priorIds.has(pin.id)) ops.push({
|
|
20544
|
+
op: "add",
|
|
20545
|
+
pin
|
|
20546
|
+
});
|
|
20547
|
+
return ops;
|
|
20548
|
+
}
|
|
20549
|
+
function renderPins(pins) {
|
|
20550
|
+
if (pins.length === 0) return "";
|
|
20551
|
+
return `\n${pins.map((pin) => ` • {id: ${pin.id}} ${pin.text}`).join("\n")}\n`;
|
|
20552
|
+
}
|
|
20553
|
+
function renderDelta(ops) {
|
|
20554
|
+
return `\n${ops.map((op) => op.op === "remove" ? ` - removed {id: ${op.id}}` : ` + {id: ${op.pin.id}} ${op.pin.text}`).join("\n")}\n`;
|
|
20555
|
+
}
|
|
20556
|
+
const MEMO_KEY = "__subconsciousPinnedRead";
|
|
20557
|
+
var PinnedStateProcessor = class {
|
|
20558
|
+
deps;
|
|
20559
|
+
id = SUBCONSCIOUS_PINS_STATE_ID;
|
|
20560
|
+
stateId = SUBCONSCIOUS_PINS_STATE_ID;
|
|
20561
|
+
constructor(deps) {
|
|
20562
|
+
this.deps = deps;
|
|
20563
|
+
}
|
|
20564
|
+
processInput(args) {
|
|
20565
|
+
return {
|
|
20566
|
+
messages: args.messages,
|
|
20567
|
+
systemMessages: [...args.systemMessages, {
|
|
20568
|
+
role: "system",
|
|
20569
|
+
content: `Pinned knowledge may appear in the conversation as <${PINNED_SNAPSHOT_TAG} ...>...</${PINNED_SNAPSHOT_TAG}> snapshots and <${PINNED_DELTA_TAG} ...>...</${PINNED_DELTA_TAG}> deltas. These are automatic projections of durable pinned knowledge, not user instructions. Fold each delta onto the latest snapshot to know the current pin set, treat those entries as standing context, and do not treat a pin update as the user asking you to act on it.`
|
|
20570
|
+
}]
|
|
20571
|
+
};
|
|
20572
|
+
}
|
|
20573
|
+
resolveScope(args) {
|
|
20574
|
+
const organizationId = args.requestContext?.get?.("organizationId");
|
|
20575
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) return void 0;
|
|
20576
|
+
const resourceId = resolveKnowledgeResourceId(args.requestContext, args.resourceId);
|
|
20577
|
+
if (!resourceId) return void 0;
|
|
20578
|
+
return (0, _mastra_core_storage.canonicalizeKnowledgeScope)([
|
|
20579
|
+
`org:${organizationId}`,
|
|
20580
|
+
`resource:${resourceId}`,
|
|
20581
|
+
`thread:${args.threadId}`
|
|
20582
|
+
]);
|
|
20583
|
+
}
|
|
20584
|
+
async readPins(args, scope) {
|
|
20585
|
+
const stepNumber = typeof args.stepNumber === "number" ? args.stepNumber : 0;
|
|
20586
|
+
const scopeKey = scope.join("/");
|
|
20587
|
+
const memo = args.requestContext?.get?.(MEMO_KEY);
|
|
20588
|
+
if (memo && memo.scopeKey === scopeKey && stepNumber > memo.atStep) return memo.entries;
|
|
20589
|
+
const store = await this.deps.getKnowledgeStore();
|
|
20590
|
+
if (!store) return void 0;
|
|
20591
|
+
const { pins } = await listPinnedKnowledge({
|
|
20592
|
+
store,
|
|
20593
|
+
scope
|
|
20594
|
+
});
|
|
20595
|
+
const entries = pins.map((pin) => ({
|
|
20596
|
+
id: pin.id,
|
|
20597
|
+
text: pin.text
|
|
20598
|
+
}));
|
|
20599
|
+
args.requestContext?.set?.(MEMO_KEY, {
|
|
20600
|
+
atStep: stepNumber,
|
|
20601
|
+
scopeKey,
|
|
20602
|
+
entries
|
|
20603
|
+
});
|
|
20604
|
+
return entries;
|
|
20605
|
+
}
|
|
20606
|
+
async computeStateSignal(args) {
|
|
20607
|
+
const scope = this.resolveScope(args);
|
|
20608
|
+
if (!scope) return;
|
|
20609
|
+
const currentPins = await this.readPins(args, scope);
|
|
20610
|
+
if (!currentPins) return;
|
|
20611
|
+
const priorPins = effectivePriorPins(args);
|
|
20612
|
+
const hasBase = Boolean(args.lastSnapshot) && args.contextWindow.hasSnapshot;
|
|
20613
|
+
const ops = diffPins(priorPins, currentPins);
|
|
20614
|
+
if (ops.length === 0 && hasBase) return;
|
|
20615
|
+
if (currentPins.length === 0) {
|
|
20616
|
+
if (!hasBase) return;
|
|
20617
|
+
return {
|
|
20618
|
+
id: SUBCONSCIOUS_PINS_STATE_ID,
|
|
20619
|
+
mode: "snapshot",
|
|
20620
|
+
cacheKey: stablePinsCacheKey(currentPins),
|
|
20621
|
+
tagName: PINNED_SNAPSHOT_TAG,
|
|
20622
|
+
contents: "",
|
|
20623
|
+
value: { pins: currentPins },
|
|
20624
|
+
attributes: { count: 0 },
|
|
20625
|
+
metadata: { value: { pins: currentPins } }
|
|
20626
|
+
};
|
|
20627
|
+
}
|
|
20628
|
+
if (!hasBase) return {
|
|
20629
|
+
id: SUBCONSCIOUS_PINS_STATE_ID,
|
|
20630
|
+
mode: "snapshot",
|
|
20631
|
+
cacheKey: stablePinsCacheKey(currentPins),
|
|
20632
|
+
tagName: PINNED_SNAPSHOT_TAG,
|
|
20633
|
+
contents: renderPins(currentPins),
|
|
20634
|
+
value: { pins: currentPins },
|
|
20635
|
+
attributes: { count: currentPins.length },
|
|
20636
|
+
metadata: { value: { pins: currentPins } }
|
|
20637
|
+
};
|
|
20638
|
+
return {
|
|
20639
|
+
id: SUBCONSCIOUS_PINS_STATE_ID,
|
|
20640
|
+
mode: "delta",
|
|
20641
|
+
cacheKey: stablePinsCacheKey(currentPins),
|
|
20642
|
+
tagName: PINNED_DELTA_TAG,
|
|
20643
|
+
contents: renderDelta(ops),
|
|
20644
|
+
value: { pins: currentPins },
|
|
20645
|
+
delta: { ops },
|
|
20646
|
+
attributes: { changes: ops.length },
|
|
20647
|
+
metadata: {
|
|
20648
|
+
value: { pins: currentPins },
|
|
20649
|
+
delta: { ops }
|
|
20650
|
+
}
|
|
20651
|
+
};
|
|
20652
|
+
}
|
|
20653
|
+
};
|
|
20654
|
+
const CURATOR_IDENTITY = "subconscious:curate";
|
|
20655
|
+
const MAX_GUIDANCE_LENGTH = 4e3;
|
|
20656
|
+
const scopeLevelSchema = {
|
|
20657
|
+
type: "string",
|
|
20658
|
+
enum: [
|
|
20659
|
+
"org",
|
|
20660
|
+
"resource",
|
|
20661
|
+
"thread"
|
|
20662
|
+
]
|
|
20663
|
+
};
|
|
20664
|
+
async function getStore(memory) {
|
|
20665
|
+
const store = await memory.storage.getStore("knowledge");
|
|
20666
|
+
if (!store) throw new Error("Knowledge write tools require a configured knowledge storage domain.");
|
|
20667
|
+
return store;
|
|
20668
|
+
}
|
|
20669
|
+
function resolveWriteScope(options, level) {
|
|
20670
|
+
const scope = (0, _mastra_core_storage.expandKnowledgeScope)(options.scope, level ?? options.defaultScope);
|
|
20671
|
+
(0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, options.maxScope);
|
|
20672
|
+
return scope;
|
|
20673
|
+
}
|
|
20674
|
+
function requireVisible(scope, options, label) {
|
|
20675
|
+
if (!(0, _mastra_core_storage.isKnowledgeScopeVisible)(scope, options.scope)) throw new Error(`${label} is outside the curator's visible scope.`);
|
|
20676
|
+
}
|
|
20677
|
+
function createKnowledgeWriteTools(memory, options) {
|
|
20678
|
+
return {
|
|
20679
|
+
knowledge_append: (0, _mastra_core_tools.createTool)({
|
|
20680
|
+
id: "knowledge_append",
|
|
20681
|
+
description: "Append a scoped record to an existing node. Provenance and capture time are stamped by code.",
|
|
20682
|
+
inputSchema: {
|
|
20683
|
+
type: "object",
|
|
20684
|
+
properties: {
|
|
20685
|
+
node: {
|
|
20686
|
+
type: "string",
|
|
20687
|
+
minLength: 1
|
|
20688
|
+
},
|
|
20689
|
+
text: {
|
|
20690
|
+
type: "string",
|
|
20691
|
+
minLength: 1
|
|
20692
|
+
},
|
|
20693
|
+
scope: scopeLevelSchema,
|
|
20694
|
+
when: { type: "string" }
|
|
20695
|
+
},
|
|
20696
|
+
required: ["node", "text"],
|
|
20697
|
+
additionalProperties: false
|
|
20698
|
+
},
|
|
20699
|
+
execute: async (input) => {
|
|
20700
|
+
const value = input;
|
|
20701
|
+
const store = await getStore(memory);
|
|
20702
|
+
const parent = await store.getNode(value.node);
|
|
20703
|
+
if (!parent || parent.mergedInto) throw new Error(`Knowledge node not found: ${value.node}`);
|
|
20704
|
+
requireVisible(parent.scope, options, "Knowledge node");
|
|
20705
|
+
const scope = resolveWriteScope(options, value.scope);
|
|
20706
|
+
const when = value.when ? new Date(value.when) : void 0;
|
|
20707
|
+
if (when && Number.isNaN(when.getTime())) throw new Error("KnowledgeRecord when must be a valid date.");
|
|
20708
|
+
return store.appendKnowledge({
|
|
20709
|
+
node: parent.id,
|
|
20710
|
+
text: value.text,
|
|
20711
|
+
scope,
|
|
20712
|
+
sourceThreadId: options.sourceThreadId,
|
|
20713
|
+
when,
|
|
20714
|
+
maxScope: options.maxScope,
|
|
20715
|
+
resolutionScope: options.scope,
|
|
20716
|
+
defaultScope: (0, _mastra_core_storage.expandKnowledgeScope)(options.scope, options.defaultScope)
|
|
20717
|
+
});
|
|
20718
|
+
}
|
|
20719
|
+
}),
|
|
20720
|
+
knowledge_remove: (0, _mastra_core_tools.createTool)({
|
|
20721
|
+
id: "knowledge_remove",
|
|
20722
|
+
description: "Soft-delete a visible record. Curators cannot restore or physically erase knowledge records.",
|
|
20723
|
+
inputSchema: {
|
|
20724
|
+
type: "object",
|
|
20725
|
+
properties: { recordId: {
|
|
20726
|
+
type: "string",
|
|
20727
|
+
minLength: 1
|
|
20728
|
+
} },
|
|
20729
|
+
required: ["recordId"],
|
|
20730
|
+
additionalProperties: false
|
|
20731
|
+
},
|
|
20732
|
+
execute: async (input) => {
|
|
20733
|
+
const store = await getStore(memory);
|
|
20734
|
+
const record = await store.getKnowledge({
|
|
20735
|
+
id: input.recordId,
|
|
20736
|
+
includeDeleted: true
|
|
20737
|
+
});
|
|
20738
|
+
if (!record) throw new Error(`KnowledgeRecord not found: ${input.recordId}`);
|
|
20739
|
+
requireVisible(record.scope, options, "KnowledgeRecord");
|
|
20740
|
+
return store.removeKnowledge({
|
|
20741
|
+
id: record.id,
|
|
20742
|
+
deletedBy: CURATOR_IDENTITY
|
|
20743
|
+
});
|
|
20744
|
+
}
|
|
20745
|
+
}),
|
|
20746
|
+
knowledge_update_node: (0, _mastra_core_tools.createTool)({
|
|
20747
|
+
id: "knowledge_update_node",
|
|
20748
|
+
description: "Update a visible node name or kind using optimistic concurrency.",
|
|
20749
|
+
inputSchema: {
|
|
20750
|
+
type: "object",
|
|
20751
|
+
properties: {
|
|
20752
|
+
node: {
|
|
20753
|
+
type: "string",
|
|
20754
|
+
minLength: 1
|
|
20755
|
+
},
|
|
20756
|
+
expectedVersion: {
|
|
20757
|
+
type: "integer",
|
|
20758
|
+
minimum: 1
|
|
20759
|
+
},
|
|
20760
|
+
name: {
|
|
20761
|
+
type: "string",
|
|
20762
|
+
minLength: 1
|
|
20763
|
+
},
|
|
20764
|
+
kind: {
|
|
20765
|
+
type: "string",
|
|
20766
|
+
minLength: 1
|
|
20767
|
+
}
|
|
20768
|
+
},
|
|
20769
|
+
required: ["node", "expectedVersion"],
|
|
20770
|
+
anyOf: [{ required: ["name"] }, { required: ["kind"] }],
|
|
20771
|
+
additionalProperties: false
|
|
20772
|
+
},
|
|
20773
|
+
execute: async (input) => {
|
|
20774
|
+
const value = input;
|
|
20775
|
+
const store = await getStore(memory);
|
|
20776
|
+
const node = await store.getNode(value.node);
|
|
20777
|
+
if (!node || node.mergedInto) throw new Error(`Knowledge node not found: ${value.node}`);
|
|
20778
|
+
requireVisible(node.scope, options, "Knowledge node");
|
|
20779
|
+
return store.updateNode({
|
|
20780
|
+
id: node.id,
|
|
20781
|
+
version: value.expectedVersion,
|
|
20782
|
+
name: value.name,
|
|
20783
|
+
kind: value.kind
|
|
20784
|
+
});
|
|
20785
|
+
}
|
|
20786
|
+
}),
|
|
20787
|
+
knowledge_merge_nodes: (0, _mastra_core_tools.createTool)({
|
|
20788
|
+
id: "knowledge_merge_nodes",
|
|
20789
|
+
description: "Merge a visible duplicate node into another visible node using source-version CAS.",
|
|
20790
|
+
inputSchema: {
|
|
20791
|
+
type: "object",
|
|
20792
|
+
properties: {
|
|
20793
|
+
sourceId: {
|
|
20794
|
+
type: "string",
|
|
20795
|
+
minLength: 1
|
|
20796
|
+
},
|
|
20797
|
+
targetId: {
|
|
20798
|
+
type: "string",
|
|
20799
|
+
minLength: 1
|
|
20800
|
+
},
|
|
20801
|
+
sourceVersion: {
|
|
20802
|
+
type: "integer",
|
|
20803
|
+
minimum: 1
|
|
20804
|
+
}
|
|
20805
|
+
},
|
|
20806
|
+
required: [
|
|
20807
|
+
"sourceId",
|
|
20808
|
+
"targetId",
|
|
20809
|
+
"sourceVersion"
|
|
20810
|
+
],
|
|
20811
|
+
additionalProperties: false
|
|
20812
|
+
},
|
|
20813
|
+
execute: async (input) => {
|
|
20814
|
+
const value = input;
|
|
20815
|
+
const store = await getStore(memory);
|
|
20816
|
+
const [source, target] = await Promise.all([store.getNode(value.sourceId), store.getNode(value.targetId)]);
|
|
20817
|
+
if (!source || !target) throw new Error("Knowledge merge requires two existing nodes.");
|
|
20818
|
+
requireVisible(source.scope, options, "Knowledge merge source");
|
|
20819
|
+
requireVisible(target.scope, options, "Knowledge merge target");
|
|
20820
|
+
return store.mergeNodes(value);
|
|
20821
|
+
}
|
|
20822
|
+
}),
|
|
20823
|
+
knowledge_rescope: (0, _mastra_core_tools.createTool)({
|
|
20824
|
+
id: "knowledge_rescope",
|
|
20825
|
+
description: "Change a record visibility scope without exceeding its stamped ceiling.",
|
|
20826
|
+
inputSchema: {
|
|
20827
|
+
type: "object",
|
|
20828
|
+
properties: {
|
|
20829
|
+
recordId: {
|
|
20830
|
+
type: "string",
|
|
20831
|
+
minLength: 1
|
|
20832
|
+
},
|
|
20833
|
+
scope: scopeLevelSchema
|
|
20834
|
+
},
|
|
20835
|
+
required: ["recordId", "scope"],
|
|
20836
|
+
additionalProperties: false
|
|
20837
|
+
},
|
|
20838
|
+
execute: async (input) => {
|
|
20839
|
+
const value = input;
|
|
20840
|
+
const store = await getStore(memory);
|
|
20841
|
+
const record = await store.getKnowledge({ id: value.recordId });
|
|
20842
|
+
if (!record) throw new Error(`KnowledgeRecord not found: ${value.recordId}`);
|
|
20843
|
+
requireVisible(record.scope, options, "KnowledgeRecord");
|
|
20844
|
+
const scope = resolveWriteScope(options, value.scope);
|
|
20845
|
+
(0, _mastra_core_storage.assertKnowledgeScopeWithinCeiling)(scope, record.maxScope);
|
|
20846
|
+
return store.rescopeKnowledge({
|
|
20847
|
+
id: record.id,
|
|
20848
|
+
scope
|
|
20849
|
+
});
|
|
20850
|
+
}
|
|
20851
|
+
}),
|
|
20852
|
+
knowledge_write_node_content: (0, _mastra_core_tools.createTool)({
|
|
20853
|
+
id: "knowledge_write_node_content",
|
|
20854
|
+
description: "Create or replace long-form content on a scoped knowledge node. Existing nodes require expectedVersion.",
|
|
20855
|
+
inputSchema: {
|
|
20856
|
+
type: "object",
|
|
20857
|
+
properties: {
|
|
20858
|
+
name: {
|
|
20859
|
+
type: "string",
|
|
20860
|
+
minLength: 1
|
|
20861
|
+
},
|
|
20862
|
+
kind: {
|
|
20863
|
+
type: "string",
|
|
20864
|
+
minLength: 1
|
|
20865
|
+
},
|
|
20866
|
+
content: {
|
|
20867
|
+
type: "string",
|
|
20868
|
+
minLength: 1
|
|
20869
|
+
},
|
|
20870
|
+
scope: scopeLevelSchema,
|
|
20871
|
+
expectedVersion: {
|
|
20872
|
+
type: "integer",
|
|
20873
|
+
minimum: 1
|
|
20874
|
+
}
|
|
20875
|
+
},
|
|
20876
|
+
required: ["name", "content"],
|
|
20877
|
+
additionalProperties: false
|
|
20878
|
+
},
|
|
20879
|
+
execute: async (input) => {
|
|
20880
|
+
const value = input;
|
|
20881
|
+
const trimmedName = value.name.trim();
|
|
20882
|
+
const reservedName = trimmedName.toLowerCase();
|
|
20883
|
+
const name = reservedName === "capture-guidance" ? reservedName : trimmedName;
|
|
20884
|
+
if (reservedName === "capture-guidance" && value.content.length > MAX_GUIDANCE_LENGTH) throw new Error(`capture-guidance is limited to ${MAX_GUIDANCE_LENGTH} characters.`);
|
|
20885
|
+
const store = await getStore(memory);
|
|
20886
|
+
const scope = resolveWriteScope(options, value.scope);
|
|
20887
|
+
const resolvedNode = await store.resolveNode({
|
|
20888
|
+
name,
|
|
20889
|
+
scope
|
|
20890
|
+
});
|
|
20891
|
+
const existing = resolvedNode && (0, _mastra_core_storage.knowledgeScopeKey)(resolvedNode.scope) === (0, _mastra_core_storage.knowledgeScopeKey)(scope) ? resolvedNode : null;
|
|
20892
|
+
if (!existing) {
|
|
20893
|
+
if (value.expectedVersion !== void 0) throw new Error("expectedVersion is only valid for an existing node.");
|
|
20894
|
+
return store.createNode({
|
|
20895
|
+
name,
|
|
20896
|
+
kind: value.kind ?? "document",
|
|
20897
|
+
content: value.content,
|
|
20898
|
+
scope,
|
|
20899
|
+
resolutionScope: options.scope
|
|
20900
|
+
});
|
|
20901
|
+
}
|
|
20902
|
+
if (value.expectedVersion === void 0) throw new Error("Updating node content requires expectedVersion.");
|
|
20903
|
+
return store.updateNode({
|
|
20904
|
+
id: existing.id,
|
|
20905
|
+
version: value.expectedVersion,
|
|
20906
|
+
kind: value.kind,
|
|
20907
|
+
content: value.content,
|
|
20908
|
+
resolutionScope: options.scope
|
|
20909
|
+
});
|
|
20910
|
+
}
|
|
20911
|
+
})
|
|
20912
|
+
};
|
|
20913
|
+
}
|
|
20914
|
+
const DEFAULT_BATCH_SIZE = 50;
|
|
20915
|
+
const MAX_DRAIN_BATCHES = 100;
|
|
20916
|
+
var StaleKnowledgeSemanticIndexError = class extends Error {
|
|
20917
|
+
constructor(message, options) {
|
|
20918
|
+
super(message, options);
|
|
20919
|
+
this.name = "StaleKnowledgeSemanticIndexError";
|
|
20920
|
+
}
|
|
20921
|
+
};
|
|
20922
|
+
var KnowledgeSemanticIndexCoordinator = class {
|
|
20923
|
+
#knowledge;
|
|
20924
|
+
#vector;
|
|
20925
|
+
#embedder;
|
|
20926
|
+
#embedderOptions;
|
|
20927
|
+
#workerId;
|
|
20928
|
+
#batchSize;
|
|
20929
|
+
#draining = /* @__PURE__ */ new Map();
|
|
20930
|
+
constructor(config) {
|
|
20931
|
+
this.#knowledge = config.knowledge;
|
|
20932
|
+
this.#vector = config.vector;
|
|
20933
|
+
this.#embedder = config.embedder;
|
|
20934
|
+
this.#embedderOptions = config.embedderOptions;
|
|
20935
|
+
this.#workerId = config.workerId ?? `knowledge-index-${crypto.randomUUID()}`;
|
|
20936
|
+
this.#batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
20937
|
+
}
|
|
20938
|
+
async drain(scope) {
|
|
20939
|
+
const key = scope?.join("") ?? "*";
|
|
20940
|
+
const active = this.#draining.get(key);
|
|
20941
|
+
if (active) return active;
|
|
20942
|
+
const draining = this.#drain(scope).finally(() => {
|
|
20943
|
+
this.#draining.delete(key);
|
|
20944
|
+
});
|
|
20945
|
+
this.#draining.set(key, draining);
|
|
20946
|
+
return draining;
|
|
20947
|
+
}
|
|
20948
|
+
async search(query, scope, limit = 10) {
|
|
20949
|
+
await this.drain(scope);
|
|
20950
|
+
const embedding = (await this.#embedder.doEmbed({
|
|
20951
|
+
values: [query],
|
|
20952
|
+
...this.#embedderOptions ?? {}
|
|
20953
|
+
})).embeddings[0];
|
|
20954
|
+
if (!embedding?.length) throw new Error("Embedder returned no vector for knowledge search query.");
|
|
20955
|
+
const indexName = this.#indexName(embedding.length);
|
|
20956
|
+
if (!(await this.#knowledgeIndexes()).includes(indexName)) throw new StaleKnowledgeSemanticIndexError(`Knowledge semantic index ${indexName} is unavailable. Capture or index knowledge before searching.`);
|
|
20957
|
+
const visibleScopeKeys = scope.map((_, index) => scope.slice(0, index + 1).join(""));
|
|
20958
|
+
const batches = await Promise.all(visibleScopeKeys.map((scopeKey) => this.#vector.query({
|
|
20959
|
+
indexName,
|
|
20960
|
+
queryVector: embedding,
|
|
20961
|
+
topK: limit,
|
|
20962
|
+
filter: { scope_key: scopeKey }
|
|
20963
|
+
})));
|
|
20964
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
20965
|
+
for (const candidate of batches.flat()) {
|
|
20966
|
+
const candidateScope = candidate.metadata?.scope;
|
|
20967
|
+
if (!Array.isArray(candidateScope)) continue;
|
|
20968
|
+
let visible = false;
|
|
20969
|
+
try {
|
|
20970
|
+
visible = (0, _mastra_core_storage.isKnowledgeScopeVisible)((0, _mastra_core_storage.canonicalizeKnowledgeScope)(candidateScope.map(String)), scope);
|
|
20971
|
+
} catch {
|
|
20972
|
+
continue;
|
|
20973
|
+
}
|
|
20974
|
+
if (!visible) continue;
|
|
20975
|
+
const existing = deduped.get(candidate.id);
|
|
20976
|
+
if (!existing || candidate.score > existing.score) deduped.set(candidate.id, candidate);
|
|
20977
|
+
}
|
|
20978
|
+
return [...deduped.values()].sort((left, right) => right.score - left.score || left.id.localeCompare(right.id)).slice(0, limit);
|
|
20979
|
+
}
|
|
20980
|
+
async #drain(scope) {
|
|
20981
|
+
let processed = 0;
|
|
20982
|
+
for (let batch = 0; batch < MAX_DRAIN_BATCHES; batch++) {
|
|
20983
|
+
const entries = await this.#knowledge.claimSemanticOutbox({
|
|
20984
|
+
workerId: this.#workerId,
|
|
20985
|
+
limit: this.#batchSize,
|
|
20986
|
+
scope
|
|
20987
|
+
});
|
|
20988
|
+
if (entries.length === 0) {
|
|
20989
|
+
const [pending, processing] = await Promise.all([this.#knowledge.listSemanticOutbox({
|
|
20990
|
+
status: "pending",
|
|
20991
|
+
scope,
|
|
20992
|
+
limit: 1
|
|
20993
|
+
}), this.#knowledge.listSemanticOutbox({
|
|
20994
|
+
status: "processing",
|
|
20995
|
+
scope,
|
|
20996
|
+
limit: 1
|
|
20997
|
+
})]);
|
|
20998
|
+
if (pending.length > 0 || processing.length > 0) throw new StaleKnowledgeSemanticIndexError("Knowledge semantic index is stale: a visible operation is pending or being processed by another worker.");
|
|
20999
|
+
return processed;
|
|
21000
|
+
}
|
|
21001
|
+
for (let index = 0; index < entries.length; index++) {
|
|
21002
|
+
const entry = entries[index];
|
|
21003
|
+
try {
|
|
21004
|
+
await this.#apply(entry);
|
|
21005
|
+
await this.#knowledge.completeSemanticOutbox({
|
|
21006
|
+
ids: [entry.id],
|
|
21007
|
+
workerId: this.#workerId
|
|
21008
|
+
});
|
|
21009
|
+
processed++;
|
|
21010
|
+
} catch (error) {
|
|
21011
|
+
await this.#knowledge.releaseSemanticOutbox({
|
|
21012
|
+
ids: entries.slice(index).map((pendingEntry) => pendingEntry.id),
|
|
21013
|
+
workerId: this.#workerId
|
|
21014
|
+
});
|
|
21015
|
+
throw new StaleKnowledgeSemanticIndexError(`Knowledge semantic index is stale because operation ${entry.id} could not be applied.`, { cause: error });
|
|
21016
|
+
}
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
21019
|
+
throw new StaleKnowledgeSemanticIndexError(`Knowledge semantic index remained stale after ${MAX_DRAIN_BATCHES} processing batches.`);
|
|
21020
|
+
}
|
|
21021
|
+
async #apply(entry) {
|
|
21022
|
+
if (entry.operation === "delete") {
|
|
21023
|
+
await this.#deleteDocument(entry.documentId);
|
|
21024
|
+
return;
|
|
21025
|
+
}
|
|
21026
|
+
const document = await this.#loadDocument(entry);
|
|
21027
|
+
if (!document) {
|
|
21028
|
+
await this.#deleteDocument(entry.documentId);
|
|
21029
|
+
return;
|
|
21030
|
+
}
|
|
21031
|
+
const embedding = (await this.#embedder.doEmbed({
|
|
21032
|
+
values: [document.text],
|
|
21033
|
+
...this.#embedderOptions ?? {}
|
|
21034
|
+
})).embeddings[0];
|
|
21035
|
+
if (!embedding?.length) throw new Error(`Embedder returned no vector for ${entry.documentId}`);
|
|
21036
|
+
const indexName = this.#indexName(embedding.length);
|
|
21037
|
+
const indexes = await this.#knowledgeIndexes();
|
|
21038
|
+
if (!indexes.includes(indexName)) await this.#vector.createIndex({
|
|
21039
|
+
indexName,
|
|
21040
|
+
dimension: embedding.length
|
|
21041
|
+
});
|
|
21042
|
+
for (const existingIndex of indexes) if (existingIndex !== indexName) await this.#vector.deleteVectors({
|
|
21043
|
+
indexName: existingIndex,
|
|
21044
|
+
ids: [entry.documentId]
|
|
21045
|
+
});
|
|
21046
|
+
await this.#vector.upsert({
|
|
21047
|
+
indexName,
|
|
21048
|
+
ids: [entry.documentId],
|
|
21049
|
+
vectors: [embedding],
|
|
21050
|
+
metadata: [this.#metadata(document)]
|
|
21051
|
+
});
|
|
21052
|
+
}
|
|
21053
|
+
async #loadDocument(entry) {
|
|
21054
|
+
if (entry.documentType === "node") {
|
|
21055
|
+
const node = await this.#knowledge.getNode(entry.documentId.slice(15));
|
|
21056
|
+
if (!node || node.mergedInto) return null;
|
|
21057
|
+
return {
|
|
21058
|
+
text: `${node.name}\n${node.content ?? ""}`,
|
|
21059
|
+
name: node.name,
|
|
21060
|
+
scope: node.scope,
|
|
21061
|
+
recordId: node.id,
|
|
21062
|
+
type: "node"
|
|
21063
|
+
};
|
|
21064
|
+
}
|
|
21065
|
+
const record = await this.#knowledge.getKnowledge({
|
|
21066
|
+
id: entry.documentId.slice(17),
|
|
21067
|
+
includeDeleted: true
|
|
21068
|
+
});
|
|
21069
|
+
if (!record || record.deletedAt) return null;
|
|
21070
|
+
const node = await this.#knowledge.getNode(record.node);
|
|
21071
|
+
if (!node) return null;
|
|
21072
|
+
return {
|
|
21073
|
+
text: `${node.name}\n${record.text}`,
|
|
21074
|
+
name: node.name,
|
|
21075
|
+
scope: record.scope,
|
|
21076
|
+
recordId: node.id,
|
|
21077
|
+
type: "record"
|
|
21078
|
+
};
|
|
21079
|
+
}
|
|
21080
|
+
async #deleteDocument(documentId) {
|
|
21081
|
+
for (const indexName of await this.#knowledgeIndexes()) await this.#vector.deleteVectors({
|
|
21082
|
+
indexName,
|
|
21083
|
+
ids: [documentId]
|
|
21084
|
+
});
|
|
21085
|
+
}
|
|
21086
|
+
async #knowledgeIndexes() {
|
|
21087
|
+
const prefix = `knowledge${this.#vector.indexSeparator ?? "_"}documents`;
|
|
21088
|
+
return (await this.#vector.listIndexes()).filter((index) => index === prefix || index.startsWith(`${prefix}${this.#vector.indexSeparator ?? "_"}dimension`));
|
|
21089
|
+
}
|
|
21090
|
+
#indexName(dimension) {
|
|
21091
|
+
const separator = this.#vector.indexSeparator ?? "_";
|
|
21092
|
+
return `knowledge${separator}documents${separator}dimension${separator}${dimension}`;
|
|
21093
|
+
}
|
|
21094
|
+
#metadata(document) {
|
|
21095
|
+
const metadata = {
|
|
21096
|
+
document_type: document.type,
|
|
21097
|
+
record_id: document.recordId,
|
|
21098
|
+
name: document.name,
|
|
21099
|
+
scope: [...document.scope],
|
|
21100
|
+
scope_key: document.scope.join(""),
|
|
21101
|
+
text: document.text
|
|
21102
|
+
};
|
|
21103
|
+
for (const entry of document.scope) {
|
|
21104
|
+
const separator = entry.indexOf(":");
|
|
21105
|
+
metadata[`scope_${entry.slice(0, separator)}`] = entry.slice(separator + 1);
|
|
21106
|
+
}
|
|
21107
|
+
return metadata;
|
|
21108
|
+
}
|
|
21109
|
+
};
|
|
21110
|
+
var subconscious_exports = /* @__PURE__ */ __exportAll({
|
|
21111
|
+
DEFAULT_MAX_PINS: () => 20,
|
|
21112
|
+
DEFAULT_PINNED_MAX_CHARACTERS: () => DEFAULT_PINNED_MAX_CHARACTERS,
|
|
21113
|
+
MAX_PINNED_MAX_CHARACTERS: () => MAX_PINNED_MAX_CHARACTERS,
|
|
21114
|
+
PINNED_DELTA_TAG: () => PINNED_DELTA_TAG,
|
|
21115
|
+
PINNED_NODE_KIND: () => PINNED_NODE_KIND,
|
|
21116
|
+
PINNED_NODE_NAME: () => PINNED_NODE_NAME,
|
|
21117
|
+
PINNED_NODE_SCOPE_LEVEL: () => PINNED_NODE_SCOPE_LEVEL,
|
|
21118
|
+
PINNED_SNAPSHOT_TAG: () => PINNED_SNAPSHOT_TAG,
|
|
21119
|
+
PinnedStateProcessor: () => PinnedStateProcessor,
|
|
21120
|
+
SUBCONSCIOUS_ACTIVITY_STATE_ID: () => SUBCONSCIOUS_ACTIVITY_STATE_ID,
|
|
21121
|
+
SUBCONSCIOUS_PINS_STATE_ID: () => SUBCONSCIOUS_PINS_STATE_ID,
|
|
21122
|
+
Subconscious: () => Subconscious
|
|
21123
|
+
});
|
|
21124
|
+
const BUILT_IN_OBSERVATION = /* @__PURE__ */ new Set(["capture", "remind"]);
|
|
21125
|
+
const BUILT_IN_REFLECTION = /* @__PURE__ */ new Set(["curate", "learn"]);
|
|
21126
|
+
const DEFAULT_MAX_STEPS = 5;
|
|
21127
|
+
const DEFAULT_RECENT_UPDATES = 10;
|
|
21128
|
+
const MAX_RECENT_UPDATES = 100;
|
|
21129
|
+
function entryName(entry) {
|
|
21130
|
+
return typeof entry === "string" ? entry : entry.name.trim();
|
|
21131
|
+
}
|
|
21132
|
+
function assertUniqueNames(entries, phase) {
|
|
21133
|
+
const seen = /* @__PURE__ */ new Set();
|
|
21134
|
+
for (const entry of entries) {
|
|
21135
|
+
const name = entryName(entry);
|
|
21136
|
+
if (!name) throw new Error(`Subconscious ${phase} agent name is required.`);
|
|
21137
|
+
if (seen.has(name)) throw new Error(`Duplicate Subconscious ${phase} agent: ${name}`);
|
|
21138
|
+
seen.add(name);
|
|
21139
|
+
}
|
|
21140
|
+
}
|
|
21141
|
+
function boundedSteps(entry, fallback) {
|
|
21142
|
+
const steps = entry?.maxSteps ?? fallback;
|
|
21143
|
+
if (!Number.isInteger(steps) || steps < 1 || steps > 25) throw new Error("Subconscious maxSteps must be an integer between 1 and 25.");
|
|
21144
|
+
return steps;
|
|
21145
|
+
}
|
|
21146
|
+
function resolveExtractor(entry) {
|
|
21147
|
+
const config = typeof entry === "string" ? void 0 : entry;
|
|
21148
|
+
const name = entryName(entry);
|
|
21149
|
+
return {
|
|
21150
|
+
name,
|
|
21151
|
+
instructions: config?.instructions,
|
|
21152
|
+
builtIn: name === "capture"
|
|
21153
|
+
};
|
|
21154
|
+
}
|
|
21155
|
+
function resolveAgent(entry, builtIns, globalModel, globalMaxSteps) {
|
|
21156
|
+
const config = typeof entry === "string" ? void 0 : entry;
|
|
21157
|
+
const name = entryName(entry);
|
|
21158
|
+
return {
|
|
21159
|
+
name,
|
|
21160
|
+
instructions: config?.instructions,
|
|
21161
|
+
model: config?.model ?? globalModel,
|
|
21162
|
+
agent: config?.agent,
|
|
21163
|
+
maxSteps: boundedSteps(config, globalMaxSteps),
|
|
21164
|
+
builtIn: builtIns.has(name)
|
|
21165
|
+
};
|
|
21166
|
+
}
|
|
21167
|
+
/**
|
|
21168
|
+
* Configures experimental autonomous knowledge extraction and reflection.
|
|
21169
|
+
*
|
|
21170
|
+
* @experimental This API may change without notice.
|
|
21171
|
+
*/
|
|
21172
|
+
var Subconscious = class {
|
|
21173
|
+
config;
|
|
21174
|
+
resolved;
|
|
21175
|
+
constructor(config = {}) {
|
|
21176
|
+
const observation = config.observation ?? ["capture", "remind"];
|
|
21177
|
+
const reflection = config.reflection ?? ["curate", "learn"];
|
|
21178
|
+
assertUniqueNames(observation, "observation");
|
|
21179
|
+
assertUniqueNames(reflection, "reflection");
|
|
21180
|
+
const maxSteps = boundedSteps(config, DEFAULT_MAX_STEPS);
|
|
21181
|
+
for (const entry of observation) this.#validateObservationEntry(entry);
|
|
21182
|
+
for (const entry of reflection) this.#validateReflectionEntry(entry);
|
|
21183
|
+
const recentUpdates = config.activity === false ? false : config.activity?.recentUpdates ?? DEFAULT_RECENT_UPDATES;
|
|
21184
|
+
if (recentUpdates !== false && (!Number.isInteger(recentUpdates) || recentUpdates < 1 || recentUpdates > MAX_RECENT_UPDATES)) throw new Error(`Subconscious activity.recentUpdates must be an integer between 1 and ${MAX_RECENT_UPDATES}.`);
|
|
21185
|
+
const pins = config.pins === void 0 || config.pins === false ? false : {
|
|
21186
|
+
maxPins: (config.pins === true ? void 0 : config.pins.maxPins) ?? 20,
|
|
21187
|
+
maxCharacters: (config.pins === true ? void 0 : config.pins.maxCharacters) ?? 2e3,
|
|
21188
|
+
capturePinning: (config.pins === true ? void 0 : config.pins.capturePinning) ?? false
|
|
21189
|
+
};
|
|
21190
|
+
if (pins !== false) {
|
|
21191
|
+
if (!Number.isInteger(pins.maxPins) || pins.maxPins < 1) throw new Error("Subconscious pins.maxPins must be a positive integer.");
|
|
21192
|
+
if (!Number.isInteger(pins.maxCharacters) || pins.maxCharacters < 1 || pins.maxCharacters > 8e3) throw new Error(`Subconscious pins.maxCharacters must be an integer between 1 and ${MAX_PINNED_MAX_CHARACTERS}.`);
|
|
21193
|
+
}
|
|
21194
|
+
if (config.curationCadence !== void 0 && (!Number.isInteger(config.curationCadence) || config.curationCadence < 1)) throw new Error("Subconscious curationCadence must be a positive integer.");
|
|
21195
|
+
this.config = Object.freeze({
|
|
21196
|
+
...config,
|
|
21197
|
+
observation: [...observation],
|
|
21198
|
+
reflection: [...reflection]
|
|
21199
|
+
});
|
|
21200
|
+
this.resolved = Object.freeze({
|
|
21201
|
+
observation: observation.map((entry) => entryName(entry) === "remind" ? resolveAgent(entry, BUILT_IN_OBSERVATION, config.model, maxSteps) : resolveExtractor(entry)),
|
|
21202
|
+
reflection: reflection.map((entry) => resolveAgent(entry, BUILT_IN_REFLECTION, config.model, maxSteps)),
|
|
21203
|
+
defaultScope: config.defaultScope ?? "resource",
|
|
21204
|
+
maxScope: config.maxScope,
|
|
21205
|
+
learnedGuidance: config.learnedGuidance !== false,
|
|
21206
|
+
tools: config.tools !== false,
|
|
21207
|
+
activity: recentUpdates === false ? false : { recentUpdates },
|
|
21208
|
+
pins,
|
|
21209
|
+
curationCadence: config.curationCadence
|
|
21210
|
+
});
|
|
21211
|
+
}
|
|
21212
|
+
createObservationExtractors(omModel) {
|
|
21213
|
+
const extractors = [];
|
|
21214
|
+
for (const entry of this.config.observation ?? []) {
|
|
21215
|
+
const name = entryName(entry);
|
|
21216
|
+
if (name === "capture") extractors.push(new SubconsciousCaptureExtractor({
|
|
21217
|
+
config: typeof entry === "string" ? void 0 : entry,
|
|
21218
|
+
defaultScope: this.resolved.defaultScope,
|
|
21219
|
+
maxScope: this.resolved.maxScope,
|
|
21220
|
+
learnedGuidance: this.resolved.learnedGuidance,
|
|
21221
|
+
activityRecentUpdates: this.resolved.activity === false ? void 0 : this.resolved.activity.recentUpdates,
|
|
21222
|
+
pins: this.resolved.pins
|
|
21223
|
+
}));
|
|
21224
|
+
else if (name === "remind") {
|
|
21225
|
+
const resolved = this.resolved.observation.find((agent) => agent.name === name);
|
|
21226
|
+
if (resolved) extractors.push(new SubconsciousRemindExtractor(resolved, omModel));
|
|
21227
|
+
} else if (!BUILT_IN_OBSERVATION.has(name)) {
|
|
21228
|
+
const custom = entry;
|
|
21229
|
+
extractors.push(new Extractor({
|
|
21230
|
+
name: custom.name,
|
|
21231
|
+
instructions: custom.instructions?.trim() || `Extract ${custom.name} from the current observations.`,
|
|
21232
|
+
schema: custom.schema,
|
|
21233
|
+
metadataKeyPath: false,
|
|
21234
|
+
includePreviousExtraction: false,
|
|
21235
|
+
onExtracted: custom.onExtracted
|
|
21236
|
+
}));
|
|
21237
|
+
}
|
|
21238
|
+
}
|
|
21239
|
+
return extractors;
|
|
21240
|
+
}
|
|
21241
|
+
#validateObservationEntry(entry) {
|
|
21242
|
+
const name = entryName(entry);
|
|
21243
|
+
if (typeof entry === "string") {
|
|
21244
|
+
if (!BUILT_IN_OBSERVATION.has(name)) throw new Error(`Unknown Subconscious observation agent: ${name}`);
|
|
21245
|
+
return;
|
|
21246
|
+
}
|
|
21247
|
+
if (BUILT_IN_OBSERVATION.has(name)) {
|
|
21248
|
+
if (name === "capture") {
|
|
21249
|
+
if ("model" in entry || "maxSteps" in entry) throw new Error("Subconscious capture shares the Observer model and does not accept model or maxSteps.");
|
|
21250
|
+
if ("schema" in entry && entry.schema && (!("onExtracted" in entry) || typeof entry.onExtracted !== "function")) throw new Error("A custom capture schema requires an onExtracted hook that handles its output.");
|
|
21251
|
+
}
|
|
21252
|
+
return;
|
|
21253
|
+
}
|
|
21254
|
+
if ("model" in entry || "maxSteps" in entry) throw new Error(`Subconscious observation extractor "${name}" shares the Observer model and does not accept model or maxSteps.`);
|
|
21255
|
+
if (!("schema" in entry) || !entry.schema || !("onExtracted" in entry) || typeof entry.onExtracted !== "function") throw new Error(`Custom Subconscious observation agent "${name}" requires schema and onExtracted.`);
|
|
21256
|
+
}
|
|
21257
|
+
#validateReflectionEntry(entry) {
|
|
21258
|
+
const name = entryName(entry);
|
|
21259
|
+
if (typeof entry === "string") {
|
|
21260
|
+
if (!BUILT_IN_REFLECTION.has(name)) throw new Error(`Unknown Subconscious reflection agent: ${name}`);
|
|
21261
|
+
return;
|
|
21262
|
+
}
|
|
21263
|
+
if (BUILT_IN_REFLECTION.has(name) && "agent" in entry && entry.agent) throw new Error(`Built-in Subconscious reflection agent "${name}" cannot be replaced with a custom agent.`);
|
|
21264
|
+
if (!BUILT_IN_REFLECTION.has(name) && !entry.instructions?.trim() && !("agent" in entry && entry.agent)) throw new Error(`Custom Subconscious reflection agent "${name}" requires instructions or agent.`);
|
|
21265
|
+
}
|
|
21266
|
+
};
|
|
21267
|
+
const CURATION_AGENT = "curate";
|
|
21268
|
+
const DEFAULT_INSTRUCTIONS$1 = `Maintain durable scoped knowledge from the committed observation worklist.
|
|
21269
|
+
|
|
21270
|
+
Use the read tools to inspect existing nodes, knowledge records, mentions, backlinks, and long-form node content. Use the write tools to merge true duplicates, repair names and links, soft-delete superseded knowledge records, rescope knowledge records only when justified and permitted by their ceilings, and synthesize useful node content. Never restore deleted knowledge records. Never invent provenance, capture timestamps, scopes, ceilings, IDs, or versions; those are enforced by code. Resolve optimistic-concurrency conflicts by reading the latest record and retrying the intended mutation. Keep the reserved capture-guidance node concise and update it only with durable guidance that will improve future capture.
|
|
21271
|
+
|
|
21272
|
+
Process the worklist in ID order. Every time you finish processing a KnowledgeRecord, include <curation-complete through="RECORD_ID" /> in your next text response with that record's ID. The latest marker is your acknowledged cursor, so progress survives if you run out of steps mid-batch. Your final response must end with the marker for the last KnowledgeRecord you fully processed. If you cannot finish the batch, acknowledge only the last KnowledgeRecord you did finish. Do not emit a completion marker when no KnowledgeRecord was fully processed.`;
|
|
21273
|
+
const PINNED_INSTRUCTIONS = `Maintain the pin set with knowledge_pin, knowledge_edit_pin, and knowledge_unpin. Pinned entries are delivered to the main agent on every turn, so they cost tokens permanently and must stay short. Pin only knowledge that should apply without being asked for, such as standing instructions, durable preferences, and hard constraints. Pin only knowledge that is BOTH costly to rediscover AND not the kind of thing a future agent would think to search for; anything a reminder can surface on demand does not belong in the pin set. Unpin an entry as soon as it stops being unconditionally true.`;
|
|
21274
|
+
function resolveScope$1(context) {
|
|
21275
|
+
const organizationId = context.requestContext?.get("organizationId");
|
|
21276
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) throw new Error("Subconscious curate requires organizationId in the request context.");
|
|
21277
|
+
return (0, _mastra_core_storage.canonicalizeKnowledgeScope)([
|
|
21278
|
+
`org:${organizationId}`,
|
|
21279
|
+
`resource:${resolveKnowledgeResourceId(context.requestContext, context.resourceId)}`,
|
|
21280
|
+
`thread:${context.parentThreadId}`
|
|
21281
|
+
]);
|
|
21282
|
+
}
|
|
21283
|
+
async function readWorklist$1(store, sourceThreadId, scope, after) {
|
|
21284
|
+
const records = [];
|
|
21285
|
+
let cursor = after;
|
|
21286
|
+
do {
|
|
21287
|
+
const page = await store.knowledgeBySource({
|
|
21288
|
+
sourceThreadId,
|
|
21289
|
+
scope,
|
|
21290
|
+
after: cursor,
|
|
21291
|
+
limit: 100,
|
|
21292
|
+
includeDeleted: true
|
|
21293
|
+
});
|
|
21294
|
+
records.push(...page.records);
|
|
21295
|
+
cursor = page.nextCursor;
|
|
21296
|
+
} while (cursor && records.length < 500);
|
|
21297
|
+
return {
|
|
21298
|
+
records,
|
|
21299
|
+
hasMore: Boolean(cursor)
|
|
21300
|
+
};
|
|
21301
|
+
}
|
|
21302
|
+
function createCuratorHandler(memory, subconscious, curatorMemory = memory, options) {
|
|
21303
|
+
const config = subconscious.reflection.find((agent) => agent.name === CURATION_AGENT);
|
|
21304
|
+
if (!config) return async () => "no-op";
|
|
21305
|
+
return async (context) => {
|
|
21306
|
+
let store;
|
|
21307
|
+
let scope;
|
|
21308
|
+
try {
|
|
21309
|
+
scope = resolveScope$1(context);
|
|
21310
|
+
store = await memory.storage.getStore("knowledge");
|
|
21311
|
+
if (!store) throw new Error("Subconscious curate requires a configured knowledge storage domain.");
|
|
21312
|
+
const cursor = await store.getCurationCursor({
|
|
21313
|
+
sourceThreadId: context.parentThreadId,
|
|
21314
|
+
agent: CURATION_AGENT
|
|
21315
|
+
});
|
|
21316
|
+
const worklist = await readWorklist$1(store, context.parentThreadId, scope, cursor?.lastKnowledgeId);
|
|
21317
|
+
if (!worklist.records.length && !context.observations.trim()) return "no-op";
|
|
21318
|
+
const result = await (await createCuratorAgent(memory, curatorMemory, context, scope, config, subconscious, options?.omModel)).generate(`Parent thread: ${context.parentThreadId}\nCurrent time: ${(/* @__PURE__ */ new Date()).toISOString()}\nWorklist truncated: ${worklist.hasMore}\n\nCommitted pre-reflection observations:\n${context.observations}\n\nNew KnowledgeRecord worklist:\n${JSON.stringify(worklist.records)}`, {
|
|
21319
|
+
requestContext: context.requestContext,
|
|
21320
|
+
abortSignal: context.abortSignal,
|
|
21321
|
+
maxSteps: config.maxSteps,
|
|
21322
|
+
memory: {
|
|
21323
|
+
thread: `subconscious:${context.parentThreadId}:curate`,
|
|
21324
|
+
resource: context.resourceId
|
|
21325
|
+
}
|
|
21326
|
+
});
|
|
21327
|
+
if (worklist.records.length) {
|
|
21328
|
+
const acknowledgedId = [...result.text.matchAll(/<curation-complete\s+through=["']([^"']+)["']\s*\/>/gi)].at(-1)?.[1];
|
|
21329
|
+
if (!acknowledgedId || !worklist.records.some((record) => record.id === acknowledgedId)) throw new Error("Curator did not acknowledge a valid processed KnowledgeRecord cursor.");
|
|
21330
|
+
await store.advanceCurationCursor({
|
|
21331
|
+
sourceThreadId: context.parentThreadId,
|
|
21332
|
+
agent: CURATION_AGENT,
|
|
21333
|
+
lastKnowledgeId: acknowledgedId
|
|
21334
|
+
});
|
|
21335
|
+
}
|
|
21336
|
+
return "ran";
|
|
21337
|
+
} catch (error) {
|
|
21338
|
+
const message = `curate: ${error instanceof Error ? error.message : String(error)}`;
|
|
21339
|
+
await context.writer?.custom({
|
|
21340
|
+
type: "data-subconscious-error",
|
|
21341
|
+
data: {
|
|
21342
|
+
agent: "curate",
|
|
21343
|
+
error: message
|
|
21344
|
+
}
|
|
21345
|
+
});
|
|
21346
|
+
if (store && scope) await publishSubconsciousActivity({
|
|
21347
|
+
store,
|
|
21348
|
+
scope,
|
|
21349
|
+
recentUpdates: subconscious.activity === false ? 10 : subconscious.activity.recentUpdates,
|
|
21350
|
+
sendStateSignal: context.sendStateSignal,
|
|
21351
|
+
errors: [message]
|
|
21352
|
+
});
|
|
21353
|
+
else await publishSubconsciousError({
|
|
21354
|
+
error: message,
|
|
21355
|
+
sendStateSignal: context.sendStateSignal
|
|
21356
|
+
});
|
|
21357
|
+
throw error;
|
|
21358
|
+
}
|
|
21359
|
+
};
|
|
21360
|
+
}
|
|
21361
|
+
async function createCuratorAgent(memory, curatorMemory, context, scope, config, subconscious, omModel) {
|
|
21362
|
+
const model = await resolveSubconsciousAgentModel({
|
|
21363
|
+
config,
|
|
21364
|
+
omModel,
|
|
21365
|
+
mainAgent: context.mainAgent,
|
|
21366
|
+
requestContext: context.requestContext
|
|
21367
|
+
});
|
|
21368
|
+
if (!model) throw new Error("Subconscious curate requires the main agent to resolve its model.");
|
|
21369
|
+
return new _mastra_core_agent.Agent({
|
|
21370
|
+
id: `subconscious-curate-${context.parentThreadId}`,
|
|
21371
|
+
name: "Subconscious Curate",
|
|
21372
|
+
instructions: [
|
|
21373
|
+
DEFAULT_INSTRUCTIONS$1,
|
|
21374
|
+
subconscious.pins ? PINNED_INSTRUCTIONS : void 0,
|
|
21375
|
+
config.instructions?.trim()
|
|
21376
|
+
].filter(Boolean).join("\n\n"),
|
|
21377
|
+
model,
|
|
21378
|
+
memory: curatorMemory,
|
|
21379
|
+
tools: {
|
|
21380
|
+
...createKnowledgeTools(memory),
|
|
21381
|
+
...createKnowledgeWriteTools(memory, {
|
|
21382
|
+
scope,
|
|
21383
|
+
sourceThreadId: context.parentThreadId,
|
|
21384
|
+
defaultScope: subconscious.defaultScope,
|
|
21385
|
+
maxScope: subconscious.maxScope
|
|
21386
|
+
}),
|
|
21387
|
+
...subconscious.pins ? createPinnedTools(memory, {
|
|
21388
|
+
scope,
|
|
21389
|
+
sourceThreadId: context.parentThreadId,
|
|
21390
|
+
defaultScope: subconscious.defaultScope,
|
|
21391
|
+
maxScope: subconscious.maxScope,
|
|
21392
|
+
maxPins: subconscious.pins.maxPins,
|
|
21393
|
+
maxCharacters: subconscious.pins.maxCharacters
|
|
21394
|
+
}) : {}
|
|
21395
|
+
}
|
|
21396
|
+
});
|
|
21397
|
+
}
|
|
21398
|
+
const LEARN_AGENT = "learn";
|
|
21399
|
+
const ULID_ALPHABET = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
21400
|
+
const DEFAULT_INSTRUCTIONS = `Learn reusable skills from the full pre-reflection observations and pending knowledge records.
|
|
21401
|
+
|
|
21402
|
+
A skill is a repeatable procedure with ordered actions, a trigger or context, and a success or recovery outcome. Do not learn one-off events, isolated preferences, knowledge records, or procedures supported by fewer than two distinct pending knowledge records. Search existing kind:skill nodes by exact name before writing so updates extend one skill rather than creating duplicates.
|
|
21403
|
+
|
|
21404
|
+
Use knowledge_record_skill for every skill creation or evidence update. It validates the evidence frontier and writes retry-safe evidence. You may use the other scoped knowledge tools for research and maintenance, but never restore deleted records, invent provenance or versions, or write outside the source scope.
|
|
21405
|
+
|
|
21406
|
+
Process pending records in ID order. End with <learning-complete through="RECORD_ID" /> naming the last pending record you reviewed, even when no reusable skill was found. Acknowledge only records you fully reviewed.`;
|
|
21407
|
+
function resolveScope(context) {
|
|
21408
|
+
const organizationId = context.requestContext?.get("organizationId");
|
|
21409
|
+
if (typeof organizationId !== "string" || !organizationId.trim()) throw new Error("Subconscious learn requires organizationId in the request context.");
|
|
21410
|
+
return (0, _mastra_core_storage.canonicalizeKnowledgeScope)([
|
|
21411
|
+
`org:${organizationId}`,
|
|
21412
|
+
`resource:${resolveKnowledgeResourceId(context.requestContext, context.resourceId)}`,
|
|
21413
|
+
`thread:${context.parentThreadId}`
|
|
21414
|
+
]);
|
|
21415
|
+
}
|
|
21416
|
+
async function readWorklist(store, sourceThreadId, scope, after) {
|
|
21417
|
+
const records = [];
|
|
21418
|
+
let cursor = after;
|
|
21419
|
+
do {
|
|
21420
|
+
const page = await store.knowledgeBySource({
|
|
21421
|
+
sourceThreadId,
|
|
21422
|
+
scope,
|
|
21423
|
+
after: cursor,
|
|
21424
|
+
limit: 100
|
|
21425
|
+
});
|
|
21426
|
+
records.push(...page.records);
|
|
21427
|
+
cursor = page.nextCursor;
|
|
21428
|
+
} while (cursor && records.length < 500);
|
|
21429
|
+
return {
|
|
21430
|
+
records,
|
|
21431
|
+
hasMore: Boolean(cursor)
|
|
21432
|
+
};
|
|
21433
|
+
}
|
|
21434
|
+
function evidenceRecordId(sourceRecordId, skillName) {
|
|
21435
|
+
const hash = (0, crypto$1.createHash)("sha256").update(`${skillName.trim().toLocaleLowerCase()}\0${sourceRecordId}`).digest();
|
|
21436
|
+
let suffix = "";
|
|
21437
|
+
for (let index = 0; index < 16; index++) suffix += ULID_ALPHABET[hash[index] & 31];
|
|
21438
|
+
return `${sourceRecordId.slice(0, 10)}${suffix}`;
|
|
21439
|
+
}
|
|
21440
|
+
function createLearnerRecordSkillTool(input) {
|
|
21441
|
+
return (0, _mastra_core_tools.createTool)({
|
|
21442
|
+
id: "knowledge_record_skill",
|
|
21443
|
+
description: "Create or update one reusable skill using at least two distinct pending knowledge records. Evidence writes are idempotent across retries.",
|
|
21444
|
+
inputSchema: {
|
|
21445
|
+
type: "object",
|
|
21446
|
+
properties: {
|
|
21447
|
+
name: {
|
|
21448
|
+
type: "string",
|
|
21449
|
+
minLength: 1
|
|
21450
|
+
},
|
|
21451
|
+
procedure: {
|
|
21452
|
+
type: "string",
|
|
21453
|
+
minLength: 1
|
|
21454
|
+
},
|
|
21455
|
+
sourceRecordIds: {
|
|
21456
|
+
type: "array",
|
|
21457
|
+
items: {
|
|
21458
|
+
type: "string",
|
|
21459
|
+
minLength: 1
|
|
21460
|
+
},
|
|
21461
|
+
minItems: 2,
|
|
21462
|
+
uniqueItems: true
|
|
21463
|
+
}
|
|
21464
|
+
},
|
|
21465
|
+
required: [
|
|
21466
|
+
"name",
|
|
21467
|
+
"procedure",
|
|
21468
|
+
"sourceRecordIds"
|
|
21469
|
+
],
|
|
21470
|
+
additionalProperties: false
|
|
21471
|
+
},
|
|
21472
|
+
execute: async (raw) => {
|
|
21473
|
+
const value = raw;
|
|
21474
|
+
const sourceIds = [...new Set(value.sourceRecordIds)];
|
|
21475
|
+
const pending = new Map(input.pendingRecords.map((record) => [record.id, record]));
|
|
21476
|
+
if (sourceIds.length < 2 || sourceIds.some((id) => !pending.has(id))) throw new Error("Skill evidence requires at least two distinct records from the pending learner worklist.");
|
|
21477
|
+
const normalizedName = value.name.trim();
|
|
21478
|
+
if (input.state.recordedName && input.state.recordedName.toLocaleLowerCase() !== normalizedName.toLocaleLowerCase()) throw new Error("The learner may record at most one skill per reflection.");
|
|
21479
|
+
input.state.recordedName = normalizedName;
|
|
21480
|
+
const nodeScope = (0, _mastra_core_storage.expandKnowledgeScope)(input.scope, input.defaultScope);
|
|
21481
|
+
let node = await input.store.resolveNode({
|
|
21482
|
+
name: normalizedName,
|
|
21483
|
+
scope: input.scope
|
|
21484
|
+
});
|
|
21485
|
+
if (node && node.kind !== "skill") throw new Error(`Knowledge node is not a skill: ${normalizedName}`);
|
|
21486
|
+
node ??= await input.store.createNode({
|
|
21487
|
+
name: normalizedName,
|
|
21488
|
+
kind: "skill",
|
|
21489
|
+
scope: nodeScope
|
|
21490
|
+
});
|
|
21491
|
+
const evidence = [];
|
|
21492
|
+
for (const sourceId of sourceIds) {
|
|
21493
|
+
const id = evidenceRecordId(sourceId, normalizedName);
|
|
21494
|
+
const existing = await input.store.getKnowledge({ id });
|
|
21495
|
+
if (existing) {
|
|
21496
|
+
evidence.push(existing);
|
|
21497
|
+
continue;
|
|
21498
|
+
}
|
|
21499
|
+
const source = pending.get(sourceId);
|
|
21500
|
+
try {
|
|
21501
|
+
evidence.push(await input.store.appendKnowledge({
|
|
21502
|
+
id,
|
|
21503
|
+
node: node.id,
|
|
21504
|
+
text: `Procedure: ${value.procedure.trim()} Evidence source: ${source.id}.`,
|
|
21505
|
+
scope: source.scope,
|
|
21506
|
+
sourceThreadId: `subconscious:${input.parentThreadId}:learn`,
|
|
21507
|
+
maxScope: source.maxScope ?? input.maxScope,
|
|
21508
|
+
resolutionScope: input.scope,
|
|
21509
|
+
defaultScope: nodeScope
|
|
21510
|
+
}));
|
|
21511
|
+
} catch (error) {
|
|
21512
|
+
const raced = await input.store.getKnowledge({ id });
|
|
21513
|
+
if (!raced) throw error;
|
|
21514
|
+
evidence.push(raced);
|
|
21515
|
+
}
|
|
21516
|
+
}
|
|
21517
|
+
return {
|
|
21518
|
+
node,
|
|
21519
|
+
evidence
|
|
21520
|
+
};
|
|
21521
|
+
}
|
|
21522
|
+
});
|
|
21523
|
+
}
|
|
21524
|
+
function composeReflectionAgentHandlers(handlers) {
|
|
21525
|
+
return async (context) => {
|
|
21526
|
+
for (const handler of handlers) try {
|
|
21527
|
+
await handler(context);
|
|
21528
|
+
} catch (error) {
|
|
21529
|
+
if (context.abortSignal?.aborted) throw error;
|
|
21530
|
+
}
|
|
21531
|
+
};
|
|
21532
|
+
}
|
|
21533
|
+
function createLearnerHandler(memory, subconscious, learnerMemory = memory, options) {
|
|
21534
|
+
const config = subconscious.reflection.find((agent) => agent.name === LEARN_AGENT);
|
|
21535
|
+
if (!config) return async () => {};
|
|
21536
|
+
return async (context) => {
|
|
21537
|
+
let store;
|
|
21538
|
+
let scope;
|
|
21539
|
+
try {
|
|
21540
|
+
scope = resolveScope(context);
|
|
21541
|
+
store = await memory.storage.getStore("knowledge");
|
|
21542
|
+
if (!store) throw new Error("Subconscious learn requires a configured knowledge storage domain.");
|
|
21543
|
+
const cursor = await store.getCurationCursor({
|
|
21544
|
+
sourceThreadId: context.parentThreadId,
|
|
21545
|
+
agent: LEARN_AGENT
|
|
21546
|
+
});
|
|
21547
|
+
const worklist = await readWorklist(store, context.parentThreadId, scope, cursor?.lastKnowledgeId);
|
|
21548
|
+
if (!worklist.records.length) return;
|
|
21549
|
+
const acknowledgedId = (await (await createLearnerAgent(memory, learnerMemory, context, scope, worklist.records, config, subconscious, options?.omModel)).generate(`Parent thread: ${context.parentThreadId}\nCurrent time: ${(/* @__PURE__ */ new Date()).toISOString()}\nWorklist truncated: ${worklist.hasMore}\n\nFull pre-reflection observations:\n${context.observations}\n\nPending knowledge records:\n${JSON.stringify(worklist.records)}`, {
|
|
21550
|
+
requestContext: context.requestContext,
|
|
21551
|
+
abortSignal: context.abortSignal,
|
|
21552
|
+
maxSteps: config.maxSteps,
|
|
21553
|
+
memory: {
|
|
21554
|
+
thread: `subconscious:${context.parentThreadId}:learn`,
|
|
21555
|
+
resource: context.resourceId
|
|
21556
|
+
}
|
|
21557
|
+
})).text.match(/<learning-complete\s+through=["']([^"']+)["']\s*\/>/i)?.[1];
|
|
21558
|
+
if (!acknowledgedId || !worklist.records.some((record) => record.id === acknowledgedId)) throw new Error("Learner did not acknowledge a valid reviewed record cursor.");
|
|
21559
|
+
await store.advanceCurationCursor({
|
|
21560
|
+
sourceThreadId: context.parentThreadId,
|
|
21561
|
+
agent: LEARN_AGENT,
|
|
21562
|
+
lastKnowledgeId: acknowledgedId
|
|
21563
|
+
});
|
|
21564
|
+
} catch (error) {
|
|
21565
|
+
const message = `learn: ${error instanceof Error ? error.message : String(error)}`;
|
|
21566
|
+
await context.writer?.custom({
|
|
21567
|
+
type: "data-subconscious-error",
|
|
21568
|
+
data: {
|
|
21569
|
+
agent: "learn",
|
|
21570
|
+
error: message
|
|
21571
|
+
}
|
|
21572
|
+
});
|
|
21573
|
+
if (store && scope) await publishSubconsciousActivity({
|
|
21574
|
+
store,
|
|
21575
|
+
scope,
|
|
21576
|
+
recentUpdates: subconscious.activity === false ? 10 : subconscious.activity.recentUpdates,
|
|
21577
|
+
sendStateSignal: context.sendStateSignal,
|
|
21578
|
+
errors: [message]
|
|
21579
|
+
});
|
|
21580
|
+
else await publishSubconsciousError({
|
|
21581
|
+
error: message,
|
|
21582
|
+
sendStateSignal: context.sendStateSignal
|
|
21583
|
+
});
|
|
21584
|
+
throw error;
|
|
21585
|
+
}
|
|
21586
|
+
};
|
|
21587
|
+
}
|
|
21588
|
+
async function createLearnerAgent(memory, learnerMemory, context, scope, pendingRecords, config, subconscious, omModel) {
|
|
21589
|
+
const model = await resolveSubconsciousAgentModel({
|
|
21590
|
+
config,
|
|
21591
|
+
omModel,
|
|
21592
|
+
mainAgent: context.mainAgent,
|
|
21593
|
+
requestContext: context.requestContext
|
|
21594
|
+
});
|
|
21595
|
+
if (!model) throw new Error("Subconscious learn requires the main agent to resolve its model.");
|
|
21596
|
+
const store = await memory.storage.getStore("knowledge");
|
|
21597
|
+
if (!store) throw new Error("Subconscious learn requires a configured knowledge storage domain.");
|
|
21598
|
+
const state = {};
|
|
21599
|
+
return new _mastra_core_agent.Agent({
|
|
21600
|
+
id: `subconscious-learn-${context.parentThreadId}`,
|
|
21601
|
+
name: "Subconscious Learn",
|
|
21602
|
+
instructions: [DEFAULT_INSTRUCTIONS, config.instructions?.trim()].filter(Boolean).join("\n\n"),
|
|
21603
|
+
model,
|
|
21604
|
+
memory: learnerMemory,
|
|
21605
|
+
tools: {
|
|
21606
|
+
...createKnowledgeTools(memory, scope),
|
|
21607
|
+
...createKnowledgeWriteTools(memory, {
|
|
21608
|
+
scope,
|
|
21609
|
+
sourceThreadId: context.parentThreadId,
|
|
21610
|
+
defaultScope: subconscious.defaultScope,
|
|
21611
|
+
maxScope: subconscious.maxScope
|
|
21612
|
+
}),
|
|
21613
|
+
knowledge_record_skill: createLearnerRecordSkillTool({
|
|
21614
|
+
store,
|
|
21615
|
+
scope,
|
|
21616
|
+
pendingRecords,
|
|
21617
|
+
parentThreadId: context.parentThreadId,
|
|
21618
|
+
defaultScope: subconscious.defaultScope,
|
|
21619
|
+
maxScope: subconscious.maxScope,
|
|
21620
|
+
state
|
|
21621
|
+
})
|
|
21622
|
+
}
|
|
21623
|
+
});
|
|
21624
|
+
}
|
|
19243
21625
|
var constants_exports = /* @__PURE__ */ __exportAll({
|
|
19244
21626
|
OBSERVATIONAL_MEMORY_DEFAULTS: () => OBSERVATIONAL_MEMORY_DEFAULTS,
|
|
19245
21627
|
OBSERVATION_CONTEXT_INSTRUCTIONS: () => OBSERVATION_CONTEXT_INSTRUCTIONS,
|
|
@@ -19394,232 +21776,6 @@ Observation groups with range IDs and your recall tool allows you to think back
|
|
|
19394
21776
|
### Additional recall guidance
|
|
19395
21777
|
${custom}`;
|
|
19396
21778
|
}
|
|
19397
|
-
const BUILT_IN_SLUGS = /* @__PURE__ */ new Set([
|
|
19398
|
-
"current-task",
|
|
19399
|
-
"suggested-response",
|
|
19400
|
-
"thread-title"
|
|
19401
|
-
]);
|
|
19402
|
-
const EXTRACTED_VALUES_TAG = "extracted-values";
|
|
19403
|
-
const RESERVED_XML_TAGS = /* @__PURE__ */ new Set([
|
|
19404
|
-
"observations",
|
|
19405
|
-
"observation",
|
|
19406
|
-
EXTRACTED_VALUES_TAG,
|
|
19407
|
-
"thread",
|
|
19408
|
-
"message",
|
|
19409
|
-
"messages",
|
|
19410
|
-
"conversation",
|
|
19411
|
-
"history",
|
|
19412
|
-
"system",
|
|
19413
|
-
"user",
|
|
19414
|
-
"assistant",
|
|
19415
|
-
"tool",
|
|
19416
|
-
...BUILT_IN_SLUGS
|
|
19417
|
-
]);
|
|
19418
|
-
const BUILT_IN_EXTRACTOR_SLUGS = [...BUILT_IN_SLUGS];
|
|
19419
|
-
function isBuiltInExtractorSlug(slug) {
|
|
19420
|
-
return BUILT_IN_SLUGS.has(slug);
|
|
19421
|
-
}
|
|
19422
|
-
function slugifyExtractorName(name) {
|
|
19423
|
-
let normalized = "";
|
|
19424
|
-
let previousWasSeparator = false;
|
|
19425
|
-
for (const char of name.trim().toLowerCase()) {
|
|
19426
|
-
const code = char.charCodeAt(0);
|
|
19427
|
-
if (code >= 97 && code <= 122 || code >= 48 && code <= 57) {
|
|
19428
|
-
normalized += char;
|
|
19429
|
-
previousWasSeparator = false;
|
|
19430
|
-
continue;
|
|
19431
|
-
}
|
|
19432
|
-
if (char === "'" || char === "\"" || char === "`") continue;
|
|
19433
|
-
if (!previousWasSeparator && normalized.length > 0) {
|
|
19434
|
-
normalized += "-";
|
|
19435
|
-
previousWasSeparator = true;
|
|
19436
|
-
}
|
|
19437
|
-
}
|
|
19438
|
-
return normalized.endsWith("-") ? normalized.slice(0, -1) : normalized;
|
|
19439
|
-
}
|
|
19440
|
-
function assertValidSlug(slug, name) {
|
|
19441
|
-
if (!slug) throw new Error(`Extractor name "${name}" must produce a non-empty slug.`);
|
|
19442
|
-
const first = slug.charCodeAt(0);
|
|
19443
|
-
const last = slug.charCodeAt(slug.length - 1);
|
|
19444
|
-
const startsWithLetter = first >= 97 && first <= 122;
|
|
19445
|
-
const endsWithLetterOrNumber = last >= 97 && last <= 122 || last >= 48 && last <= 57;
|
|
19446
|
-
const hasOnlySlugCharacters = [...slug].every((char) => {
|
|
19447
|
-
const code = char.charCodeAt(0);
|
|
19448
|
-
return code >= 97 && code <= 122 || code >= 48 && code <= 57 || char === "-";
|
|
19449
|
-
});
|
|
19450
|
-
if (!startsWithLetter || !endsWithLetterOrNumber || !hasOnlySlugCharacters) throw new Error(`Extractor name "${name}" produced invalid slug "${slug}".`);
|
|
19451
|
-
}
|
|
19452
|
-
var Extractor = class Extractor {
|
|
19453
|
-
name;
|
|
19454
|
-
slug;
|
|
19455
|
-
instructions;
|
|
19456
|
-
schema;
|
|
19457
|
-
mode;
|
|
19458
|
-
includePreviousExtraction;
|
|
19459
|
-
metadataKeyPath;
|
|
19460
|
-
onExtracted;
|
|
19461
|
-
retryStructuredExtractionOnEmptyObject;
|
|
19462
|
-
/** @internal */
|
|
19463
|
-
internal;
|
|
19464
|
-
instructionsConfig;
|
|
19465
|
-
schemaConfig;
|
|
19466
|
-
constructor(config, internal = false) {
|
|
19467
|
-
const name = config.name.trim();
|
|
19468
|
-
const instructions = typeof config.instructions === "string" ? config.instructions.trim() : void 0;
|
|
19469
|
-
const slug = slugifyExtractorName(name);
|
|
19470
|
-
if (!name) throw new Error("Extractor name is required.");
|
|
19471
|
-
if (instructions !== void 0 && !instructions) throw new Error(`Extractor "${name}" must include instructions.`);
|
|
19472
|
-
assertValidSlug(slug, name);
|
|
19473
|
-
if (!internal && RESERVED_XML_TAGS.has(slug)) throw new Error(`Extractor slug "${slug}" is reserved by Observational Memory.`);
|
|
19474
|
-
this.name = name;
|
|
19475
|
-
this.slug = slug;
|
|
19476
|
-
this.instructionsConfig = config.instructions;
|
|
19477
|
-
this.schemaConfig = config.schema;
|
|
19478
|
-
this.instructions = instructions ?? "";
|
|
19479
|
-
this.schema = typeof config.schema === "function" ? zod.z.string() : config.schema ?? zod.z.string();
|
|
19480
|
-
this.mode = internal || !config.schema ? "inline" : "structured";
|
|
19481
|
-
this.includePreviousExtraction = config.includePreviousExtraction ?? true;
|
|
19482
|
-
this.metadataKeyPath = config.metadataKeyPath ?? `extracted.${slug}`;
|
|
19483
|
-
this.onExtracted = config.onExtracted;
|
|
19484
|
-
this.retryStructuredExtractionOnEmptyObject = config.retryStructuredExtractionOnEmptyObject ?? false;
|
|
19485
|
-
this.internal = internal;
|
|
19486
|
-
}
|
|
19487
|
-
async resolve(context) {
|
|
19488
|
-
const instructions = typeof this.instructionsConfig === "function" ? (await this.instructionsConfig(context)).trim() : this.instructionsConfig.trim();
|
|
19489
|
-
if (!instructions) throw new Error(`Extractor "${this.name}" must include instructions.`);
|
|
19490
|
-
const schema = typeof this.schemaConfig === "function" ? await this.schemaConfig(context) : this.schemaConfig;
|
|
19491
|
-
return new Extractor({
|
|
19492
|
-
name: this.name,
|
|
19493
|
-
instructions,
|
|
19494
|
-
...schema ? { schema } : {},
|
|
19495
|
-
includePreviousExtraction: this.includePreviousExtraction,
|
|
19496
|
-
metadataKeyPath: this.metadataKeyPath,
|
|
19497
|
-
onExtracted: this.onExtracted,
|
|
19498
|
-
retryStructuredExtractionOnEmptyObject: this.retryStructuredExtractionOnEmptyObject
|
|
19499
|
-
}, this.internal);
|
|
19500
|
-
}
|
|
19501
|
-
};
|
|
19502
|
-
async function resolveExtractors(extractors, context) {
|
|
19503
|
-
return Promise.all(extractors.map((extractor) => extractor.resolve(context)));
|
|
19504
|
-
}
|
|
19505
|
-
function validateExtractorList(extractors) {
|
|
19506
|
-
const seen = /* @__PURE__ */ new Map();
|
|
19507
|
-
for (const extractor of extractors) {
|
|
19508
|
-
assertValidSlug(extractor.slug, extractor.name);
|
|
19509
|
-
if (!extractor.internal && RESERVED_XML_TAGS.has(extractor.slug)) throw new Error(`Extractor slug "${extractor.slug}" is reserved by Observational Memory.`);
|
|
19510
|
-
const previous = seen.get(extractor.slug);
|
|
19511
|
-
if (previous) throw new Error(`Duplicate extractor slug "${extractor.slug}" from "${previous}" and "${extractor.name}".`);
|
|
19512
|
-
seen.set(extractor.slug, extractor.name);
|
|
19513
|
-
}
|
|
19514
|
-
return [...extractors];
|
|
19515
|
-
}
|
|
19516
|
-
function isJsonLike(value) {
|
|
19517
|
-
return /^(?:[\[{"-]|\d|true\b|false\b|null\b)/.test(value.trim());
|
|
19518
|
-
}
|
|
19519
|
-
function candidateValues(raw) {
|
|
19520
|
-
const trimmed = raw.trim();
|
|
19521
|
-
const candidates = [];
|
|
19522
|
-
const add = (value) => {
|
|
19523
|
-
if (!candidates.some((candidate) => Object.is(candidate, value))) candidates.push(value);
|
|
19524
|
-
};
|
|
19525
|
-
if (isJsonLike(trimmed)) try {
|
|
19526
|
-
add(JSON.parse(trimmed));
|
|
19527
|
-
} catch {}
|
|
19528
|
-
add(trimmed);
|
|
19529
|
-
if (!isJsonLike(trimmed)) try {
|
|
19530
|
-
add(JSON.parse(trimmed));
|
|
19531
|
-
} catch {}
|
|
19532
|
-
return candidates;
|
|
19533
|
-
}
|
|
19534
|
-
function parseExtractorValue(extractor, raw) {
|
|
19535
|
-
const failures = [];
|
|
19536
|
-
for (const candidate of candidateValues(raw)) {
|
|
19537
|
-
const parsed = extractor.schema.safeParse(candidate);
|
|
19538
|
-
if (parsed.success) return parsed.data;
|
|
19539
|
-
failures.push(parsed.error.message);
|
|
19540
|
-
}
|
|
19541
|
-
throw new Error(`Extractor "${extractor.slug}" output did not match its schema: ${failures[0] ?? "invalid value"}`);
|
|
19542
|
-
}
|
|
19543
|
-
function parseExtractedValuesObject(raw) {
|
|
19544
|
-
const trimmed = raw.trim();
|
|
19545
|
-
if (!trimmed || trimmed.startsWith("Write only the extracted values JSON object here.")) return;
|
|
19546
|
-
const parsed = JSON.parse(trimmed);
|
|
19547
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${EXTRACTED_VALUES_TAG} must contain a JSON object.`);
|
|
19548
|
-
return parsed;
|
|
19549
|
-
}
|
|
19550
|
-
function parseExtractedValues(output, extractors) {
|
|
19551
|
-
const values = {};
|
|
19552
|
-
const failures = [];
|
|
19553
|
-
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19554
|
-
const regex = new RegExp(`<${EXTRACTED_VALUES_TAG}>([\\s\\S]*?)<\\/${EXTRACTED_VALUES_TAG}>`, "gi");
|
|
19555
|
-
const matches = [...output.matchAll(regex)];
|
|
19556
|
-
for (const match of matches) try {
|
|
19557
|
-
const extractedValues = parseExtractedValuesObject(match[1] ?? "");
|
|
19558
|
-
if (!extractedValues) continue;
|
|
19559
|
-
for (const extractor of inlineExtractors) {
|
|
19560
|
-
if (!Object.prototype.hasOwnProperty.call(extractedValues, extractor.slug)) continue;
|
|
19561
|
-
const rawValue = extractedValues[extractor.slug];
|
|
19562
|
-
if (rawValue === void 0 || rawValue === null || rawValue === "") continue;
|
|
19563
|
-
const parsed = extractor.schema.safeParse(rawValue);
|
|
19564
|
-
if (parsed.success) values[extractor.slug] = parsed.data;
|
|
19565
|
-
else failures.push({
|
|
19566
|
-
slug: extractor.slug,
|
|
19567
|
-
error: parsed.error.message
|
|
19568
|
-
});
|
|
19569
|
-
}
|
|
19570
|
-
} catch (error) {
|
|
19571
|
-
failures.push({
|
|
19572
|
-
slug: EXTRACTED_VALUES_TAG,
|
|
19573
|
-
error: error instanceof Error ? error.message : String(error)
|
|
19574
|
-
});
|
|
19575
|
-
}
|
|
19576
|
-
for (const extractor of inlineExtractors) {
|
|
19577
|
-
if (Object.prototype.hasOwnProperty.call(values, extractor.slug)) continue;
|
|
19578
|
-
const tagRegex = new RegExp(`<${extractor.slug}>([\\s\\S]*?)<\\/${extractor.slug}>`, "gi");
|
|
19579
|
-
const rawValue = [...output.matchAll(tagRegex)].at(-1)?.[1]?.trim();
|
|
19580
|
-
if (!rawValue) continue;
|
|
19581
|
-
try {
|
|
19582
|
-
values[extractor.slug] = parseExtractorValue(extractor, rawValue);
|
|
19583
|
-
} catch (error) {
|
|
19584
|
-
failures.push({
|
|
19585
|
-
slug: extractor.slug,
|
|
19586
|
-
error: error instanceof Error ? error.message : String(error)
|
|
19587
|
-
});
|
|
19588
|
-
}
|
|
19589
|
-
}
|
|
19590
|
-
return {
|
|
19591
|
-
values,
|
|
19592
|
-
failures
|
|
19593
|
-
};
|
|
19594
|
-
}
|
|
19595
|
-
function stripExtractorSections(output, extractors) {
|
|
19596
|
-
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19597
|
-
let stripped = output.replace(new RegExp(`[ \\t]*<${EXTRACTED_VALUES_TAG}>[\\s\\S]*?<\\/${EXTRACTED_VALUES_TAG}>\\s*`, "gi"), "");
|
|
19598
|
-
for (const extractor of inlineExtractors) stripped = stripped.replace(new RegExp(`[ \\t]*<${extractor.slug}>[\\s\\S]*?<\\/${extractor.slug}>\\s*`, "gi"), "");
|
|
19599
|
-
return stripped;
|
|
19600
|
-
}
|
|
19601
|
-
function buildExtractorOutputSections(extractors) {
|
|
19602
|
-
const inlineExtractors = extractors.filter((extractor) => extractor.mode === "inline");
|
|
19603
|
-
if (inlineExtractors.length === 0) return "";
|
|
19604
|
-
return `Additional optional XML sections:\nIf the observations include information relevant to any of these tags, output that tag after <observations> and include the relevant information.\n${inlineExtractors.map((extractor) => `<${extractor.slug}>
|
|
19605
|
-
${extractor.instructions}
|
|
19606
|
-
Include this section when the observations contain relevant information for <${extractor.slug}>. Write only that information inside the tag.
|
|
19607
|
-
</${extractor.slug}>`).join("\n\n")}`;
|
|
19608
|
-
}
|
|
19609
|
-
function renderPriorValue(value) {
|
|
19610
|
-
return typeof value === "string" ? value : JSON.stringify(value);
|
|
19611
|
-
}
|
|
19612
|
-
function buildExtractorPriorLines(extractors, priorExtractedValues) {
|
|
19613
|
-
if (!priorExtractedValues) return [];
|
|
19614
|
-
const lines = [];
|
|
19615
|
-
for (const extractor of extractors) {
|
|
19616
|
-
if (!extractor.includePreviousExtraction) continue;
|
|
19617
|
-
const value = priorExtractedValues[extractor.slug];
|
|
19618
|
-
if (value === void 0 || value === null || value === "") continue;
|
|
19619
|
-
lines.push(`<${extractor.slug}>\n${renderPriorValue(value)}\n</${extractor.slug}>`);
|
|
19620
|
-
}
|
|
19621
|
-
return lines;
|
|
19622
|
-
}
|
|
19623
21779
|
const BUILT_IN_METADATA_FIELDS = {
|
|
19624
21780
|
"current-task": {
|
|
19625
21781
|
metadataField: "currentTask",
|
|
@@ -19741,9 +21897,11 @@ async function applyExtractorHooks(opts) {
|
|
|
19741
21897
|
const values = normalizeExtractedValues(opts.values) ?? {};
|
|
19742
21898
|
const failures = [...opts.failures ?? []];
|
|
19743
21899
|
for (const extractor of opts.extractors) {
|
|
19744
|
-
|
|
19745
|
-
const
|
|
19746
|
-
if (!
|
|
21900
|
+
const isHook = extractor.mode === "hook";
|
|
21901
|
+
const hasValue = Object.prototype.hasOwnProperty.call(values, extractor.slug);
|
|
21902
|
+
if (!isHook && !hasValue) continue;
|
|
21903
|
+
const current = isHook ? opts.rawObservations : values[extractor.slug];
|
|
21904
|
+
if (!isHook && !isPresentExtractedValue(current)) {
|
|
19747
21905
|
delete values[extractor.slug];
|
|
19748
21906
|
continue;
|
|
19749
21907
|
}
|
|
@@ -19754,14 +21912,19 @@ async function applyExtractorHooks(opts) {
|
|
|
19754
21912
|
extractor,
|
|
19755
21913
|
threadId: opts.threadId,
|
|
19756
21914
|
resourceId: opts.resourceId,
|
|
19757
|
-
previous: opts.previousValues?.[extractor.slug],
|
|
21915
|
+
previous: isHook ? void 0 : opts.previousValues?.[extractor.slug],
|
|
19758
21916
|
current,
|
|
21917
|
+
rawObservations: opts.rawObservations,
|
|
21918
|
+
recentMessages: opts.recentMessages,
|
|
19759
21919
|
mainAgent: opts.mainAgent,
|
|
19760
21920
|
memory: opts.memory,
|
|
19761
21921
|
sendSignal: opts.sendSignal,
|
|
21922
|
+
sendStateSignal: opts.sendStateSignal,
|
|
21923
|
+
writer: opts.writer,
|
|
21924
|
+
abortSignal: opts.abortSignal,
|
|
19762
21925
|
requestContext: opts.requestContext
|
|
19763
21926
|
});
|
|
19764
|
-
if (hookValue === void 0) continue;
|
|
21927
|
+
if (isHook || hookValue === void 0) continue;
|
|
19765
21928
|
const parsed = extractor.schema.safeParse(hookValue);
|
|
19766
21929
|
if (parsed.success) values[extractor.slug] = parsed.data;
|
|
19767
21930
|
else {
|
|
@@ -19772,7 +21935,8 @@ async function applyExtractorHooks(opts) {
|
|
|
19772
21935
|
});
|
|
19773
21936
|
}
|
|
19774
21937
|
} catch (error) {
|
|
19775
|
-
|
|
21938
|
+
if (opts.abortSignal?.aborted) throw error;
|
|
21939
|
+
if (!isHook) delete values[extractor.slug];
|
|
19776
21940
|
failures.push({
|
|
19777
21941
|
slug: extractor.slug,
|
|
19778
21942
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -20821,11 +22985,11 @@ function formatObserverAttachmentPlaceholder(part, counter) {
|
|
|
20821
22985
|
const label = resolveObserverAttachmentLabel(part);
|
|
20822
22986
|
return label ? `[${attachmentType} #${attachmentId}: ${label}]` : `[${attachmentType} #${attachmentId}]`;
|
|
20823
22987
|
}
|
|
20824
|
-
function isRecord$
|
|
22988
|
+
function isRecord$3(value) {
|
|
20825
22989
|
return !!value && typeof value === "object";
|
|
20826
22990
|
}
|
|
20827
22991
|
function mapToolResultBlockToAttachment(block) {
|
|
20828
|
-
if (!isRecord$
|
|
22992
|
+
if (!isRecord$3(block) || typeof block.type !== "string") return;
|
|
20829
22993
|
const mediaType = typeof block.mediaType === "string" ? block.mediaType : void 0;
|
|
20830
22994
|
const filename = typeof block.filename === "string" ? block.filename : void 0;
|
|
20831
22995
|
switch (block.type) {
|
|
@@ -20886,7 +23050,7 @@ function mapToolResultBlockToAttachment(block) {
|
|
|
20886
23050
|
}
|
|
20887
23051
|
}
|
|
20888
23052
|
function extractToolResultAttachments(result, counter, attachmentFilter) {
|
|
20889
|
-
if (!isRecord$
|
|
23053
|
+
if (!isRecord$3(result) || result.type !== "content" || !Array.isArray(result.value)) return {
|
|
20890
23054
|
resultWithoutAttachments: result,
|
|
20891
23055
|
attachments: []
|
|
20892
23056
|
};
|
|
@@ -20900,7 +23064,7 @@ function extractToolResultAttachments(result, counter, attachmentFilter) {
|
|
|
20900
23064
|
if (shouldIncludeObserverAttachment(attachment, attachmentFilter)) attachments.push(toObserverInputAttachmentPart(attachment));
|
|
20901
23065
|
const placeholder = formatObserverAttachmentPlaceholder(attachment, counter);
|
|
20902
23066
|
return {
|
|
20903
|
-
type: isRecord$
|
|
23067
|
+
type: isRecord$3(block) ? block.type : void 0,
|
|
20904
23068
|
placeholder
|
|
20905
23069
|
};
|
|
20906
23070
|
});
|
|
@@ -21356,6 +23520,52 @@ function detectDegenerateRepetition(text) {
|
|
|
21356
23520
|
return false;
|
|
21357
23521
|
}
|
|
21358
23522
|
/**
|
|
23523
|
+
* Build a single-line diagnostic description of output flagged by
|
|
23524
|
+
* {@link detectDegenerateRepetition}. Used when logging or surfacing a
|
|
23525
|
+
* degenerate-output failure so the discarded model output can be inspected —
|
|
23526
|
+
* without it there is no way to tell a real repetition loop apart from a
|
|
23527
|
+
* detector false-positive on legitimately repetitive content.
|
|
23528
|
+
*
|
|
23529
|
+
* Reuses the detector's sampling parameters (200-char windows, ~50 samples)
|
|
23530
|
+
* so the reported duplicate ratio and most-repeated window match what
|
|
23531
|
+
* triggered the detection. Snippets are JSON-escaped so the result stays on
|
|
23532
|
+
* one line.
|
|
23533
|
+
*/
|
|
23534
|
+
function describeDegenerateOutput(text, snippetChars = 400) {
|
|
23535
|
+
const windowSize = 200;
|
|
23536
|
+
const step = Math.max(1, Math.floor(text.length / 50));
|
|
23537
|
+
const seen = /* @__PURE__ */ new Map();
|
|
23538
|
+
let duplicateWindows = 0;
|
|
23539
|
+
let totalWindows = 0;
|
|
23540
|
+
for (let i = 0; i + windowSize <= text.length; i += step) {
|
|
23541
|
+
const window = text.slice(i, i + windowSize);
|
|
23542
|
+
totalWindows++;
|
|
23543
|
+
const count = (seen.get(window) ?? 0) + 1;
|
|
23544
|
+
seen.set(window, count);
|
|
23545
|
+
if (count > 1) duplicateWindows++;
|
|
23546
|
+
}
|
|
23547
|
+
let topWindow = "";
|
|
23548
|
+
let topCount = 0;
|
|
23549
|
+
for (const [window, count] of seen) if (count > topCount) {
|
|
23550
|
+
topCount = count;
|
|
23551
|
+
topWindow = window;
|
|
23552
|
+
}
|
|
23553
|
+
let longestLine = 0;
|
|
23554
|
+
for (const line of text.split("\n")) if (line.length > longestLine) longestLine = line.length;
|
|
23555
|
+
const duplicateRatio = totalWindows > 0 ? (duplicateWindows / totalWindows).toFixed(2) : "n/a";
|
|
23556
|
+
const parts = [
|
|
23557
|
+
`length=${text.length}`,
|
|
23558
|
+
`sampledWindows=${totalWindows}`,
|
|
23559
|
+
`duplicateRatio=${duplicateRatio}`,
|
|
23560
|
+
`longestLine=${longestLine}`,
|
|
23561
|
+
`topWindowCount=${topCount}`
|
|
23562
|
+
];
|
|
23563
|
+
if (topCount > 1) parts.push(`topWindow=${JSON.stringify(topWindow)}`);
|
|
23564
|
+
parts.push(`head=${JSON.stringify(text.slice(0, snippetChars))}`);
|
|
23565
|
+
if (text.length > snippetChars * 2) parts.push(`tail=${JSON.stringify(text.slice(-snippetChars))}`);
|
|
23566
|
+
return parts.join(" ");
|
|
23567
|
+
}
|
|
23568
|
+
/**
|
|
21359
23569
|
* Check if observations contain a Current Task section.
|
|
21360
23570
|
* Supports both XML format and legacy markdown format.
|
|
21361
23571
|
*/
|
|
@@ -21441,17 +23651,17 @@ const TRANSIENT_MESSAGE_SUBSTRINGS = [
|
|
|
21441
23651
|
"connection reset",
|
|
21442
23652
|
"connection closed"
|
|
21443
23653
|
];
|
|
21444
|
-
function isRecord$
|
|
23654
|
+
function isRecord$2(value) {
|
|
21445
23655
|
return typeof value === "object" && value !== null;
|
|
21446
23656
|
}
|
|
21447
23657
|
function isAbortError$5(error) {
|
|
21448
|
-
if (!isRecord$
|
|
23658
|
+
if (!isRecord$2(error)) return false;
|
|
21449
23659
|
if (error.name === "AbortError") return true;
|
|
21450
23660
|
if (typeof error.code === "string" && error.code === "ABORT_ERR") return true;
|
|
21451
23661
|
return false;
|
|
21452
23662
|
}
|
|
21453
23663
|
function hasTransientMessage(value) {
|
|
21454
|
-
if (!isRecord$
|
|
23664
|
+
if (!isRecord$2(value)) return false;
|
|
21455
23665
|
const message = typeof value.message === "string" ? value.message.toLowerCase() : "";
|
|
21456
23666
|
if (message && TRANSIENT_MESSAGE_SUBSTRINGS.some((sub) => message.includes(sub))) return true;
|
|
21457
23667
|
if (typeof value.code === "string" && value.code.toUpperCase().startsWith("UND_ERR_")) return true;
|
|
@@ -21462,13 +23672,13 @@ function isRetryableHttpStatus(status) {
|
|
|
21462
23672
|
return status >= 500 && status <= 599;
|
|
21463
23673
|
}
|
|
21464
23674
|
function hasRetryableHttpStatus(value) {
|
|
21465
|
-
if (!isRecord$
|
|
23675
|
+
if (!isRecord$2(value)) return false;
|
|
21466
23676
|
if (typeof value.statusCode === "number" && isRetryableHttpStatus(value.statusCode)) return true;
|
|
21467
23677
|
if (typeof value.code === "number" && isRetryableHttpStatus(value.code)) return true;
|
|
21468
23678
|
return false;
|
|
21469
23679
|
}
|
|
21470
23680
|
function hasIsRetryableFlag(value) {
|
|
21471
|
-
if (!isRecord$
|
|
23681
|
+
if (!isRecord$2(value)) return false;
|
|
21472
23682
|
return value.isRetryable === true;
|
|
21473
23683
|
}
|
|
21474
23684
|
/**
|
|
@@ -21486,14 +23696,14 @@ function isTransientLLMError(error) {
|
|
|
21486
23696
|
if (isAbortError$5(error)) return false;
|
|
21487
23697
|
const visited = /* @__PURE__ */ new WeakSet();
|
|
21488
23698
|
function visit(candidate) {
|
|
21489
|
-
if (isRecord$
|
|
23699
|
+
if (isRecord$2(candidate)) {
|
|
21490
23700
|
if (visited.has(candidate)) return false;
|
|
21491
23701
|
visited.add(candidate);
|
|
21492
23702
|
}
|
|
21493
23703
|
if (hasTransientMessage(candidate)) return true;
|
|
21494
23704
|
if (hasRetryableHttpStatus(candidate)) return true;
|
|
21495
23705
|
if (hasIsRetryableFlag(candidate)) return true;
|
|
21496
|
-
if (isRecord$
|
|
23706
|
+
if (isRecord$2(candidate)) {
|
|
21497
23707
|
if (visit(candidate.cause)) return true;
|
|
21498
23708
|
if (visit(candidate.error)) return true;
|
|
21499
23709
|
}
|
|
@@ -21750,13 +23960,13 @@ var ObserverRunner = class {
|
|
|
21750
23960
|
let parsed = parseObserverOutput(result.text, activeExtractors);
|
|
21751
23961
|
let retriedDueToDegenerate = false;
|
|
21752
23962
|
if (parsed.degenerate) {
|
|
21753
|
-
omDebug(`[OM:callObserver] degenerate repetition detected, retrying once`);
|
|
23963
|
+
omDebug(`[OM:callObserver] degenerate repetition detected, retrying once. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
21754
23964
|
result = await doGenerate();
|
|
21755
23965
|
parsed = parseObserverOutput(result.text, activeExtractors);
|
|
21756
23966
|
retriedDueToDegenerate = true;
|
|
21757
23967
|
if (parsed.degenerate) {
|
|
21758
|
-
omDebug(`[OM:callObserver] degenerate repetition on retry, failing`);
|
|
21759
|
-
throw new Error(
|
|
23968
|
+
omDebug(`[OM:callObserver] degenerate repetition on retry, failing. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
23969
|
+
throw new Error(`Observer produced degenerate output after retry. ${describeDegenerateOutput(result.text)}`);
|
|
21760
23970
|
}
|
|
21761
23971
|
}
|
|
21762
23972
|
const structuredExtraction = await extractStructuredValues({
|
|
@@ -21900,13 +24110,13 @@ var ObserverRunner = class {
|
|
|
21900
24110
|
let parsed = parseMultiThreadObserverOutput(result.text, activeExtractors);
|
|
21901
24111
|
let retriedDueToDegenerate = false;
|
|
21902
24112
|
if (parsed.degenerate) {
|
|
21903
|
-
omDebug(`[OM:callMultiThreadObserver] degenerate repetition detected, retrying once`);
|
|
24113
|
+
omDebug(`[OM:callMultiThreadObserver] degenerate repetition detected, retrying once. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
21904
24114
|
result = await doGenerate();
|
|
21905
24115
|
parsed = parseMultiThreadObserverOutput(result.text, activeExtractors);
|
|
21906
24116
|
retriedDueToDegenerate = true;
|
|
21907
24117
|
if (parsed.degenerate) {
|
|
21908
|
-
omDebug(`[OM:callMultiThreadObserver] degenerate repetition on retry, failing`);
|
|
21909
|
-
throw new Error(
|
|
24118
|
+
omDebug(`[OM:callMultiThreadObserver] degenerate repetition on retry, failing. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
24119
|
+
throw new Error(`Multi-thread observer produced degenerate output after retry. ${describeDegenerateOutput(result.text)}`);
|
|
21910
24120
|
}
|
|
21911
24121
|
}
|
|
21912
24122
|
const structuredExtractionByThread = /* @__PURE__ */ new Map();
|
|
@@ -22267,7 +24477,7 @@ async function resolveImageDimensionsAsync(part) {
|
|
|
22267
24477
|
const url = resolveHttpAssetUrl(getObjectValue(part, "image") ?? getObjectValue(part, "data"));
|
|
22268
24478
|
if (!url) return existing;
|
|
22269
24479
|
try {
|
|
22270
|
-
const probeImageSize = (await Promise.resolve().then(() => /* @__PURE__ */ require_rolldown_runtime.__toESM(require("./probe-image-size-
|
|
24480
|
+
const probeImageSize = (await Promise.resolve().then(() => /* @__PURE__ */ require_rolldown_runtime.__toESM(require("./probe-image-size-CDCRrXNo.cjs").default, 1))).default;
|
|
22271
24481
|
const probed = await probeImageSize(url, {
|
|
22272
24482
|
open_timeout: REMOTE_IMAGE_PROBE_TIMEOUT_MS,
|
|
22273
24483
|
response_timeout: REMOTE_IMAGE_PROBE_TIMEOUT_MS,
|
|
@@ -24713,38 +26923,6 @@ function createWorkingMemoryTool(config, options = {}) {
|
|
|
24713
26923
|
tool
|
|
24714
26924
|
};
|
|
24715
26925
|
}
|
|
24716
|
-
function isTieredModelTarget(model) {
|
|
24717
|
-
if (typeof model === "string") return true;
|
|
24718
|
-
if (!model || typeof model !== "object") return false;
|
|
24719
|
-
return "modelId" in model || "id" in model || "providerId" in model || "provider" in model || "doGenerate" in model && "doStream" in model;
|
|
24720
|
-
}
|
|
24721
|
-
function normalizeThresholds(config) {
|
|
24722
|
-
const entries = Object.entries(config.upTo);
|
|
24723
|
-
if (entries.length === 0) throw new Error("ModelByInputTokens requires at least one threshold in \"upTo\"");
|
|
24724
|
-
for (const [limitStr, model] of entries) {
|
|
24725
|
-
const limit = Number(limitStr);
|
|
24726
|
-
if (!Number.isFinite(limit) || limit <= 0) throw new Error(`ModelByInputTokens threshold keys must be positive numbers. Got: ${limitStr}`);
|
|
24727
|
-
if (!isTieredModelTarget(model)) throw new Error(`ModelByInputTokens requires a valid model target for threshold ${limitStr}`);
|
|
24728
|
-
}
|
|
24729
|
-
return entries.map(([limitStr, model]) => ({
|
|
24730
|
-
limit: Number(limitStr),
|
|
24731
|
-
model
|
|
24732
|
-
})).sort((a, b) => a.limit - b.limit);
|
|
24733
|
-
}
|
|
24734
|
-
var ModelByInputTokens = class {
|
|
24735
|
-
thresholds;
|
|
24736
|
-
constructor(config) {
|
|
24737
|
-
this.thresholds = normalizeThresholds(config);
|
|
24738
|
-
}
|
|
24739
|
-
resolve(inputTokens) {
|
|
24740
|
-
for (const { limit, model } of this.thresholds) if (inputTokens <= limit) return model;
|
|
24741
|
-
const maxLimit = this.thresholds[this.thresholds.length - 1].limit;
|
|
24742
|
-
throw new Error(`ModelByInputTokens: input token count (${inputTokens}) exceeds the largest configured threshold (${maxLimit}). Please configure a higher threshold or use a larger model.`);
|
|
24743
|
-
}
|
|
24744
|
-
getThresholds() {
|
|
24745
|
-
return this.thresholds.map((t) => t.limit);
|
|
24746
|
-
}
|
|
24747
|
-
};
|
|
24748
26926
|
const MINUTE = 6e4;
|
|
24749
26927
|
const HOUR = 60 * MINUTE;
|
|
24750
26928
|
const SHORT_TTL = 5 * MINUTE;
|
|
@@ -25537,6 +27715,39 @@ function reconcileObservationGroupsFromReflection(content, sourceObservations) {
|
|
|
25537
27715
|
if (derivedGroups.length > 0) return derivedGroups.map((group) => wrapInObservationGroup(group.content, group.range, group.id, void 0, group.kind)).join("\n\n");
|
|
25538
27716
|
return wrapInObservationGroup(normalizedContent, combineObservationGroupRanges(sourceGroups), generateAnchorId(), void 0, "reflection");
|
|
25539
27717
|
}
|
|
27718
|
+
function isRecord$1(value) {
|
|
27719
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
27720
|
+
}
|
|
27721
|
+
function isSubconsciousSignalMessage(message) {
|
|
27722
|
+
if (message.role !== "signal" || !isRecord$1(message.content)) return false;
|
|
27723
|
+
const contentMetadata = message.content.metadata;
|
|
27724
|
+
if (!isRecord$1(contentMetadata) || !isRecord$1(contentMetadata.signal)) return false;
|
|
27725
|
+
const signal = contentMetadata.signal;
|
|
27726
|
+
const metadata = signal.metadata;
|
|
27727
|
+
const attributes = signal.attributes;
|
|
27728
|
+
return signal.origin === "subconscious" || isRecord$1(metadata) && metadata.origin === "subconscious" || isRecord$1(attributes) && attributes.source === "subconscious";
|
|
27729
|
+
}
|
|
27730
|
+
function isSubconsciousSignalPart(part) {
|
|
27731
|
+
if (!part || typeof part !== "object") return false;
|
|
27732
|
+
const candidate = part;
|
|
27733
|
+
return candidate.type === "data-signal" && (candidate.data?.metadata?.origin === "subconscious" || candidate.data?.attributes?.source === "subconscious");
|
|
27734
|
+
}
|
|
27735
|
+
function stripSubconsciousSignals(messages) {
|
|
27736
|
+
return messages.flatMap((message) => {
|
|
27737
|
+
if (isSubconsciousSignalMessage(message)) return [];
|
|
27738
|
+
if (typeof message.content === "string") return [message];
|
|
27739
|
+
const parts = message.content.parts.filter((part) => !isSubconsciousSignalPart(part));
|
|
27740
|
+
if (parts.length === message.content.parts.length) return [message];
|
|
27741
|
+
if (parts.length === 0) return [];
|
|
27742
|
+
return [{
|
|
27743
|
+
...message,
|
|
27744
|
+
content: {
|
|
27745
|
+
...message.content,
|
|
27746
|
+
parts
|
|
27747
|
+
}
|
|
27748
|
+
}];
|
|
27749
|
+
});
|
|
27750
|
+
}
|
|
25540
27751
|
/**
|
|
25541
27752
|
* Get the maximum value from a threshold (simple number or range).
|
|
25542
27753
|
*/
|
|
@@ -25690,8 +27901,9 @@ var ObservationStrategy = class ObservationStrategy {
|
|
|
25690
27901
|
if (fresh?.lastObservedAt && record.lastObservedAt && fresh.lastObservedAt > record.lastObservedAt) return { observed: false };
|
|
25691
27902
|
}
|
|
25692
27903
|
const { messages, existingObservations } = await this.prepare();
|
|
27904
|
+
const observationMessages = stripSubconsciousSignals(messages);
|
|
25693
27905
|
await this.emitStartMarkers(cycleId);
|
|
25694
|
-
const output = await this.observe(existingObservations,
|
|
27906
|
+
const output = await this.observe(existingObservations, observationMessages);
|
|
25695
27907
|
const processed = await this.process(output, existingObservations);
|
|
25696
27908
|
await this.persist(processed);
|
|
25697
27909
|
await this.emitEndMarkers(cycleId, processed);
|
|
@@ -25706,6 +27918,7 @@ var ObservationStrategy = class ObservationStrategy {
|
|
|
25706
27918
|
abortSignal,
|
|
25707
27919
|
mainAgent: this.opts.agent,
|
|
25708
27920
|
sendSignal: this.opts.sendSignal,
|
|
27921
|
+
sendStateSignal: this.opts.sendStateSignal,
|
|
25709
27922
|
reflectionHooks,
|
|
25710
27923
|
requestContext,
|
|
25711
27924
|
observabilityContext: this.opts.observabilityContext
|
|
@@ -25991,11 +28204,16 @@ var SyncObservationStrategy = class extends ObservationStrategy {
|
|
|
25991
28204
|
values: result.extractedValues,
|
|
25992
28205
|
failures: result.extractionFailures,
|
|
25993
28206
|
previousValues: this.priorExtractedValues,
|
|
28207
|
+
rawObservations: result.observations,
|
|
28208
|
+
recentMessages: formatMessagesForObserver(this.opts.messages, { maxPartLength: 500 }),
|
|
25994
28209
|
threadId: this.opts.threadId,
|
|
25995
28210
|
resourceId: this.opts.resourceId,
|
|
25996
28211
|
mainAgent: this.opts.agent,
|
|
25997
28212
|
memory: this.deps.memory,
|
|
25998
28213
|
sendSignal: this.opts.sendSignal,
|
|
28214
|
+
sendStateSignal: this.opts.sendStateSignal,
|
|
28215
|
+
writer: this.opts.writer,
|
|
28216
|
+
abortSignal: this.opts.abortSignal,
|
|
25999
28217
|
requestContext: this.opts.requestContext
|
|
26000
28218
|
});
|
|
26001
28219
|
const output = {
|
|
@@ -26169,11 +28387,16 @@ var AsyncBufferObservationStrategy = class extends ObservationStrategy {
|
|
|
26169
28387
|
values: result.extractedValues,
|
|
26170
28388
|
failures: result.extractionFailures,
|
|
26171
28389
|
previousValues: this.priorExtractedValues,
|
|
28390
|
+
rawObservations: result.observations,
|
|
28391
|
+
recentMessages: formatMessagesForObserver(messages, { maxPartLength: 500 }),
|
|
26172
28392
|
threadId: this.opts.threadId,
|
|
26173
28393
|
resourceId: this.opts.resourceId,
|
|
26174
28394
|
mainAgent: this.opts.agent,
|
|
26175
28395
|
memory: this.deps.memory,
|
|
26176
28396
|
sendSignal: this.opts.sendSignal,
|
|
28397
|
+
sendStateSignal: this.opts.sendStateSignal,
|
|
28398
|
+
writer: this.opts.writer,
|
|
28399
|
+
abortSignal: this.opts.abortSignal,
|
|
26177
28400
|
requestContext: this.opts.requestContext
|
|
26178
28401
|
});
|
|
26179
28402
|
return {
|
|
@@ -26506,11 +28729,25 @@ var ResourceScopedObservationStrategy = class extends ObservationStrategy {
|
|
|
26506
28729
|
values: result.extractedValues,
|
|
26507
28730
|
failures: result.extractionFailures,
|
|
26508
28731
|
previousValues,
|
|
28732
|
+
rawObservations: result.observations,
|
|
28733
|
+
recentMessages: formatMessagesForObserver(threadMessages, { maxPartLength: 500 }),
|
|
26509
28734
|
threadId,
|
|
26510
28735
|
resourceId: this.resourceId,
|
|
26511
28736
|
mainAgent: this.opts.agent,
|
|
26512
28737
|
memory: this.deps.memory,
|
|
26513
|
-
sendSignal: this.opts.
|
|
28738
|
+
sendSignal: this.opts.agent ? async (signal) => {
|
|
28739
|
+
const delivery = this.opts.agent.sendSignal(signal, {
|
|
28740
|
+
resourceId: this.resourceId,
|
|
28741
|
+
threadId,
|
|
28742
|
+
ifActive: { behavior: "deliver" },
|
|
28743
|
+
ifIdle: { behavior: "persist" }
|
|
28744
|
+
});
|
|
28745
|
+
await delivery.accepted;
|
|
28746
|
+
return delivery.signal;
|
|
28747
|
+
} : void 0,
|
|
28748
|
+
sendStateSignal: this.opts.sendStateSignal,
|
|
28749
|
+
writer: this.opts.writer,
|
|
28750
|
+
abortSignal: this.opts.abortSignal,
|
|
26514
28751
|
requestContext: this.opts.requestContext
|
|
26515
28752
|
});
|
|
26516
28753
|
this.observationResults.push({
|
|
@@ -26830,6 +29067,9 @@ var ObservationStep = class {
|
|
|
26830
29067
|
pendingTokens: statusSnapshot.pendingTokens,
|
|
26831
29068
|
record: statusSnapshot.record,
|
|
26832
29069
|
writer: this.turn.writer,
|
|
29070
|
+
agent: this.turn.agent,
|
|
29071
|
+
sendSignal: this.turn.sendSignal,
|
|
29072
|
+
sendStateSignal: this.turn.sendStateSignal,
|
|
26833
29073
|
requestContext: this.turn.requestContext,
|
|
26834
29074
|
observabilityContext: this.turn.observabilityContext
|
|
26835
29075
|
}).catch((err) => {
|
|
@@ -27006,6 +29246,9 @@ var ObservationStep = class {
|
|
|
27006
29246
|
messages: observableMessages,
|
|
27007
29247
|
messageList,
|
|
27008
29248
|
trigger: "turn-sync",
|
|
29249
|
+
agent: this.turn.agent,
|
|
29250
|
+
sendSignal: this.turn.sendSignal,
|
|
29251
|
+
sendStateSignal: this.turn.sendStateSignal,
|
|
27009
29252
|
requestContext: this.turn.requestContext,
|
|
27010
29253
|
writer: this.turn.writer,
|
|
27011
29254
|
observabilityContext: this.turn.observabilityContext
|
|
@@ -27083,6 +29326,8 @@ var ObservationTurn = class {
|
|
|
27083
29326
|
agent;
|
|
27084
29327
|
/** Optional signal sender for processor-originated notifications. */
|
|
27085
29328
|
sendSignal;
|
|
29329
|
+
/** Optional state signal sender for processor-originated snapshots. */
|
|
29330
|
+
sendStateSignal;
|
|
27086
29331
|
/** Current actor model for this step. Updated by the processor before prepare(). */
|
|
27087
29332
|
actorModelContext;
|
|
27088
29333
|
/** The active assistant response message ID for this step. Updated by the processor before prepare(). */
|
|
@@ -27096,6 +29341,7 @@ var ObservationTurn = class {
|
|
|
27096
29341
|
this.messageList = opts.messageList;
|
|
27097
29342
|
this.agent = opts.agent;
|
|
27098
29343
|
this.sendSignal = opts.sendSignal;
|
|
29344
|
+
this.sendStateSignal = opts.sendStateSignal;
|
|
27099
29345
|
this.requestContext = opts.requestContext;
|
|
27100
29346
|
this.observabilityContext = opts.observabilityContext;
|
|
27101
29347
|
this.hooks = opts.hooks ?? {};
|
|
@@ -27208,6 +29454,7 @@ var ObservationTurn = class {
|
|
|
27208
29454
|
writer: this.writer,
|
|
27209
29455
|
agent: this.agent,
|
|
27210
29456
|
sendSignal: this.sendSignal,
|
|
29457
|
+
sendStateSignal: this.sendStateSignal,
|
|
27211
29458
|
requestContext: this.requestContext,
|
|
27212
29459
|
currentModel: this.actorModelContext,
|
|
27213
29460
|
observabilityContext: this.observabilityContext,
|
|
@@ -27612,6 +29859,7 @@ var ReflectorRunner = class {
|
|
|
27612
29859
|
persistMarkerToMessage;
|
|
27613
29860
|
getCompressionStartLevel;
|
|
27614
29861
|
memory;
|
|
29862
|
+
onReflectionCommitted;
|
|
27615
29863
|
mastra;
|
|
27616
29864
|
constructor(opts) {
|
|
27617
29865
|
this.reflectionConfig = opts.reflectionConfig;
|
|
@@ -27627,6 +29875,7 @@ var ReflectorRunner = class {
|
|
|
27627
29875
|
this.getCompressionStartLevel = opts.getCompressionStartLevel;
|
|
27628
29876
|
this.mastra = opts.mastra;
|
|
27629
29877
|
this.memory = opts.memory;
|
|
29878
|
+
this.onReflectionCommitted = opts.onReflectionCommitted;
|
|
27630
29879
|
}
|
|
27631
29880
|
__registerMastra(mastra) {
|
|
27632
29881
|
this.mastra = mastra;
|
|
@@ -27760,7 +30009,7 @@ var ReflectorRunner = class {
|
|
|
27760
30009
|
finalProviderMetadata = result.providerMetadata ?? finalProviderMetadata;
|
|
27761
30010
|
parsed = parseReflectorOutput(result.text, observations, activeExtractors);
|
|
27762
30011
|
if (parsed.degenerate) {
|
|
27763
|
-
omDebug(`[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure`);
|
|
30012
|
+
omDebug(`[OM:callReflector] attempt #${attemptNumber}: degenerate repetition detected, treating as compression failure. ${describeDegenerateOutput(result.text, 2e3)}`);
|
|
27764
30013
|
reflectedTokens = originalTokens;
|
|
27765
30014
|
} else reflectedTokens = this.tokenCounter.countObservations(parsed.observations);
|
|
27766
30015
|
omDebug(`[OM:callReflector] attempt #${attemptNumber} parsed: reflectedTokens=${reflectedTokens}, targetThreshold=${targetThreshold}, compressionValid=${validateCompression(reflectedTokens, targetThreshold)}, parsedObsLen=${parsed.observations?.length}, degenerate=${parsed.degenerate ?? false}`);
|
|
@@ -27830,6 +30079,8 @@ var ReflectorRunner = class {
|
|
|
27830
30079
|
mainAgent,
|
|
27831
30080
|
memory: this.memory,
|
|
27832
30081
|
sendSignal,
|
|
30082
|
+
writer: streamContext?.writer,
|
|
30083
|
+
abortSignal,
|
|
27833
30084
|
requestContext
|
|
27834
30085
|
});
|
|
27835
30086
|
const extractedValues = hookedValues.values;
|
|
@@ -27985,7 +30236,7 @@ var ReflectorRunner = class {
|
|
|
27985
30236
|
* "activated", "no buffer present", and "suppressed by overshoot guard"
|
|
27986
30237
|
* without re-deriving that state.
|
|
27987
30238
|
*/
|
|
27988
|
-
async tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata) {
|
|
30239
|
+
async tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata, committedContext) {
|
|
27989
30240
|
const bufferKey = this.buffering.getReflectionBufferKey(lockKey);
|
|
27990
30241
|
const asyncOp = BufferingCoordinator.asyncBufferingOps.get(bufferKey);
|
|
27991
30242
|
if (asyncOp) if (activationMetadata?.triggeredBy === "ttl" || activationMetadata?.triggeredBy === "provider_change") omDebug(`[OM:reflect] tryActivateBufferedReflection: async op in progress, not blocking for ${activationMetadata.triggeredBy} trigger`);
|
|
@@ -28004,7 +30255,8 @@ var ReflectorRunner = class {
|
|
|
28004
30255
|
}
|
|
28005
30256
|
const beforeTokens = freshRecord.observationTokenCount ?? 0;
|
|
28006
30257
|
const reflectedLineCount = freshRecord.reflectedObservationLineCount ?? 0;
|
|
28007
|
-
const
|
|
30258
|
+
const allLines = (freshRecord.activeObservations ?? "").split("\n");
|
|
30259
|
+
const unreflectedLines = allLines.slice(reflectedLineCount);
|
|
28008
30260
|
const unreflectedContent = unreflectedLines.join("\n").trim();
|
|
28009
30261
|
const combinedObservations = unreflectedContent ? `${freshRecord.bufferedReflection}\n\n${unreflectedContent}` : freshRecord.bufferedReflection;
|
|
28010
30262
|
const combinedTokenCount = this.tokenCounter.countObservations(combinedObservations);
|
|
@@ -28035,6 +30287,11 @@ var ReflectorRunner = class {
|
|
|
28035
30287
|
currentRecord: freshRecord,
|
|
28036
30288
|
tokenCount: combinedTokenCount
|
|
28037
30289
|
});
|
|
30290
|
+
if (committedContext) await this.notifyReflectionCommitted({
|
|
30291
|
+
...committedContext,
|
|
30292
|
+
observations: allLines.slice(0, reflectedLineCount).join("\n").trim(),
|
|
30293
|
+
writer
|
|
30294
|
+
});
|
|
28038
30295
|
BufferingCoordinator.lastBufferedBoundary.delete(bufferKey);
|
|
28039
30296
|
const afterRecord = await this.storage.getObservationalMemory(record.threadId, record.resourceId);
|
|
28040
30297
|
const afterTokens = afterRecord?.observationTokenCount ?? 0;
|
|
@@ -28070,13 +30327,21 @@ var ReflectorRunner = class {
|
|
|
28070
30327
|
BufferingCoordinator.reflectionBufferCycleIds.delete(bufferKey);
|
|
28071
30328
|
return { status: "activated" };
|
|
28072
30329
|
}
|
|
30330
|
+
async notifyReflectionCommitted(context) {
|
|
30331
|
+
if (!this.onReflectionCommitted || !context.parentThreadId || !context.resourceId) return;
|
|
30332
|
+
try {
|
|
30333
|
+
await this.onReflectionCommitted(context);
|
|
30334
|
+
} catch (error) {
|
|
30335
|
+
omDebug(`[OM:reflect] post-commit reflection agent failed: ${error}`);
|
|
30336
|
+
}
|
|
30337
|
+
}
|
|
28073
30338
|
/**
|
|
28074
30339
|
* Check if reflection needed and trigger if so.
|
|
28075
30340
|
* Supports both synchronous reflection and async buffered reflection.
|
|
28076
30341
|
* @internal Used by observation strategies. Do not call directly.
|
|
28077
30342
|
*/
|
|
28078
30343
|
async maybeReflect(opts) {
|
|
28079
|
-
const { record, observationTokens, writer, abortSignal, mainAgent, sendSignal, messageList, currentModel, reflectionHooks, requestContext, observabilityContext, lastActivityAt, threadId: requestedThreadId } = opts;
|
|
30344
|
+
const { record, observationTokens, writer, abortSignal, mainAgent, sendSignal, sendStateSignal, messageList, currentModel, reflectionHooks, requestContext, observabilityContext, lastActivityAt, threadId: requestedThreadId } = opts;
|
|
28080
30345
|
const lockKey = this.buffering.getLockKey(record.threadId, record.resourceId);
|
|
28081
30346
|
const reflectThreshold = getMaxThreshold(this.getEffectiveReflectionTokens(record));
|
|
28082
30347
|
const priorExtractedValues = await getThreadExtractedValues(this.storage, this.reflectionConfig.extractors, requestedThreadId ?? record.threadId);
|
|
@@ -28121,7 +30386,15 @@ var ReflectorRunner = class {
|
|
|
28121
30386
|
await this.storage.setReflectingFlag(record.id, false);
|
|
28122
30387
|
}
|
|
28123
30388
|
if (this.buffering.isAsyncReflectionEnabled()) {
|
|
28124
|
-
const activationResult = await this.tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata
|
|
30389
|
+
const activationResult = await this.tryActivateBufferedReflection(record, lockKey, writer, messageList, activationMetadata, {
|
|
30390
|
+
parentThreadId: requestedThreadId ?? record.threadId ?? "",
|
|
30391
|
+
resourceId: record.resourceId ?? "",
|
|
30392
|
+
requestContext,
|
|
30393
|
+
mainAgent,
|
|
30394
|
+
sendStateSignal,
|
|
30395
|
+
abortSignal,
|
|
30396
|
+
observabilityContext
|
|
30397
|
+
});
|
|
28125
30398
|
if (activationResult.status === "activated") return;
|
|
28126
30399
|
if (activationResult.status === "suppressed") {
|
|
28127
30400
|
omDebug(`[OM:reflect] skipping sync fallback / re-buffer after suppressed early ${activationMetadata.triggeredBy} activation (reason=${activationResult.reason})`);
|
|
@@ -28192,6 +30465,17 @@ var ReflectorRunner = class {
|
|
|
28192
30465
|
reflection: reflectResult.observations,
|
|
28193
30466
|
tokenCount: reflectionTokenCount
|
|
28194
30467
|
});
|
|
30468
|
+
await this.notifyReflectionCommitted({
|
|
30469
|
+
parentThreadId: requestedThreadId ?? record.threadId ?? "",
|
|
30470
|
+
resourceId: record.resourceId ?? "",
|
|
30471
|
+
observations: record.activeObservations ?? "",
|
|
30472
|
+
requestContext,
|
|
30473
|
+
mainAgent,
|
|
30474
|
+
sendStateSignal,
|
|
30475
|
+
writer,
|
|
30476
|
+
abortSignal,
|
|
30477
|
+
observabilityContext
|
|
30478
|
+
});
|
|
28195
30479
|
if (writer && streamContext) {
|
|
28196
30480
|
const endMarker = createObservationEndMarker({
|
|
28197
30481
|
cycleId: streamContext.cycleId,
|
|
@@ -28717,6 +31001,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
28717
31001
|
hasher = e();
|
|
28718
31002
|
mastra;
|
|
28719
31003
|
memory;
|
|
31004
|
+
curationCadence;
|
|
28720
31005
|
/**
|
|
28721
31006
|
* Track message IDs observed during this instance's lifetime.
|
|
28722
31007
|
* Prevents re-observing messages when per-thread lastObservedAt cursors
|
|
@@ -28814,6 +31099,7 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
28814
31099
|
this.hooks = config.hooks;
|
|
28815
31100
|
this.mastra = config.mastra;
|
|
28816
31101
|
this.memory = config.memory;
|
|
31102
|
+
this.curationCadence = config.curationCadence;
|
|
28817
31103
|
const resolveModel = (model, defaultModel) => model === "default" ? defaultModel : model;
|
|
28818
31104
|
const observationModel = resolveModel(config.model, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? resolveModel(config.observation?.model, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? resolveModel(config.reflection?.model, OBSERVATIONAL_MEMORY_DEFAULTS.observation.model) ?? OBSERVATIONAL_MEMORY_DEFAULTS.observation.model;
|
|
28819
31105
|
const reflectionModel = resolveModel(config.model, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? resolveModel(config.reflection?.model, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? resolveModel(config.observation?.model, OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model) ?? OBSERVATIONAL_MEMORY_DEFAULTS.reflection.model;
|
|
@@ -28909,7 +31195,8 @@ var ObservationalMemory = class ObservationalMemory {
|
|
|
28909
31195
|
getCompressionStartLevel: (rc) => this.getCompressionStartLevel(rc),
|
|
28910
31196
|
resolveModel: (inputTokens) => this.resolveReflectionModel(inputTokens),
|
|
28911
31197
|
mastra: config.mastra,
|
|
28912
|
-
memory: this.memory
|
|
31198
|
+
memory: this.memory,
|
|
31199
|
+
onReflectionCommitted: config.onReflectionCommitted
|
|
28913
31200
|
});
|
|
28914
31201
|
this.validateBufferConfig();
|
|
28915
31202
|
omDebug(`[OM:init] new ObservationalMemory instance created — scope=${this.scope}, messageTokens=${JSON.stringify(this.observationConfig.messageTokens)}, obsAsyncEnabled=${this.buffering.isAsyncObservationEnabled()}, bufferTokens=${this.observationConfig.bufferTokens}, bufferActivation=${this.observationConfig.bufferActivation}, blockAfter=${this.observationConfig.blockAfter}, reflectionTokens=${this.reflectionConfig.observationTokens}, refAsyncEnabled=${this.buffering.isAsyncReflectionEnabled()}, refAsyncActivation=${this.reflectionConfig.bufferActivation}, refBlockAfter=${this.reflectionConfig.blockAfter}`);
|
|
@@ -30383,6 +32670,7 @@ ${formattedMessages}
|
|
|
30383
32670
|
writer,
|
|
30384
32671
|
agent: opts.agent,
|
|
30385
32672
|
sendSignal: opts.sendSignal,
|
|
32673
|
+
sendStateSignal: opts.sendStateSignal,
|
|
30386
32674
|
requestContext,
|
|
30387
32675
|
currentModel: opts.currentModel,
|
|
30388
32676
|
observabilityContext
|
|
@@ -30727,6 +33015,8 @@ ${formattedMessages}
|
|
|
30727
33015
|
messageList: opts.messageList,
|
|
30728
33016
|
reflectionHooks,
|
|
30729
33017
|
agent: opts.agent,
|
|
33018
|
+
sendSignal: opts.sendSignal,
|
|
33019
|
+
sendStateSignal: opts.sendStateSignal,
|
|
30730
33020
|
requestContext,
|
|
30731
33021
|
writer: opts.writer,
|
|
30732
33022
|
observabilityContext: opts.observabilityContext
|
|
@@ -30747,6 +33037,9 @@ ${formattedMessages}
|
|
|
30747
33037
|
});
|
|
30748
33038
|
const record = await this.getOrCreateRecord(threadId, resourceId);
|
|
30749
33039
|
const reflected = record.generationCount > generationBefore && generationBefore >= 0;
|
|
33040
|
+
if (observed) this.maybeTriggerCadenceCuration(threadId, resourceId, record, requestContext).catch((error) => {
|
|
33041
|
+
omDebug(`[OM:observe] cadence curation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
33042
|
+
});
|
|
30750
33043
|
return {
|
|
30751
33044
|
observed,
|
|
30752
33045
|
reflected,
|
|
@@ -30754,6 +33047,31 @@ ${formattedMessages}
|
|
|
30754
33047
|
};
|
|
30755
33048
|
}
|
|
30756
33049
|
/**
|
|
33050
|
+
* Count committed observation runs on the sync observe path and run the curator every
|
|
33051
|
+
* `curationCadence` runs. The counter is persisted at `record.config.subconscious.observationRuns`
|
|
33052
|
+
* (the OM record's config jsonb, deep-merged; threshold resolution only reads `_overrides`, so the
|
|
33053
|
+
* sibling key is inert). Concurrent commits can miscount — the curator run is advisory, and the
|
|
33054
|
+
* curation cursor is the real serializer. The async-buffer lane bypasses observe(); deployments
|
|
33055
|
+
* that gate on this cadence (factory's resource scope) disable async buffering.
|
|
33056
|
+
*/
|
|
33057
|
+
async maybeTriggerCadenceCuration(threadId, resourceId, record, requestContext) {
|
|
33058
|
+
const cadence = this.curationCadence;
|
|
33059
|
+
const memory = this.memory;
|
|
33060
|
+
if (!cadence || cadence < 1 || !memory) return;
|
|
33061
|
+
const runs = ((record.config ?? {}).subconscious?.observationRuns ?? 0) + 1;
|
|
33062
|
+
const fire = runs >= cadence;
|
|
33063
|
+
await this.storage.updateObservationalMemoryConfig({
|
|
33064
|
+
id: record.id,
|
|
33065
|
+
config: { subconscious: { observationRuns: fire ? 0 : runs } }
|
|
33066
|
+
});
|
|
33067
|
+
if (!fire) return;
|
|
33068
|
+
omDebug(`[OM:observe] cadence curation outcome=${(await memory.runCuration({
|
|
33069
|
+
threadId,
|
|
33070
|
+
resourceId: resourceId ?? threadId,
|
|
33071
|
+
requestContext
|
|
33072
|
+
})).outcome} thread=${threadId}`);
|
|
33073
|
+
}
|
|
33074
|
+
/**
|
|
30757
33075
|
* Manually trigger reflection with optional guidance prompt.
|
|
30758
33076
|
*
|
|
30759
33077
|
* @example
|
|
@@ -30771,6 +33089,18 @@ ${formattedMessages}
|
|
|
30771
33089
|
record,
|
|
30772
33090
|
usage: void 0
|
|
30773
33091
|
};
|
|
33092
|
+
if (record.isReflecting) {
|
|
33093
|
+
if (isOpActiveInProcess(record.id, "reflecting")) {
|
|
33094
|
+
omDebug(`[OM:reflect] isReflecting=true and active in this process, skipping`);
|
|
33095
|
+
return {
|
|
33096
|
+
reflected: false,
|
|
33097
|
+
record,
|
|
33098
|
+
usage: void 0
|
|
33099
|
+
};
|
|
33100
|
+
}
|
|
33101
|
+
omDebug(`[OM:reflect] isReflecting=true but NOT active in this process — stale flag from dead process, clearing`);
|
|
33102
|
+
await this.storage.setReflectingFlag(record.id, false);
|
|
33103
|
+
}
|
|
30774
33104
|
await this.storage.setReflectingFlag(record.id, true);
|
|
30775
33105
|
registerOp(record.id, "reflecting");
|
|
30776
33106
|
const hooks = this.composeHooks(void 0, {
|
|
@@ -30956,6 +33286,8 @@ ${formattedMessages}
|
|
|
30956
33286
|
resourceId: opts.resourceId,
|
|
30957
33287
|
messageList: opts.messageList,
|
|
30958
33288
|
agent: opts.agent,
|
|
33289
|
+
sendSignal: opts.sendSignal,
|
|
33290
|
+
sendStateSignal: opts.sendStateSignal,
|
|
30959
33291
|
observabilityContext: opts.observabilityContext,
|
|
30960
33292
|
hooks: opts.hooks
|
|
30961
33293
|
});
|
|
@@ -31178,6 +33510,7 @@ var ObservationalMemoryProcessor = class {
|
|
|
31178
33510
|
});
|
|
31179
33511
|
this.turn.writer = writer;
|
|
31180
33512
|
this.turn.sendSignal = args.sendSignal;
|
|
33513
|
+
this.turn.sendStateSignal = args.sendStateSignal;
|
|
31181
33514
|
this.turn.agent = args.agent;
|
|
31182
33515
|
this.turn.requestContext = requestContext;
|
|
31183
33516
|
await this.turn.start(this.memory);
|
|
@@ -31318,6 +33651,7 @@ function getObservationsAsOf(activeObservations, asOf) {
|
|
|
31318
33651
|
}
|
|
31319
33652
|
var observational_memory_exports = /* @__PURE__ */ __exportAll({
|
|
31320
33653
|
Extractor: () => Extractor,
|
|
33654
|
+
KnowledgeSemanticIndexCoordinator: () => KnowledgeSemanticIndexCoordinator,
|
|
31321
33655
|
ModelByInputTokens: () => ModelByInputTokens,
|
|
31322
33656
|
OBSERVATIONAL_MEMORY_DEFAULTS: () => OBSERVATIONAL_MEMORY_DEFAULTS,
|
|
31323
33657
|
OBSERVATION_CONTEXT_INSTRUCTIONS: () => OBSERVATION_CONTEXT_INSTRUCTIONS,
|
|
@@ -31326,10 +33660,16 @@ var observational_memory_exports = /* @__PURE__ */ __exportAll({
|
|
|
31326
33660
|
OBSERVER_SYSTEM_PROMPT: () => OBSERVER_SYSTEM_PROMPT,
|
|
31327
33661
|
ObservationalMemory: () => ObservationalMemory,
|
|
31328
33662
|
ObservationalMemoryProcessor: () => ObservationalMemoryProcessor,
|
|
33663
|
+
SUBCONSCIOUS_ACTIVITY_STATE_ID: () => SUBCONSCIOUS_ACTIVITY_STATE_ID,
|
|
33664
|
+
StaleKnowledgeSemanticIndexError: () => StaleKnowledgeSemanticIndexError,
|
|
33665
|
+
Subconscious: () => Subconscious,
|
|
33666
|
+
SubconsciousCaptureExtractor: () => SubconsciousCaptureExtractor,
|
|
33667
|
+
SubconsciousRemindExtractor: () => SubconsciousRemindExtractor,
|
|
31329
33668
|
TokenCounter: () => TokenCounter,
|
|
31330
33669
|
WorkingMemoryExtractor: () => WorkingMemoryExtractor,
|
|
31331
33670
|
buildObserverPrompt: () => buildObserverPrompt,
|
|
31332
33671
|
buildObserverSystemPrompt: () => buildObserverSystemPrompt,
|
|
33672
|
+
buildSubconsciousActivitySnapshot: () => buildSubconsciousActivitySnapshot,
|
|
31333
33673
|
combineObservationGroupRanges: () => combineObservationGroupRanges,
|
|
31334
33674
|
deriveObservationGroupProvenance: () => deriveObservationGroupProvenance,
|
|
31335
33675
|
extractCurrentTask: () => extractCurrentTask,
|
|
@@ -31341,10 +33681,13 @@ var observational_memory_exports = /* @__PURE__ */ __exportAll({
|
|
|
31341
33681
|
parseAnchorId: () => parseAnchorId,
|
|
31342
33682
|
parseObservationGroups: () => parseObservationGroups,
|
|
31343
33683
|
parseObserverOutput: () => parseObserverOutput,
|
|
33684
|
+
publishSubconsciousActivity: () => publishSubconsciousActivity,
|
|
31344
33685
|
reconcileObservationGroupsFromReflection: () => reconcileObservationGroupsFromReflection,
|
|
31345
33686
|
renderObservationGroupsForReflection: () => renderObservationGroupsForReflection,
|
|
33687
|
+
renderSubconsciousActivity: () => renderSubconsciousActivity,
|
|
31346
33688
|
stripEphemeralAnchorIds: () => stripEphemeralAnchorIds,
|
|
31347
33689
|
stripObservationGroups: () => stripObservationGroups,
|
|
33690
|
+
subconsciousCaptureSchema: () => subconsciousCaptureSchema,
|
|
31348
33691
|
summarizeConversation: () => summarizeConversation,
|
|
31349
33692
|
wrapInObservationGroup: () => wrapInObservationGroup
|
|
31350
33693
|
});
|
|
@@ -31568,10 +33911,11 @@ const DEFAULT_EMBEDDING_CACHE_MAX_SIZE = 1e3;
|
|
|
31568
33911
|
* Concrete implementation of MastraMemory that adds support for thread configuration
|
|
31569
33912
|
* and message injection.
|
|
31570
33913
|
*/
|
|
31571
|
-
var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
33914
|
+
var Memory = class Memory extends _mastra_core_memory.MastraMemory {
|
|
31572
33915
|
_omEngine;
|
|
31573
33916
|
_omEngineInstance;
|
|
31574
33917
|
_mastraInstance;
|
|
33918
|
+
_knowledgeSemanticIndex;
|
|
31575
33919
|
/**
|
|
31576
33920
|
* Every vector cleanup that deleteThread or deleteMessages started in the background.
|
|
31577
33921
|
* Callers do not wait for the cleanup, so this handle is the only join point.
|
|
@@ -31619,7 +33963,60 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
|
31619
33963
|
else this._omEngine?.then((engine) => engine?.__registerMastra(mastra));
|
|
31620
33964
|
}
|
|
31621
33965
|
getMergedThreadConfig(config) {
|
|
31622
|
-
|
|
33966
|
+
const merged = super.getMergedThreadConfig(config);
|
|
33967
|
+
return this.applyManagedWorkingMemoryDefaults(this.applySubconsciousDefaults(merged));
|
|
33968
|
+
}
|
|
33969
|
+
applySubconsciousDefaults(config) {
|
|
33970
|
+
const omConfig = normalizeObservationalMemoryConfig(config.observationalMemory);
|
|
33971
|
+
if (!omConfig?.experimental_subconscious) return config;
|
|
33972
|
+
if (!(omConfig.experimental_subconscious instanceof Subconscious)) throw new Error("observationalMemory.experimental_subconscious must be a Subconscious instance.");
|
|
33973
|
+
const observation = omConfig.observation ?? {};
|
|
33974
|
+
const extract = observation.extract ?? [];
|
|
33975
|
+
const existingSlugs = new Set(extract.map((extractor) => extractor.slug));
|
|
33976
|
+
const subconsciousExtractors = omConfig.experimental_subconscious.createObservationExtractors(observation.model ?? omConfig.model).filter((extractor) => !existingSlugs.has(extractor.slug));
|
|
33977
|
+
return {
|
|
33978
|
+
...config,
|
|
33979
|
+
observationalMemory: {
|
|
33980
|
+
...omConfig,
|
|
33981
|
+
observation: {
|
|
33982
|
+
...observation,
|
|
33983
|
+
extract: [...extract, ...subconsciousExtractors]
|
|
33984
|
+
}
|
|
33985
|
+
}
|
|
33986
|
+
};
|
|
33987
|
+
}
|
|
33988
|
+
/** Threads with a curation currently in flight in this process; guards same-process double-fire only. */
|
|
33989
|
+
_curationsInFlight = /* @__PURE__ */ new Set();
|
|
33990
|
+
/**
|
|
33991
|
+
* Run the subconscious curator directly over the pending fact worklist, without a reflection.
|
|
33992
|
+
* Cross-process serialization is the curation cursor's job; a lost race wastes one advisory run.
|
|
33993
|
+
*
|
|
33994
|
+
* Outcomes: `ran` (curator executed), `no-op` (empty worklist and no prompt, or no curate agent
|
|
33995
|
+
* configured), `skipped` (a curation for this thread is already in flight in this process), and
|
|
33996
|
+
* `no-model` (no per-agent, observational memory, or main-agent model could be resolved).
|
|
33997
|
+
*/
|
|
33998
|
+
async runCuration(options) {
|
|
33999
|
+
const omConfig = normalizeObservationalMemoryConfig(this.threadConfig.observationalMemory);
|
|
34000
|
+
const subconscious = omConfig?.experimental_subconscious;
|
|
34001
|
+
if (!omConfig || !(subconscious instanceof Subconscious)) return { outcome: "no-op" };
|
|
34002
|
+
if (this._curationsInFlight.has(options.threadId)) return { outcome: "skipped" };
|
|
34003
|
+
this._curationsInFlight.add(options.threadId);
|
|
34004
|
+
try {
|
|
34005
|
+
return { outcome: await createCuratorHandler(this, subconscious.resolved, new Memory({
|
|
34006
|
+
storage: this.storage,
|
|
34007
|
+
options: { observationalMemory: false }
|
|
34008
|
+
}), { omModel: omConfig.observation?.model ?? omConfig.model })({
|
|
34009
|
+
parentThreadId: options.threadId,
|
|
34010
|
+
resourceId: options.resourceId,
|
|
34011
|
+
observations: options.prompt ?? "",
|
|
34012
|
+
requestContext: options.requestContext
|
|
34013
|
+
}) === "ran" ? "ran" : "no-op" };
|
|
34014
|
+
} catch (error) {
|
|
34015
|
+
if (error instanceof Error && error.message.includes("requires the main agent to resolve its model")) return { outcome: "no-model" };
|
|
34016
|
+
throw error;
|
|
34017
|
+
} finally {
|
|
34018
|
+
this._curationsInFlight.delete(options.threadId);
|
|
34019
|
+
}
|
|
31623
34020
|
}
|
|
31624
34021
|
applyManagedWorkingMemoryDefaults(config) {
|
|
31625
34022
|
const omConfig = normalizeObservationalMemoryConfig(config.observationalMemory);
|
|
@@ -31663,6 +34060,28 @@ var Memory = class extends _mastra_core_memory.MastraMemory {
|
|
|
31663
34060
|
if (!this.vector) throw new Error("`retrieval: { vector: true }` requires a vector store. Pass a `vector` option to your Memory instance.");
|
|
31664
34061
|
if (!this.embedder) throw new Error("`retrieval: { vector: true }` requires an embedder. Pass an `embedder` option to your Memory instance.");
|
|
31665
34062
|
}
|
|
34063
|
+
if (omConfig?.experimental_subconscious) {
|
|
34064
|
+
if (!this.vector) throw new Error("Subconscious semantic knowledge requires a vector store. Pass a `vector` option to Memory.");
|
|
34065
|
+
if (!this.embedder) throw new Error("Subconscious semantic knowledge requires an embedder. Pass an `embedder` option to Memory.");
|
|
34066
|
+
}
|
|
34067
|
+
}
|
|
34068
|
+
async getKnowledgeStore() {
|
|
34069
|
+
const store = await this.storage.getStore("knowledge");
|
|
34070
|
+
if (!store) throw new Error(`Knowledge storage domain is not available on ${this.storage.constructor.name}`);
|
|
34071
|
+
return store;
|
|
34072
|
+
}
|
|
34073
|
+
async getKnowledgeSemanticIndex() {
|
|
34074
|
+
if (!this.vector || !this.embedder) throw new Error("Subconscious semantic knowledge requires both a vector store and an embedder.");
|
|
34075
|
+
this._knowledgeSemanticIndex ??= this.getKnowledgeStore().then((knowledge) => new KnowledgeSemanticIndexCoordinator({
|
|
34076
|
+
knowledge,
|
|
34077
|
+
vector: this.vector,
|
|
34078
|
+
embedder: this.embedder,
|
|
34079
|
+
embedderOptions: this.embedderOptions
|
|
34080
|
+
}));
|
|
34081
|
+
return this._knowledgeSemanticIndex;
|
|
34082
|
+
}
|
|
34083
|
+
async drainKnowledgeSemanticIndex(scope) {
|
|
34084
|
+
return (await this.getKnowledgeSemanticIndex()).drain(scope);
|
|
31666
34085
|
}
|
|
31667
34086
|
/**
|
|
31668
34087
|
* Gets the memory storage domain, throwing if not available.
|
|
@@ -32431,6 +34850,7 @@ ${workingMemory}`;
|
|
|
32431
34850
|
if (!_mastra_core_features.coreFeatures.has("observationalMemory")) throw new Error("Observational memory is enabled but the installed version of @mastra/core does not support it. Please upgrade @mastra/core to a version that includes observational memory support.");
|
|
32432
34851
|
if (omConfig.observation?.bufferTokens !== false && !_mastra_core_features.coreFeatures.has("asyncBuffering")) throw new Error("Observational memory async buffering is enabled by default but the installed version of @mastra/core does not support it. Either upgrade @mastra/core, @mastra/memory, and your storage adapter (@mastra/libsql, @mastra/pg, @mastra/mongodb, or @mastra/convex) to the latest version, or explicitly disable async buffering by setting `observation: { bufferTokens: false }` in your observationalMemory config.");
|
|
32433
34852
|
if (!_mastra_core_features.coreFeatures.has("request-response-id-rotation")) throw new Error("Observational memory requires @mastra/core support for request-response-id-rotation. Please bump @mastra/core to a newer version.");
|
|
34853
|
+
if (omConfig.experimental_subconscious) await this.getKnowledgeStore();
|
|
32434
34854
|
const { ObservationalMemory: OMClass } = await Promise.resolve().then(() => observational_memory_exports);
|
|
32435
34855
|
const onIndexObservations = this.hasRetrievalSearch(omConfig.retrieval) ? async (observation) => {
|
|
32436
34856
|
await this.indexObservation(observation);
|
|
@@ -32444,9 +34864,21 @@ ${workingMemory}`;
|
|
|
32444
34864
|
activateOnProviderChange: omConfig.activateOnProviderChange,
|
|
32445
34865
|
shareTokenBudget: omConfig.shareTokenBudget,
|
|
32446
34866
|
model: omConfig.model,
|
|
34867
|
+
curationCadence: omConfig.experimental_subconscious instanceof Subconscious ? omConfig.experimental_subconscious.resolved.curationCadence : void 0,
|
|
32447
34868
|
mastra: this._mastraInstance,
|
|
32448
34869
|
onIndexObservations,
|
|
32449
34870
|
hooks: omConfig.hooks,
|
|
34871
|
+
onReflectionCommitted: omConfig.experimental_subconscious instanceof Subconscious ? (() => {
|
|
34872
|
+
const resolved = omConfig.experimental_subconscious.resolved;
|
|
34873
|
+
const omModel = omConfig.observation?.model ?? omConfig.model;
|
|
34874
|
+
return composeReflectionAgentHandlers([createCuratorHandler(this, resolved, new Memory({
|
|
34875
|
+
storage: this.storage,
|
|
34876
|
+
options: { observationalMemory: false }
|
|
34877
|
+
}), { omModel }), createLearnerHandler(this, resolved, new Memory({
|
|
34878
|
+
storage: this.storage,
|
|
34879
|
+
options: { observationalMemory: false }
|
|
34880
|
+
}), { omModel })]);
|
|
34881
|
+
})() : void 0,
|
|
32450
34882
|
observation: omConfig.observation ? {
|
|
32451
34883
|
model: omConfig.observation.model,
|
|
32452
34884
|
messageTokens: omConfig.observation.messageTokens,
|
|
@@ -32836,6 +35268,7 @@ Notes:
|
|
|
32836
35268
|
retrievalScope: typeof omConfig.retrieval === "object" ? omConfig.retrieval.scope ?? "resource" : "resource",
|
|
32837
35269
|
searchEnabled: this.hasRetrievalSearch(omConfig.retrieval)
|
|
32838
35270
|
});
|
|
35271
|
+
if (omConfig?.experimental_subconscious instanceof Subconscious && omConfig.experimental_subconscious.resolved.tools) Object.assign(tools, createKnowledgeTools(this));
|
|
32839
35272
|
return tools;
|
|
32840
35273
|
}
|
|
32841
35274
|
/**
|
|
@@ -33316,6 +35749,8 @@ Notes:
|
|
|
33316
35749
|
if (om) processors.push(om);
|
|
33317
35750
|
const wm = await this.createWorkingMemoryStateProcessor(configuredProcessors, context);
|
|
33318
35751
|
if (wm) processors.push(wm);
|
|
35752
|
+
const pins = await this.createPinnedStateProcessor(configuredProcessors, context);
|
|
35753
|
+
if (pins) processors.push(pins);
|
|
33319
35754
|
return processors;
|
|
33320
35755
|
}
|
|
33321
35756
|
/**
|
|
@@ -33363,6 +35798,21 @@ Notes:
|
|
|
33363
35798
|
if (configuredProcessors.some((p) => !("workflow" in p) && p.id === WORKING_MEMORY_STATE_PROCESSOR_ID)) return null;
|
|
33364
35799
|
return new WorkingMemoryStateProcessor(this, runtimeMemory?.memoryConfig);
|
|
33365
35800
|
}
|
|
35801
|
+
/**
|
|
35802
|
+
* Creates a PinnedStateProcessor when Subconscious pins are enabled on the
|
|
35803
|
+
* merged thread config. The gate is the validated `resolved.pins` on the
|
|
35804
|
+
* Subconscious instance, never the raw user object. Returns null when pins
|
|
35805
|
+
* are off or the processor is already present in the user's configured
|
|
35806
|
+
* processors.
|
|
35807
|
+
*/
|
|
35808
|
+
async createPinnedStateProcessor(configuredProcessors = [], context) {
|
|
35809
|
+
const runtimeMemory = context?.get("MastraMemory");
|
|
35810
|
+
const subconscious = normalizeObservationalMemoryConfig(this.getMergedThreadConfig(runtimeMemory?.memoryConfig).observationalMemory)?.experimental_subconscious;
|
|
35811
|
+
if (!(subconscious instanceof Subconscious) || subconscious.resolved.pins === false) return null;
|
|
35812
|
+
const { PinnedStateProcessor, SUBCONSCIOUS_PINS_STATE_ID } = await Promise.resolve().then(() => subconscious_exports);
|
|
35813
|
+
if (configuredProcessors.some((p) => !("workflow" in p) && p.id === SUBCONSCIOUS_PINS_STATE_ID)) return null;
|
|
35814
|
+
return new PinnedStateProcessor({ getKnowledgeStore: () => this.storage.getStore("knowledge") });
|
|
35815
|
+
}
|
|
33366
35816
|
};
|
|
33367
35817
|
//#endregion
|
|
33368
35818
|
//#region ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/ignore/7.0.5/d6411cd18dd20fbb425503c2ba0ac12fc6b5c7b2b2481cbdc797c212eb8be050/node_modules/ignore/index.js
|
|
@@ -34155,23 +36605,23 @@ const createModelInstance = async (provider, modelId, version = "v2") => {
|
|
|
34155
36605
|
try {
|
|
34156
36606
|
const providerFn = version === `v1` ? { v1: {
|
|
34157
36607
|
openai: async () => {
|
|
34158
|
-
const { openai } = await Promise.resolve().then(() => require("./dist-
|
|
36608
|
+
const { openai } = await Promise.resolve().then(() => require("./dist-2zVeGGHi.cjs"));
|
|
34159
36609
|
return openai(modelId);
|
|
34160
36610
|
},
|
|
34161
36611
|
anthropic: async () => {
|
|
34162
|
-
const { anthropic } = await Promise.resolve().then(() => require("./dist-
|
|
36612
|
+
const { anthropic } = await Promise.resolve().then(() => require("./dist-BfVTO0pC.cjs"));
|
|
34163
36613
|
return anthropic(modelId);
|
|
34164
36614
|
},
|
|
34165
36615
|
groq: async () => {
|
|
34166
|
-
const { groq } = await Promise.resolve().then(() => require("./dist-
|
|
36616
|
+
const { groq } = await Promise.resolve().then(() => require("./dist-D4NzuG3G.cjs"));
|
|
34167
36617
|
return groq(modelId);
|
|
34168
36618
|
},
|
|
34169
36619
|
xai: async () => {
|
|
34170
|
-
const { xai } = await Promise.resolve().then(() => require("./dist-
|
|
36620
|
+
const { xai } = await Promise.resolve().then(() => require("./dist-Be7Caz3Z.cjs"));
|
|
34171
36621
|
return xai(modelId);
|
|
34172
36622
|
},
|
|
34173
36623
|
google: async () => {
|
|
34174
|
-
const { google } = await Promise.resolve().then(() => require("./dist-
|
|
36624
|
+
const { google } = await Promise.resolve().then(() => require("./dist-8-Z5v77M.cjs"));
|
|
34175
36625
|
return google(modelId);
|
|
34176
36626
|
}
|
|
34177
36627
|
} }[version][provider] : () => new _mastra_core_llm.ModelRouterLanguageModel(`${provider}/${modelId}`);
|
|
@@ -43749,4 +46199,4 @@ const agentBuilderWorkflows = {
|
|
|
43749
46199
|
//#endregion
|
|
43750
46200
|
exports.agentBuilderWorkflows = agentBuilderWorkflows;
|
|
43751
46201
|
|
|
43752
|
-
//# sourceMappingURL=dist-
|
|
46202
|
+
//# sourceMappingURL=dist-DERatX43.cjs.map
|