amrita-go 0.1.0a1__tar.gz
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.
- amrita_go-0.1.0a1/.gitignore +24 -0
- amrita_go-0.1.0a1/PKG-INFO +16 -0
- amrita_go-0.1.0a1/app/__init__.py +10 -0
- amrita_go-0.1.0a1/app/__main__.py +28 -0
- amrita_go-0.1.0a1/app/agents/__init__.py +390 -0
- amrita_go-0.1.0a1/app/capabilities/__init__.py +498 -0
- amrita_go-0.1.0a1/app/capabilities/mcp_runtime.py +168 -0
- amrita_go-0.1.0a1/app/capabilities/permissions.py +197 -0
- amrita_go-0.1.0a1/app/capabilities/skills.py +266 -0
- amrita_go-0.1.0a1/app/core/__init__.py +1 -0
- amrita_go-0.1.0a1/app/core/config.py +160 -0
- amrita_go-0.1.0a1/app/core/core_config.py +490 -0
- amrita_go-0.1.0a1/app/core/crypto.py +323 -0
- amrita_go-0.1.0a1/app/core/logging_setup.py +42 -0
- amrita_go-0.1.0a1/app/core/paths_translate.py +74 -0
- amrita_go-0.1.0a1/app/core/providers.py +509 -0
- amrita_go-0.1.0a1/app/core/settings.py +227 -0
- amrita_go-0.1.0a1/app/core/storage.py +74 -0
- amrita_go-0.1.0a1/app/core/workspaces.py +117 -0
- amrita_go-0.1.0a1/app/main.py +1540 -0
- amrita_go-0.1.0a1/app/plugins/__init__.py +669 -0
- amrita_go-0.1.0a1/app/plugins/builtin.py +160 -0
- amrita_go-0.1.0a1/app/plugins/config.py +342 -0
- amrita_go-0.1.0a1/app/plugins/files.py +361 -0
- amrita_go-0.1.0a1/app/plugins/shell.py +566 -0
- amrita_go-0.1.0a1/app/plugins/todos.py +293 -0
- amrita_go-0.1.0a1/app/runtime/__init__.py +1 -0
- amrita_go-0.1.0a1/app/runtime/agent_runtime.py +572 -0
- amrita_go-0.1.0a1/app/runtime/attachments.py +216 -0
- amrita_go-0.1.0a1/app/runtime/audit.py +155 -0
- amrita_go-0.1.0a1/app/runtime/billing.py +203 -0
- amrita_go-0.1.0a1/app/runtime/fallback_watch.py +58 -0
- amrita_go-0.1.0a1/app/runtime/limit_gate.py +114 -0
- amrita_go-0.1.0a1/app/runtime/session_memory.py +241 -0
- amrita_go-0.1.0a1/app/runtime/sessions.py +321 -0
- amrita_go-0.1.0a1/app/runtime/stream_hub.py +135 -0
- amrita_go-0.1.0a1/app/runtime/tool_limit.py +175 -0
- amrita_go-0.1.0a1/app/runtime/workflows.py +144 -0
- amrita_go-0.1.0a1/app/tools/__init__.py +1 -0
- amrita_go-0.1.0a1/app/tools/shell.py +727 -0
- amrita_go-0.1.0a1/frontend/dist/assets/abnfDiagram-VCTEODGH-ydbcv0mr.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/abnfDiagram-VCTEODGH-ydbcv0mr.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/architecture-7GRP2DOG-0mqnenvx.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/architecture-7GRP2DOG-0mqnenvx.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/architectureDiagram-5GKGNRK7-y8bm5wnd.js +39 -0
- amrita_go-0.1.0a1/frontend/dist/assets/architectureDiagram-5GKGNRK7-y8bm5wnd.js.map +13 -0
- amrita_go-0.1.0a1/frontend/dist/assets/blockDiagram-I7D4REHJ-3gb3fjqx.js +132 -0
- amrita_go-0.1.0a1/frontend/dist/assets/blockDiagram-I7D4REHJ-3gb3fjqx.js.map +12 -0
- amrita_go-0.1.0a1/frontend/dist/assets/brand/amrita-black.png +0 -0
- amrita_go-0.1.0a1/frontend/dist/assets/brand/amrita-white.png +0 -0
- amrita_go-0.1.0a1/frontend/dist/assets/c4Diagram-7LVT6UL2-fq0ver1j.js +41 -0
- amrita_go-0.1.0a1/frontend/dist/assets/c4Diagram-7LVT6UL2-fq0ver1j.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/classDiagram-ZZMXUADV-5580h9dd.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/classDiagram-ZZMXUADV-5580h9dd.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/classDiagram-v2-VYDZK3BY-758y231q.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/classDiagram-v2-VYDZK3BY-758y231q.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cose-bilkent-JH36ORCC-yc956xn3.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cose-bilkent-JH36ORCC-yc956xn3.js.map +13 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cynefin-OW5HDTMX-nwkwfrqw.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cynefin-OW5HDTMX-nwkwfrqw.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cynefinDiagram-5FMLGOSQ-q6m7dcn0.js +65 -0
- amrita_go-0.1.0a1/frontend/dist/assets/cynefinDiagram-5FMLGOSQ-q6m7dcn0.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/dagre-GXQ25YYZ-kct1jgtx.js +7 -0
- amrita_go-0.1.0a1/frontend/dist/assets/dagre-GXQ25YYZ-kct1jgtx.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-S7CK7UJ4-0gwke9sa.js +33 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-S7CK7UJ4-0gwke9sa.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-UQ7AKVKN-baz3wq1b.js +44 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-UQ7AKVKN-baz3wq1b.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-VSXAHHWV-qvz1h028.js +6 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-VSXAHHWV-qvz1h028.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-VX7I27RA-chmy8jcc.js +27 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-VX7I27RA-chmy8jcc.js.map +31 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-Z3DM3KII-rbkxsmzm.js +27 -0
- amrita_go-0.1.0a1/frontend/dist/assets/diagram-Z3DM3KII-rbkxsmzm.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ebnfDiagram-PWID7BFC-ssxpmwt9.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ebnfDiagram-PWID7BFC-ssxpmwt9.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/erDiagram-RLTQ6QDP-h5529f8k.js +102 -0
- amrita_go-0.1.0a1/frontend/dist/assets/erDiagram-RLTQ6QDP-h5529f8k.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/eventmodeling-NTZA5JFV-rby9j3a8.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/eventmodeling-NTZA5JFV-rby9j3a8.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/flowDiagram-HODETNUW-5j9t1hne.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/flowDiagram-HODETNUW-5j9t1hne.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ganttDiagram-EL5Y4UJY-t3vqnjsr.js +295 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ganttDiagram-EL5Y4UJY-t3vqnjsr.js.map +36 -0
- amrita_go-0.1.0a1/frontend/dist/assets/gitGraph-4MIJSDKK-ctq6z2sh.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/gitGraph-4MIJSDKK-ctq6z2sh.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/gitGraphDiagram-WWUBYQGX-k8jcdexn.js +109 -0
- amrita_go-0.1.0a1/frontend/dist/assets/gitGraphDiagram-WWUBYQGX-k8jcdexn.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-0qp5qe86.js +400 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-0qp5qe86.js.map +431 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-1pyg88ra.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-1pyg88ra.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-2mhshrm8.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-2mhshrm8.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-5a43s6hf.js +235 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-5a43s6hf.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-5axqjc3f.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-5axqjc3f.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-6zt17tvy.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-6zt17tvy.js.map +21 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-7sdrq6ys.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-7sdrq6ys.js.map +11 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-9p2wgm38.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-9p2wgm38.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-amaxjr2y.js +335 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-amaxjr2y.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-ezdsv18s.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-ezdsv18s.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-gq4q62gw.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-gq4q62gw.js.map +29 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-hfavbw0q.js +182 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-hfavbw0q.js.map +26 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-jre8gp00.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-jre8gp00.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-k5gd5h9y.js +172 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-k5gd5h9y.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-mvwv71mr.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-mvwv71mr.js.map +126 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-pr34nm6z.js +304 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-pr34nm6z.js.map +360 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-ptebcmdw.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-ptebcmdw.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-pzvqcg4a.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-pzvqcg4a.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-qe8n5502.js +92 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-qe8n5502.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-rvvxwq2w.js +210 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-rvvxwq2w.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-vt3cved4.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-vt3cved4.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-xad3aj0n.css +1 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-z80txd0f.js +19 -0
- amrita_go-0.1.0a1/frontend/dist/assets/index-z80txd0f.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/info-A6RAGUB7-q3zh4gf1.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/info-A6RAGUB7-q3zh4gf1.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/infoDiagram-27XIBGKW-0fs5f5g6.js +5 -0
- amrita_go-0.1.0a1/frontend/dist/assets/infoDiagram-27XIBGKW-0fs5f5g6.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ishikawaDiagram-5VMMS53U-zzdfyqwa.js +73 -0
- amrita_go-0.1.0a1/frontend/dist/assets/ishikawaDiagram-5VMMS53U-zzdfyqwa.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/journeyDiagram-3NMN7TZE-tfzkq339.js +142 -0
- amrita_go-0.1.0a1/frontend/dist/assets/journeyDiagram-3NMN7TZE-tfzkq339.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/kanban-definition-UXKFOSKX-7tyb2526.js +92 -0
- amrita_go-0.1.0a1/frontend/dist/assets/kanban-definition-UXKFOSKX-7tyb2526.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/katex-atpyhmb9.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/katex-atpyhmb9.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/main-j4ybp022.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/main-j4ybp022.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/mermaid-block-qc6zzf55.js +15 -0
- amrita_go-0.1.0a1/frontend/dist/assets/mermaid-block-qc6zzf55.js.map +19 -0
- amrita_go-0.1.0a1/frontend/dist/assets/mindmap-definition-YA3MSWOX-xdssqxrs.js +99 -0
- amrita_go-0.1.0a1/frontend/dist/assets/mindmap-definition-YA3MSWOX-xdssqxrs.js.map +13 -0
- amrita_go-0.1.0a1/frontend/dist/assets/packet-AYTQ26CC-csjhhp0g.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/packet-AYTQ26CC-csjhhp0g.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pegDiagram-XKGWAZYB-dfxmjy7d.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pegDiagram-XKGWAZYB-dfxmjy7d.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pie-WAS4IAKB-c34r6efb.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pie-WAS4IAKB-c34r6efb.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pieDiagram-E7YTZNPT-zq77mwa1.js +42 -0
- amrita_go-0.1.0a1/frontend/dist/assets/pieDiagram-E7YTZNPT-zq77mwa1.js.map +13 -0
- amrita_go-0.1.0a1/frontend/dist/assets/quadrantDiagram-AXDQQJYC-xqttaj0y.js +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/quadrantDiagram-AXDQQJYC-xqttaj0y.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/radar-RG4KPBEZ-gh6td0ns.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/radar-RG4KPBEZ-gh6td0ns.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-74A4TZTK-b5w32k1z.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-74A4TZTK-b5w32k1z.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-abnf-HS5TGJTU-9jrrhxtz.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-abnf-HS5TGJTU-9jrrhxtz.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-ebnf-LZEXJU2U-ptn8zb2e.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-ebnf-LZEXJU2U-ptn8zb2e.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-peg-WCYAUIDC-sf78y306.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroad-peg-WCYAUIDC-sf78y306.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroadDiagram-O6MQD6OU-bd57mh7f.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/railroadDiagram-O6MQD6OU-bd57mh7f.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/requirementDiagram-BXWQKSXE-smbnzk8r.js +87 -0
- amrita_go-0.1.0a1/frontend/dist/assets/requirementDiagram-BXWQKSXE-smbnzk8r.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sankeyDiagram-P5KCCOFB-62v92dxr.js +43 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sankeyDiagram-P5KCCOFB-62v92dxr.js.map +24 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sequenceDiagram-WJ2MYXX4-y1c6spqg.js +165 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sequenceDiagram-WJ2MYXX4-y1c6spqg.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sizeCapture-INFHLROL-jcdjvdwt.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/sizeCapture-INFHLROL-jcdjvdwt.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/stateDiagram-D77RDMKH-9855dxdp.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/stateDiagram-D77RDMKH-9855dxdp.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/stateDiagram-v2-MP3YSRHH-qtwctcqm.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/stateDiagram-v2-MP3YSRHH-qtwctcqm.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/swimlanes-42K2YHIH-syh23jms.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/swimlanes-42K2YHIH-syh23jms.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/swimlanesDiagram-VR7AAH4N-vr02f49g.js +11 -0
- amrita_go-0.1.0a1/frontend/dist/assets/swimlanesDiagram-VR7AAH4N-vr02f49g.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/timeline-definition-24CTP7MA-rf7dqa87.js +123 -0
- amrita_go-0.1.0a1/frontend/dist/assets/timeline-definition-24CTP7MA-rf7dqa87.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/treeView-Q6P3EWNA-pwbxezm1.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/treeView-Q6P3EWNA-pwbxezm1.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/treemap-WGGIJYW6-etxev972.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/treemap-WGGIJYW6-etxev972.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/vennDiagram-4TSXK5OY-79ewqkmq.js +37 -0
- amrita_go-0.1.0a1/frontend/dist/assets/vennDiagram-4TSXK5OY-79ewqkmq.js.map +12 -0
- amrita_go-0.1.0a1/frontend/dist/assets/wardley-WFR3VGLG-4sj4yz6z.js +4 -0
- amrita_go-0.1.0a1/frontend/dist/assets/wardley-WFR3VGLG-4sj4yz6z.js.map +9 -0
- amrita_go-0.1.0a1/frontend/dist/assets/wardleyDiagram-VM6X3IG4-rk8d3jz5.js +81 -0
- amrita_go-0.1.0a1/frontend/dist/assets/wardleyDiagram-VM6X3IG4-rk8d3jz5.js.map +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/xychartDiagram-S5SC5T6Z-jt385t8g.js +10 -0
- amrita_go-0.1.0a1/frontend/dist/assets/xychartDiagram-S5SC5T6Z-jt385t8g.js.map +12 -0
- amrita_go-0.1.0a1/frontend/dist/index.html +13 -0
- amrita_go-0.1.0a1/hatch_build.py +68 -0
- amrita_go-0.1.0a1/pyproject.toml +82 -0
- amrita_go-0.1.0a1/scripts/check_replay.py +114 -0
- amrita_go-0.1.0a1/scripts/check_skills.py +93 -0
- amrita_go-0.1.0a1/scripts/e2e_mock.py +114 -0
- amrita_go-0.1.0a1/scripts/mock_openai.py +167 -0
- amrita_go-0.1.0a1/scripts/smoke_ws.py +69 -0
- amrita_go-0.1.0a1/uv.lock +3324 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Workspace-scoped agent directory.
|
|
2
|
+
#
|
|
3
|
+
# Skills are project knowledge and should be committed:
|
|
4
|
+
# .amrita/skills/<name>/SKILL.md
|
|
5
|
+
# Memory (conversations, config, presets) is personal state and never belongs in
|
|
6
|
+
# a repo — and presets carry API keys.
|
|
7
|
+
.amrita/sessions/
|
|
8
|
+
.amrita/settings.json
|
|
9
|
+
.amrita/core.json
|
|
10
|
+
.amrita/mcp.json
|
|
11
|
+
.amrita/presets/
|
|
12
|
+
.amrita/*.local.json
|
|
13
|
+
|
|
14
|
+
# Build output / tooling
|
|
15
|
+
node_modules/
|
|
16
|
+
dist/
|
|
17
|
+
.dev-build/
|
|
18
|
+
.venv/
|
|
19
|
+
__pycache__/
|
|
20
|
+
*.py[cod]
|
|
21
|
+
.uv/
|
|
22
|
+
*.log
|
|
23
|
+
.DS_Store
|
|
24
|
+
.env
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: amrita-go
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: A agent workstation built on AmritaCore
|
|
5
|
+
Requires-Python: <3.15,>=3.10
|
|
6
|
+
Requires-Dist: amrita-core[anthropic]>=1.3.1
|
|
7
|
+
Requires-Dist: cryptography>=43.0
|
|
8
|
+
Requires-Dist: faskill[amrita]>=0.3.0
|
|
9
|
+
Requires-Dist: fastapi>=0.115.0
|
|
10
|
+
Requires-Dist: httpx>=0.28.1
|
|
11
|
+
Requires-Dist: keyring>=25.0; sys_platform == 'linux'
|
|
12
|
+
Requires-Dist: pydantic>=2.9.0
|
|
13
|
+
Requires-Dist: pyyaml>=6.0
|
|
14
|
+
Requires-Dist: uvicorn[standard]>=0.30.0
|
|
15
|
+
Provides-Extra: dev
|
|
16
|
+
Requires-Dist: ruff>=0.12.8; extra == 'dev'
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""AmritaGO backend package."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
# Read the installed distribution once, at import: one source of truth, no
|
|
7
|
+
# hand-maintained copy that drifts from pyproject.toml.
|
|
8
|
+
__version__ = version("amrita-go")
|
|
9
|
+
except PackageNotFoundError: # a source tree that was never installed
|
|
10
|
+
__version__ = "0.0.0"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Console entry point: ``python -m app`` or the ``amrita-go`` script."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from app.core.config import HOST, PORT
|
|
6
|
+
from app.core.logging_setup import setup_logging
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main() -> None:
|
|
10
|
+
import uvicorn
|
|
11
|
+
|
|
12
|
+
# Install before ``uvicorn.run`` so startup lines are already formatted.
|
|
13
|
+
setup_logging()
|
|
14
|
+
|
|
15
|
+
uvicorn.run(
|
|
16
|
+
"app.main:app",
|
|
17
|
+
host=HOST,
|
|
18
|
+
port=PORT,
|
|
19
|
+
reload=False,
|
|
20
|
+
log_level="info",
|
|
21
|
+
# Protocol pings time out while the dev proxy bundles; the app-level keepalive replaces them.
|
|
22
|
+
ws_ping_interval=None,
|
|
23
|
+
ws_ping_timeout=None,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
if __name__ == "__main__":
|
|
28
|
+
main()
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"""Agent presets: one Markdown file per agent mode.
|
|
2
|
+
|
|
3
|
+
The front matter holds ``name/description/icon/tools/access/workflow/memory/
|
|
4
|
+
template``; everything after it is the prompt body, and the body *is* the
|
|
5
|
+
system prompt. A body line starting with ``\\---`` becomes a literal ``---``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import fnmatch
|
|
12
|
+
import re
|
|
13
|
+
from collections.abc import Iterable
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import yaml
|
|
19
|
+
from amrita_core.consts import DEFAULT_TEMPLATE
|
|
20
|
+
from amrita_sense.logging import logger
|
|
21
|
+
from jinja2 import Template, TemplateSyntaxError
|
|
22
|
+
|
|
23
|
+
from app.capabilities.permissions import ACCESS_MODES
|
|
24
|
+
from app.core.config import PATHS
|
|
25
|
+
from app.runtime.workflows import DEFAULT_WORKFLOW, WORKFLOWS, WorkflowSpec
|
|
26
|
+
|
|
27
|
+
_FENCE = re.compile(r"^---\s*$", re.MULTILINE)
|
|
28
|
+
_ESCAPED_FENCE = "\\---"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AgentPresetError(ValueError):
|
|
32
|
+
"""Raised when a preset file cannot be understood."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _as_globs(raw: Any, key: str) -> list[str] | None:
|
|
36
|
+
if raw is None:
|
|
37
|
+
return None
|
|
38
|
+
if isinstance(raw, str):
|
|
39
|
+
return [part.strip() for part in raw.split(",") if part.strip()]
|
|
40
|
+
if isinstance(raw, list):
|
|
41
|
+
return [str(item).strip() for item in raw if str(item).strip()]
|
|
42
|
+
raise AgentPresetError(f"`{key}` must be a list or a comma-separated string")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class AgentPreset:
|
|
47
|
+
name: str
|
|
48
|
+
title: str
|
|
49
|
+
description: str = ""
|
|
50
|
+
icon: str = "bot"
|
|
51
|
+
# Glob patterns matched against tool names. ``None`` = allow every tool.
|
|
52
|
+
tools: list[str] | None = None
|
|
53
|
+
# Access modes this preset may use; ``None`` allows every mode.
|
|
54
|
+
access: list[str] | None = None
|
|
55
|
+
# Registered workflow to run; ``None`` follows the global switch.
|
|
56
|
+
workflow: str | None = None
|
|
57
|
+
# ``"session"`` mounts an app-owned scratch directory for plans and notes.
|
|
58
|
+
memory: str | None = None
|
|
59
|
+
# ``None`` -> use AmritaCore's default Jinja2 template.
|
|
60
|
+
template: str | None = None
|
|
61
|
+
prompt: str = ""
|
|
62
|
+
path: Path | None = None
|
|
63
|
+
scope: str = "user"
|
|
64
|
+
extra: dict[str, Any] = field(default_factory=dict)
|
|
65
|
+
|
|
66
|
+
def tool_allowed(self, tool_name: str) -> bool:
|
|
67
|
+
"""``None`` tools means "everything"; an empty list means "nothing"."""
|
|
68
|
+
if self.tools is None:
|
|
69
|
+
return True
|
|
70
|
+
return any(fnmatch.fnmatchcase(tool_name, pattern) for pattern in self.tools)
|
|
71
|
+
|
|
72
|
+
def access_allowed(self, mode: str) -> bool:
|
|
73
|
+
"""``None`` allows every mode; a list restricts to what it names."""
|
|
74
|
+
if self.access is None:
|
|
75
|
+
return True
|
|
76
|
+
return mode in self.access
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def read_only(self) -> bool:
|
|
80
|
+
"""A preset that can only read is the common safe default."""
|
|
81
|
+
return (
|
|
82
|
+
self.access is not None
|
|
83
|
+
and "readonly" in self.access
|
|
84
|
+
and not ("workspace" in self.access or "full" in self.access)
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def resolved_template(self) -> Template:
|
|
88
|
+
"""The Jinja2 template to render the system prompt with."""
|
|
89
|
+
if not self.template or not self.template.strip():
|
|
90
|
+
return DEFAULT_TEMPLATE
|
|
91
|
+
return Template(self.template)
|
|
92
|
+
|
|
93
|
+
def resolved_workflow(self, fallback: str | None = None) -> WorkflowSpec:
|
|
94
|
+
"""The preset's workflow, or the caller's active one when unpinned."""
|
|
95
|
+
return WORKFLOWS.require(self.workflow or fallback or DEFAULT_WORKFLOW)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def workflow_pinned(self) -> bool:
|
|
99
|
+
"""A preset that names a workflow overrides the global switch."""
|
|
100
|
+
return self.workflow is not None
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _unescape_body(body: str) -> str:
|
|
104
|
+
lines: list[str] = []
|
|
105
|
+
for line in body.splitlines():
|
|
106
|
+
if line.startswith(_ESCAPED_FENCE):
|
|
107
|
+
lines.append("---" + line[len(_ESCAPED_FENCE) :])
|
|
108
|
+
else:
|
|
109
|
+
lines.append(line)
|
|
110
|
+
return "\n".join(lines)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _split_frontmatter(text: str) -> tuple[str, str]:
|
|
114
|
+
"""Split into ``(yaml_text, body)``.
|
|
115
|
+
|
|
116
|
+
A file without front matter is treated as "prompt only" — useful for a
|
|
117
|
+
quick local mode. Everything else must be well-formed, because a silently
|
|
118
|
+
ignored ``tools:`` list is worse than a loud error.
|
|
119
|
+
"""
|
|
120
|
+
stripped = text.lstrip("\ufeff")
|
|
121
|
+
lines = stripped.splitlines()
|
|
122
|
+
if not lines or not _FENCE.match(lines[0]):
|
|
123
|
+
return "", stripped.strip()
|
|
124
|
+
|
|
125
|
+
end_meta = None
|
|
126
|
+
for index in range(1, len(lines)):
|
|
127
|
+
if _FENCE.match(lines[index]):
|
|
128
|
+
end_meta = index
|
|
129
|
+
break
|
|
130
|
+
if end_meta is None:
|
|
131
|
+
raise AgentPresetError("front matter is not closed with '---'")
|
|
132
|
+
|
|
133
|
+
yaml_text = "\n".join(lines[1:end_meta])
|
|
134
|
+
rest = lines[end_meta + 1 :]
|
|
135
|
+
first_content = next((line for line in rest if line.strip()), None)
|
|
136
|
+
if first_content is not None and _FENCE.match(first_content):
|
|
137
|
+
raise AgentPresetError(
|
|
138
|
+
"a second '---' block is no longer supported: put the Jinja2 "
|
|
139
|
+
"template under the YAML `template:` key, and start a body line "
|
|
140
|
+
"with '\\---' when you need a literal '---'"
|
|
141
|
+
)
|
|
142
|
+
return yaml_text, _unescape_body("\n".join(rest)).strip()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def parse_preset(path: Path, scope: str = "user") -> AgentPreset:
|
|
146
|
+
try:
|
|
147
|
+
text = path.read_text(encoding="utf-8")
|
|
148
|
+
except OSError as exc:
|
|
149
|
+
raise AgentPresetError(f"cannot read {path}: {exc}") from exc
|
|
150
|
+
|
|
151
|
+
yaml_text, body = _split_frontmatter(text)
|
|
152
|
+
|
|
153
|
+
meta: dict[str, Any] = {}
|
|
154
|
+
if yaml_text.strip():
|
|
155
|
+
try:
|
|
156
|
+
loaded = yaml.safe_load(yaml_text)
|
|
157
|
+
except yaml.YAMLError as exc:
|
|
158
|
+
raise AgentPresetError(f"invalid YAML: {exc}") from exc
|
|
159
|
+
if loaded is not None and not isinstance(loaded, dict):
|
|
160
|
+
raise AgentPresetError("front matter must be a mapping")
|
|
161
|
+
meta = loaded or {}
|
|
162
|
+
|
|
163
|
+
name = str(meta.get("name") or path.stem).strip()
|
|
164
|
+
if not name:
|
|
165
|
+
raise AgentPresetError("preset name is empty")
|
|
166
|
+
|
|
167
|
+
tools = _as_globs(meta.get("tools"), "tools")
|
|
168
|
+
access = _as_globs(meta.get("access"), "access")
|
|
169
|
+
if access is not None:
|
|
170
|
+
unknown = [mode for mode in access if mode not in ACCESS_MODES]
|
|
171
|
+
if unknown:
|
|
172
|
+
raise AgentPresetError(
|
|
173
|
+
f"unknown access mode(s): {', '.join(unknown)}; allowed: {', '.join(ACCESS_MODES)}"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Accepted and ignored: reasoning is always streamed now.
|
|
177
|
+
memory = meta.get("memory")
|
|
178
|
+
if memory is not None:
|
|
179
|
+
memory = str(memory).strip().lower() or None
|
|
180
|
+
if memory not in (None, "session"):
|
|
181
|
+
raise AgentPresetError("`memory` must be `session` (or omitted)")
|
|
182
|
+
|
|
183
|
+
workflow = meta.get("workflow")
|
|
184
|
+
if workflow is not None:
|
|
185
|
+
workflow = str(workflow).strip() or None
|
|
186
|
+
if workflow is not None:
|
|
187
|
+
try:
|
|
188
|
+
WORKFLOWS.require(workflow)
|
|
189
|
+
except ValueError as exc:
|
|
190
|
+
raise AgentPresetError(str(exc)) from exc
|
|
191
|
+
|
|
192
|
+
template = meta.get("template")
|
|
193
|
+
if template is not None and not isinstance(template, str):
|
|
194
|
+
raise AgentPresetError("`template` must be a string")
|
|
195
|
+
template = template.strip() if isinstance(template, str) else ""
|
|
196
|
+
if template:
|
|
197
|
+
try:
|
|
198
|
+
Template(template)
|
|
199
|
+
except TemplateSyntaxError as exc:
|
|
200
|
+
raise AgentPresetError(f"invalid Jinja2 template: {exc}") from exc
|
|
201
|
+
|
|
202
|
+
known = {
|
|
203
|
+
"name",
|
|
204
|
+
"title",
|
|
205
|
+
"description",
|
|
206
|
+
"icon",
|
|
207
|
+
"tools",
|
|
208
|
+
"access",
|
|
209
|
+
"workflow",
|
|
210
|
+
"memory",
|
|
211
|
+
"enable_thinking",
|
|
212
|
+
"template",
|
|
213
|
+
}
|
|
214
|
+
extra = {key: value for key, value in meta.items() if key not in known}
|
|
215
|
+
|
|
216
|
+
return AgentPreset(
|
|
217
|
+
name=name,
|
|
218
|
+
title=str(meta.get("title") or name),
|
|
219
|
+
description=str(meta.get("description") or ""),
|
|
220
|
+
icon=str(meta.get("icon") or "bot"),
|
|
221
|
+
tools=tools,
|
|
222
|
+
access=access,
|
|
223
|
+
workflow=workflow,
|
|
224
|
+
memory=memory,
|
|
225
|
+
template=template or None,
|
|
226
|
+
prompt=body or str(meta.get("prompt") or ""),
|
|
227
|
+
path=path,
|
|
228
|
+
scope=scope,
|
|
229
|
+
extra=extra,
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def unknown_tool_patterns(preset: AgentPreset, available: Iterable[str]) -> list[str]:
|
|
234
|
+
"""Preset ``tools:`` entries that match nothing in the current tool pool.
|
|
235
|
+
|
|
236
|
+
The pool is the **mixed** one — plugin tools and MCP tools together — because
|
|
237
|
+
a preset does not care where a tool comes from: it names tools, and a name
|
|
238
|
+
is a name. Checking only the built-in tools would report every MCP rule as a
|
|
239
|
+
typo, which is exactly how a warning becomes noise people filter out.
|
|
240
|
+
|
|
241
|
+
Reported, never enforced: a rule may legitimately wait for an MCP server
|
|
242
|
+
that is not connected right now, and a stale rule that suddenly matches a
|
|
243
|
+
future tool is harmless. The editor shows the list; the console gets one
|
|
244
|
+
line per preset.
|
|
245
|
+
"""
|
|
246
|
+
if preset.tools is None:
|
|
247
|
+
return []
|
|
248
|
+
names = [name for name in available if name]
|
|
249
|
+
return [
|
|
250
|
+
pattern
|
|
251
|
+
for pattern in preset.tools
|
|
252
|
+
if not any(fnmatch.fnmatchcase(name, pattern) for name in names)
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def discover_sync(workspace: Path | None = None) -> list[AgentPreset]:
|
|
257
|
+
"""Collect presets; a workspace file shadows a built-in or user one by name."""
|
|
258
|
+
PATHS.ensure()
|
|
259
|
+
found: list[AgentPreset] = []
|
|
260
|
+
seen: set[str] = set()
|
|
261
|
+
for directory, scope in (
|
|
262
|
+
(
|
|
263
|
+
PATHS.workspace_agents if workspace is None else workspace / ".amrita" / "agents",
|
|
264
|
+
"workspace",
|
|
265
|
+
),
|
|
266
|
+
(PATHS.user_agents, "user"),
|
|
267
|
+
):
|
|
268
|
+
if not directory.is_dir():
|
|
269
|
+
continue
|
|
270
|
+
for path in sorted(directory.glob("*.md")):
|
|
271
|
+
try:
|
|
272
|
+
preset = parse_preset(path, scope)
|
|
273
|
+
except AgentPresetError as exc:
|
|
274
|
+
logger.warning(f"Skipping agent preset {path}: {exc}")
|
|
275
|
+
continue
|
|
276
|
+
if preset.name in seen:
|
|
277
|
+
continue
|
|
278
|
+
seen.add(preset.name)
|
|
279
|
+
found.append(preset)
|
|
280
|
+
# Built-ins first; a file of the same name shadows one and keeps its place.
|
|
281
|
+
return [preset for preset in BUILTIN_PRESETS if preset.name not in seen] + found
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
async def discover(workspace: Path | None = None) -> list[AgentPreset]:
|
|
285
|
+
return await asyncio.to_thread(discover_sync, workspace)
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def find(name: str, workspace: Path | None = None) -> AgentPreset | None:
|
|
289
|
+
for preset in discover_sync(workspace):
|
|
290
|
+
if preset.name == name:
|
|
291
|
+
return preset
|
|
292
|
+
return None
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
BUILTIN_STANDARD = AgentPreset(
|
|
296
|
+
name="standard",
|
|
297
|
+
title="标准模式",
|
|
298
|
+
description="允许使用全部已启用的工具;工作流跟随全局设置。",
|
|
299
|
+
icon="wrench",
|
|
300
|
+
tools=None,
|
|
301
|
+
access=None,
|
|
302
|
+
workflow=None,
|
|
303
|
+
scope="builtin",
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
# Shipped modes. They live in code, so only a same-named file can override one.
|
|
307
|
+
BUILTIN_PLANNER = AgentPreset(
|
|
308
|
+
name="planner",
|
|
309
|
+
title="计划模式",
|
|
310
|
+
description="先拆解任务再动手,适合多步骤需求。只读,计划写在会话临时目录里。",
|
|
311
|
+
icon="list-tree",
|
|
312
|
+
tools=None,
|
|
313
|
+
access=["readonly"],
|
|
314
|
+
workflow="react-step",
|
|
315
|
+
memory="session",
|
|
316
|
+
scope="builtin",
|
|
317
|
+
prompt=(
|
|
318
|
+
"你是计划模式。收到需求后先列出步骤,再逐步执行;每一步说明依据。\n\n"
|
|
319
|
+
"本预设使用步进 ReAct:任务会先被拆解成多步计划,再逐个执行,"
|
|
320
|
+
"所以务必先说明整体思路再动手。\n"
|
|
321
|
+
"当前会话是只读的:可以读取文件、搜索代码、翻目录,但不能修改工作区;"
|
|
322
|
+
"这一模式不提供 shell,需要跑命令请换成具备写权限的预设。\n"
|
|
323
|
+
"如果需要动手改代码,请在回答末尾提醒用户切换到具备写权限的 Agent 预设。\n\n"
|
|
324
|
+
"## 计划写在哪里\n\n"
|
|
325
|
+
"系统提示词里会给出本次会话的临时记忆目录。把拆解结果用 `memory_write` 存成 "
|
|
326
|
+
"`plan.md`(步骤、依赖、验收标准),执行过程中用 `memory_write` 更新状态,"
|
|
327
|
+
"需要时用 `memory_read` 读回,不要让计划只存在于对话里。"
|
|
328
|
+
"这个目录随对话删除,不属于工作区,可以放心写;"
|
|
329
|
+
"但不要用它保存源码或试图绕过只读限制。\n"
|
|
330
|
+
),
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
BUILTIN_CODER = AgentPreset(
|
|
334
|
+
name="coder",
|
|
335
|
+
title="编码模式",
|
|
336
|
+
description="可读写工作区,工作流跟随全局设置。",
|
|
337
|
+
icon="code",
|
|
338
|
+
# No whitelist: a coder that cannot reach the files is not a coder.
|
|
339
|
+
tools=None,
|
|
340
|
+
access=["workspace", "full"],
|
|
341
|
+
workflow=None,
|
|
342
|
+
scope="builtin",
|
|
343
|
+
prompt=(
|
|
344
|
+
"你是编码模式,可以读写当前工作区中的文件。动手前先读相关代码,"
|
|
345
|
+
"改完自己验证一遍。回答里不要重复贴出整份文件,说清楚改了什么、为什么改。\n"
|
|
346
|
+
),
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
BUILTIN_PRESETS: tuple[AgentPreset, ...] = (
|
|
350
|
+
BUILTIN_STANDARD,
|
|
351
|
+
BUILTIN_PLANNER,
|
|
352
|
+
BUILTIN_CODER,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# Names reserved by the built-ins, so an override can be labelled as one.
|
|
356
|
+
BUILTIN_NAMES: frozenset[str] = frozenset(preset.name for preset in BUILTIN_PRESETS)
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def resolve(name: str | None, workspace: Path | None = None) -> AgentPreset:
|
|
360
|
+
"""Look up a preset, falling back to the built-in standard mode."""
|
|
361
|
+
if name:
|
|
362
|
+
found = find(name, workspace)
|
|
363
|
+
if found is not None:
|
|
364
|
+
return found
|
|
365
|
+
return BUILTIN_STANDARD
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def to_public(preset: AgentPreset) -> dict[str, Any]:
|
|
369
|
+
workflow: WorkflowSpec | None = WORKFLOWS.get(preset.workflow)
|
|
370
|
+
return {
|
|
371
|
+
"name": preset.name,
|
|
372
|
+
"title": preset.title,
|
|
373
|
+
"description": preset.description,
|
|
374
|
+
"icon": preset.icon,
|
|
375
|
+
"tools": preset.tools,
|
|
376
|
+
"access": preset.access,
|
|
377
|
+
"read_only": preset.read_only,
|
|
378
|
+
"workflow": preset.workflow,
|
|
379
|
+
"workflow_pinned": preset.workflow_pinned,
|
|
380
|
+
"workflow_title": workflow.title if workflow else None,
|
|
381
|
+
"workflow_mode": workflow.mode if workflow else None,
|
|
382
|
+
"workflow_mode_label": workflow.mode_label if workflow else None,
|
|
383
|
+
"memory": preset.memory,
|
|
384
|
+
"scope": preset.scope,
|
|
385
|
+
# True when this file overrides a built-in mode.
|
|
386
|
+
"shadows_builtin": preset.scope != "builtin" and preset.name in BUILTIN_NAMES,
|
|
387
|
+
"path": str(preset.path) if preset.path else None,
|
|
388
|
+
"has_custom_template": bool(preset.template and preset.template.strip()),
|
|
389
|
+
"has_custom_prompt": bool(preset.prompt.strip()),
|
|
390
|
+
}
|