multiagentos 0.4.0__py3-none-any.whl
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.
- agents/__init__.py +1 -0
- agents/catalog.py +52 -0
- agents/registry.py +11 -0
- core/__init__.py +38 -0
- core/artifacts.py +47 -0
- core/chat_agent_bridge.py +280 -0
- core/chat_agent_registry.py +61 -0
- core/chat_agent_router.py +85 -0
- core/chat_session.py +62 -0
- core/contracts/__init__.py +22 -0
- core/contracts/agent.py +21 -0
- core/contracts/ai.py +25 -0
- core/contracts/capability.py +44 -0
- core/contracts/chat_agent.py +34 -0
- core/contracts/checkpoint.py +78 -0
- core/contracts/discovery.py +30 -0
- core/contracts/execution.py +28 -0
- core/contracts/github.py +74 -0
- core/contracts/handoff.py +56 -0
- core/contracts/health.py +206 -0
- core/contracts/human_review.py +20 -0
- core/contracts/ide.py +113 -0
- core/contracts/mcp.py +76 -0
- core/contracts/model_runtime.py +25 -0
- core/contracts/planning.py +25 -0
- core/contracts/profile.py +66 -0
- core/contracts/quota.py +62 -0
- core/contracts/repository.py +34 -0
- core/contracts/resume.py +55 -0
- core/contracts/runtime.py +19 -0
- core/contracts/vyrelon_runtime.py +118 -0
- core/contracts/work_unit.py +48 -0
- core/delegation.py +33 -0
- core/handoff.py +68 -0
- core/lifecycle.py +85 -0
- core/multi_agent_workflow.py +574 -0
- core/orchestrator.py +51 -0
- core/planning.py +22 -0
- core/registry.py +44 -0
- core/routing.py +195 -0
- core/state.py +155 -0
- installer/__init__.py +1 -0
- installer/init.py +71 -0
- integrations/__init__.py +0 -0
- integrations/github/__init__.py +3 -0
- integrations/github/gateway.py +164 -0
- integrations/openai/__init__.py +1 -0
- integrations/openai/chat_agent.py +147 -0
- multiagentos/__init__.py +1 -0
- multiagentos/cli.py +759 -0
- multiagentos-0.4.0.dist-info/METADATA +7 -0
- multiagentos-0.4.0.dist-info/RECORD +122 -0
- multiagentos-0.4.0.dist-info/WHEEL +5 -0
- multiagentos-0.4.0.dist-info/entry_points.txt +2 -0
- multiagentos-0.4.0.dist-info/top_level.txt +7 -0
- profiles/__init__.py +1 -0
- profiles/common.py +11 -0
- profiles/detector.py +67 -0
- profiles/registry.py +46 -0
- profiles/resolver.py +63 -0
- runtime/__init__.py +5 -0
- runtime/agent/__init__.py +1 -0
- runtime/agent/ide.py +74 -0
- runtime/agent/model.py +197 -0
- runtime/agent/model_backed.py +49 -0
- runtime/agent/process.py +21 -0
- runtime/builtin_tools.py +57 -0
- runtime/capability.py +143 -0
- runtime/chat_adapter_registry.py +43 -0
- runtime/chat_config.py +57 -0
- runtime/chat_execution.py +52 -0
- runtime/config/__init__.py +1 -0
- runtime/config/loader.py +67 -0
- runtime/discovery.py +334 -0
- runtime/execution_config.py +71 -0
- runtime/execution_registry.py +50 -0
- runtime/git.py +84 -0
- runtime/github.py +56 -0
- runtime/github_probe.py +23 -0
- runtime/health.py +14 -0
- runtime/ide/__init__.py +6 -0
- runtime/ide/bridge.py +198 -0
- runtime/ide/registry.py +24 -0
- runtime/ide/runtime.py +35 -0
- runtime/local/__init__.py +18 -0
- runtime/local/filesystem.py +58 -0
- runtime/local/patch.py +79 -0
- runtime/local/path_security.py +31 -0
- runtime/local/permissions.py +20 -0
- runtime/local/process.py +56 -0
- runtime/local/shell.py +97 -0
- runtime/mcp/__init__.py +7 -0
- runtime/mcp/client.py +120 -0
- runtime/mcp/config.py +36 -0
- runtime/mcp/policy.py +57 -0
- runtime/mcp/proxy.py +30 -0
- runtime/mcp/server.py +137 -0
- runtime/mcp/session.py +19 -0
- runtime/model/__init__.py +5 -0
- runtime/model/ai_runtime.py +165 -0
- runtime/model/cli.py +49 -0
- runtime/model/config.py +98 -0
- runtime/model/credentials.py +42 -0
- runtime/model/factory.py +82 -0
- runtime/model/http.py +78 -0
- runtime/model/invoker.py +16 -0
- runtime/model/materializer.py +101 -0
- runtime/model/native.py +244 -0
- runtime/model/providers.py +55 -0
- runtime/model/registry.py +26 -0
- runtime/model/runtime_loader.py +51 -0
- runtime/model_control.py +136 -0
- runtime/multi_agent.py +142 -0
- runtime/policy.py +28 -0
- runtime/process.py +41 -0
- runtime/quota.py +259 -0
- runtime/repository.py +103 -0
- runtime/repository_tools.py +62 -0
- runtime/status.py +87 -0
- runtime/tool_calling.py +134 -0
- runtime/validation.py +121 -0
- runtime/vyrelon.py +1557 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
agents/__init__.py,sha256=y8HsCN8YhVOJqxV1MtJouTbIsFHnAE5E7rL0YMrrJDQ,38
|
|
2
|
+
agents/catalog.py,sha256=lZAD7k5BNZaUjdCfNQhL8K-6AzU-yK7xPgWdLlySdzk,2432
|
|
3
|
+
agents/registry.py,sha256=lHnGWejM5V_hHk_duuFEGX4TiTkhEOxYwWqZPQzMwPI,341
|
|
4
|
+
core/__init__.py,sha256=DNVaqbDfMDiMSzjRTCnGlp9K-GeL8rDFtGE38LpkKkw,2422
|
|
5
|
+
core/artifacts.py,sha256=x8UEkQBSNwaEsW7wqv3vya7A_JiJ2LD8TvC0SkzAP08,1576
|
|
6
|
+
core/chat_agent_bridge.py,sha256=4pwaF-zRWpt42JaP5UGWKwvEj9OHI3FKSaM82-lwwoI,10791
|
|
7
|
+
core/chat_agent_registry.py,sha256=AXOMJERyrGroXEo6FPvVNB75rQEAc3CiLTlH05MRGn8,1933
|
|
8
|
+
core/chat_agent_router.py,sha256=ta45juNjxQdE4uCDDrrmsPRItZFaSpv9eO8pnv4c-A8,2872
|
|
9
|
+
core/chat_session.py,sha256=iM-4iYIl6gGXDQqn_rnRYuPqb3-dsr5zHnuB6W65Z1c,2100
|
|
10
|
+
core/delegation.py,sha256=ZDynxkaLhcQ5AqzMdys55jxMeJmZxzFbo7_ddEL2qMs,1029
|
|
11
|
+
core/handoff.py,sha256=xijpkuYsdExvgQI8gXaVpTD80Oyn9x2MlfZG2SFrwCs,2573
|
|
12
|
+
core/lifecycle.py,sha256=rTmvKidCX4YS9TR9lKwWrM7TY29oMCHRL7bpnP8YOsU,3624
|
|
13
|
+
core/multi_agent_workflow.py,sha256=_n2FFsIq_U5AAt1oBx2Xn7DjUJdpiy6P7qM-QB6dF6w,28509
|
|
14
|
+
core/orchestrator.py,sha256=Y1_TSlGMQ2EX75e7VVC6rfXjVp3NWuZbHdu59seLch0,1656
|
|
15
|
+
core/planning.py,sha256=SLSwiMl2pU7Y2b-JxOvzI72sF5OpbeG67aGGEqJwyZU,797
|
|
16
|
+
core/registry.py,sha256=_YPS8PvSUmueTvXOaECzFB27Lvx4ERhBX7oDWcRaurw,1489
|
|
17
|
+
core/routing.py,sha256=8muE1DDrUfH-nQhLGENKHHVKpbrk6yX-bk_5lpk4j7s,7357
|
|
18
|
+
core/state.py,sha256=HUaBrmQOSwrzfNZxPPogQzDXhcx_3DpCUvcDAvNq9hQ,5567
|
|
19
|
+
core/contracts/__init__.py,sha256=AW61P8Bon06eUtByLe7VBpAaiBhJnytopx-Xy0kPiEY,1260
|
|
20
|
+
core/contracts/agent.py,sha256=YfzN1KaZLVLuo76my18Nb4FhJzHkvPNHJLtWAsKcRN4,574
|
|
21
|
+
core/contracts/ai.py,sha256=5Z3QLt9kDOaMd0WcrKYl_7MzhiZg-8c2KEjEoxz7-o8,607
|
|
22
|
+
core/contracts/capability.py,sha256=jd1oTxaRuvaKyNDjibx2cMb-4h7TymAd76-JC6OSaMA,1194
|
|
23
|
+
core/contracts/chat_agent.py,sha256=1BhxrZuxxOH3ZInN-yK5yMY648CtFXX5NDjMDIvVIL8,1034
|
|
24
|
+
core/contracts/checkpoint.py,sha256=wIGOtUVtjex13o6RUjaixbngdplm_lEY3x0gbeC66KE,3017
|
|
25
|
+
core/contracts/discovery.py,sha256=xJawPFQON_ynjAGxDg9LuYTHR_73e48yw1TD9_CaS1U,804
|
|
26
|
+
core/contracts/execution.py,sha256=evMJ1Cv2LApE4wQdV7vEs2t4vpopvQnbnAx3umtk3M0,696
|
|
27
|
+
core/contracts/github.py,sha256=vJ5lgGrzf8_oelv2dVuwPehtpb1tYYpSRCI91j4AFmE,1977
|
|
28
|
+
core/contracts/handoff.py,sha256=Y2tpas2YXsq0tsdLiip_Me9nlitk7DfniB9Fc9-b6f4,1428
|
|
29
|
+
core/contracts/health.py,sha256=CVF_L4ukFq8HxZdTmzvlSDOFwplm5X-mhRXQMxc7qho,7847
|
|
30
|
+
core/contracts/human_review.py,sha256=f8-QrzQY7gySPKuNY2LO8GngdfxEg0dU9jabOPezbxg,625
|
|
31
|
+
core/contracts/ide.py,sha256=rjNCq-AfYRAtmYZ4NLGtc1nmWoWZNxHPXwo8isveIvQ,2901
|
|
32
|
+
core/contracts/mcp.py,sha256=YG5SoRWQgyPrS00vvrwjiAOEsBWQ76kJjD7fYOmA17g,2874
|
|
33
|
+
core/contracts/model_runtime.py,sha256=38LA5E3WJLcGRBLRnG3eousAGIeOTW8F1X3axJrIRoI,583
|
|
34
|
+
core/contracts/planning.py,sha256=f3Y9lxOa-fm0uUY5wf8x2e-_YD8eOUw02sG7HyN_wKI,606
|
|
35
|
+
core/contracts/profile.py,sha256=ToTYhSYo522chlofTbdNQh7o24ED3ktFTnhHuAjwH6g,1837
|
|
36
|
+
core/contracts/quota.py,sha256=wFSv8p8meH-OomfM7A1iRGXkJpb58TvBDWuyFf8nTXk,1972
|
|
37
|
+
core/contracts/repository.py,sha256=WxfszMGN-UhVEAVdu5DWXOEx0xizuauVB5DHl0Stdl4,735
|
|
38
|
+
core/contracts/resume.py,sha256=1Msuel7LFFZICYN6dzZ-fgabrUUxyA8svb9j6uy7WCQ,2051
|
|
39
|
+
core/contracts/runtime.py,sha256=3wvtE1UgoN0m5fgaiWc0jokNsh8OQ7NhrYm2fhKVdQ0,454
|
|
40
|
+
core/contracts/vyrelon_runtime.py,sha256=PVVthOaRQFhqcKI8FI72u0tVCYRg2KG_KtmJgKhu_Pg,3150
|
|
41
|
+
core/contracts/work_unit.py,sha256=OYV1uaz8OL0PwF66aVzGExBE_FGN1U8_fkfkRbQUhk4,2176
|
|
42
|
+
installer/__init__.py,sha256=QX7TH_bKx3EjYlWVCiULi9azBmusF8PtSXAdJu2fApQ,33
|
|
43
|
+
installer/init.py,sha256=Cv49irDMBkC7x3VQt4PXLa1YkozPaGRP69i1LmCx_1Q,2395
|
|
44
|
+
integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
+
integrations/github/__init__.py,sha256=nwgfGd3sLQqBJLen49mToxQ7_ShXPT-nFS0s9mO7fHo,76
|
|
46
|
+
integrations/github/gateway.py,sha256=VRIXB0x9tzbqyfCWvnKFfFCBfAzvRtRWqArYUoGtQ10,5849
|
|
47
|
+
integrations/openai/__init__.py,sha256=1W9xUQyjzOqA9Kj9y7zCbLXi6Ymhspnq5Hl4pmbhRlI,56
|
|
48
|
+
integrations/openai/chat_agent.py,sha256=9APx0HTlsyOGNCmUB7iP2dD1qhd___DZRvNjon_2llU,4912
|
|
49
|
+
multiagentos/__init__.py,sha256=-WldAiz_IVL68ANxkJ4wXNyiuUknWJdJ1oHT9cJgNo8,41
|
|
50
|
+
multiagentos/cli.py,sha256=QoiNQkINCGj4uCfte2DK12zHwjxXYput_W4DoJ7fUwU,31059
|
|
51
|
+
profiles/__init__.py,sha256=EnaT_9gNjw8eLRK7O7uDLsa9IYa-cYOTsr4L7neLBBQ,48
|
|
52
|
+
profiles/common.py,sha256=A6J4go0KKfAhnJTTavPJ9GN3PxeoD88XrrldO3B-qI0,190
|
|
53
|
+
profiles/detector.py,sha256=nF6SM4TN_ILyKpO38i8rtJsw7ZniVRY6AZEyElBoWVg,2755
|
|
54
|
+
profiles/registry.py,sha256=IqPx6XyMkKcWXSpS9Htty4qnrlOBxHeIczhdrH-kRGg,1519
|
|
55
|
+
profiles/resolver.py,sha256=QrUeBvr9svCtxUkKZXh5hPygkhP89QlqmHXdh-aOn-M,2269
|
|
56
|
+
runtime/__init__.py,sha256=MuEw9LO8UJqQND0iztNb6sj7NHpGZgRDMTwPBUa0N7s,112
|
|
57
|
+
runtime/builtin_tools.py,sha256=PRPB2RZujqRfWLMmM63us1Zmvs8E6A356SMwm2tRHYQ,3335
|
|
58
|
+
runtime/capability.py,sha256=e6Y7fOg0wFhAeS6T50S_bWiMTYoNuwZ0q52y5FIvpn0,5543
|
|
59
|
+
runtime/chat_adapter_registry.py,sha256=O_zjBaA_KEXC79SmLiU4tIis2jNny-uzW2nCWc-UGNw,1385
|
|
60
|
+
runtime/chat_config.py,sha256=gD07_5B3czQ044M1J4cM9ECQ3LAcsQiMci6osGc08T4,1824
|
|
61
|
+
runtime/chat_execution.py,sha256=9MjzXT47MROMCZ3ftt4OuuzTVenY4zTg2BhpEoAPd2E,1778
|
|
62
|
+
runtime/discovery.py,sha256=0oATBN5jLG_5Dc2o6WF3rzWGz310szv0iIVjeo5EQO8,14274
|
|
63
|
+
runtime/execution_config.py,sha256=rfz5KaHLozmhw9c6IfPUavUELAWEo3xrpRO6DX78tpo,2179
|
|
64
|
+
runtime/execution_registry.py,sha256=bUeG0UzQRvJyK0jd0aGnMfuQEGUnzCVgpHaSdnAI84M,1425
|
|
65
|
+
runtime/git.py,sha256=ZmBtpetBXLouwat-3KySH_ljTOjA58ruo8kHgLEAl2A,3275
|
|
66
|
+
runtime/github.py,sha256=YiPPfPFBiDwf30pyL-lVS3vqDOopjVWzkS8Sr3aD71M,2394
|
|
67
|
+
runtime/github_probe.py,sha256=LR3iSGVvf0SZ3COitA9IhpbXRKkBHEoevfK0tKW8vMo,656
|
|
68
|
+
runtime/health.py,sha256=xiH9Kay_wDYPBh2ZWWcbmbxvjzOYPFYLuGsb-rE1DYs,263
|
|
69
|
+
runtime/model_control.py,sha256=XX7fRAY1cNBO5MJlBklgOw0polTqTW3G8wV0TGPT13E,5027
|
|
70
|
+
runtime/multi_agent.py,sha256=ut-MGFdZEPNP-a0GbxGWGdl_tM934e9ab_rOLS6hDIk,5471
|
|
71
|
+
runtime/policy.py,sha256=zziUs3sIZoNg7ymAsUdNT1zkLb6Omcc3RT-Kv0gtld4,931
|
|
72
|
+
runtime/process.py,sha256=lyvvWk-x6ZGxEWroMW2CBbQgvnkU9dCkDKZnorVoXsI,1051
|
|
73
|
+
runtime/quota.py,sha256=tepzRRathFlR47vUtkCIPvEj2gz-3VRfaN9vw_PA8cg,9863
|
|
74
|
+
runtime/repository.py,sha256=s7LeenkxPLpKWa-G-TjXCCBAes0cLqkJpmnJmw4X78o,4469
|
|
75
|
+
runtime/repository_tools.py,sha256=nJwbDJICo8Oe8CzjBEPXwB0aGVjvAgO8KNS-rbJYDYI,3898
|
|
76
|
+
runtime/status.py,sha256=I1hR5k6apgb7ScUps8YpgZ_tsX7wZ-wIGCPeBUFO-PY,3117
|
|
77
|
+
runtime/tool_calling.py,sha256=j87XkqCYmGzyaIdCWvKZEvCTDH0HYS5b212oNGVyJjM,7645
|
|
78
|
+
runtime/validation.py,sha256=eVHeCErxYPVX8I7IBdKuRx0DelBK94CldvpuPsdGxC0,3613
|
|
79
|
+
runtime/vyrelon.py,sha256=OXV-cxDFKF088QHQM8LoyUf7XWvy9aKEJ17d3Y0GSpc,66439
|
|
80
|
+
runtime/agent/__init__.py,sha256=sXO_vqwo7w0lJ0NmhQ3CxaX_HA3byyBoDDRIYHphWRo,30
|
|
81
|
+
runtime/agent/ide.py,sha256=ha2XR0XtSsaC_AItBG9gpg2mQ1knPNgm1dXuFq1JGm8,2772
|
|
82
|
+
runtime/agent/model.py,sha256=ba20cT1dLVYWwtX6nVxupGf2IviFNbh3HQt2S0aatWE,9846
|
|
83
|
+
runtime/agent/model_backed.py,sha256=vHYJilKiyv6nkladkwKEwS9IR5Z9cLzdOY9wWXjjf5E,1813
|
|
84
|
+
runtime/agent/process.py,sha256=D791ZlAqWu6b_tRQswn2DbyKhu4-VXOffir_maVmx58,746
|
|
85
|
+
runtime/config/__init__.py,sha256=cFuQW5pF5LwvfkXMcpWcEeVLtHxMzm0serM-oNXlFLg,37
|
|
86
|
+
runtime/config/loader.py,sha256=UYPTBap_lzXhAcApCQH7nEG9IFGFbY7BEE_kpMxYrPY,2395
|
|
87
|
+
runtime/ide/__init__.py,sha256=9TfNq6Oe4UoowMGEkv0zlrlEyhu8XQUw6wnZ2-cu34w,171
|
|
88
|
+
runtime/ide/bridge.py,sha256=fQ5k2AuPtpdWGEF14KcPxpT91lwMjzEPJOJsuTz3neQ,7921
|
|
89
|
+
runtime/ide/registry.py,sha256=Vz14Nnx2K945Ei3QfTCX2XvJTCzwgOiojVM74y_AEmI,720
|
|
90
|
+
runtime/ide/runtime.py,sha256=-K_oag89Veq7s-I6bueoe6OUvYzDRUcDqjOStf0OYic,1340
|
|
91
|
+
runtime/local/__init__.py,sha256=eCzuXSAUy6_IbuXq3SqiSBHgKARv-T8SZBUuZXoowjo,542
|
|
92
|
+
runtime/local/filesystem.py,sha256=KWLmVtC9y5fGsd0CpkHzXh00FiNuI7MreEs1t-EbxnQ,2138
|
|
93
|
+
runtime/local/patch.py,sha256=3buicbQiygh_M_DKmdyK8o1ucrmQnTr9n3VyaG0g-GY,2826
|
|
94
|
+
runtime/local/path_security.py,sha256=PKDfCy48pt3GN_gysHDO_T4_l-ygUsRNAo0BmVhWzyk,1160
|
|
95
|
+
runtime/local/permissions.py,sha256=s4OC2DQqq71pWX5JqoRbdcLOkVl6pDKreTTRA81NM-w,665
|
|
96
|
+
runtime/local/process.py,sha256=bOkOfsiYaTfI86d9YclNY1LkTACoZCsa63LHrbK3U-w,1933
|
|
97
|
+
runtime/local/shell.py,sha256=0bT-7oc2MKY0M1qY-bM9bSMKZ6ryfD9VbJxT6T6z2lo,2990
|
|
98
|
+
runtime/mcp/__init__.py,sha256=Q-LvSM1AGNW6uGq8B4b6QEEGCnAOInS_gS-zQmQaCD4,359
|
|
99
|
+
runtime/mcp/client.py,sha256=chJyEbuEgaPaD3jEPI6LyECIEm4rqv9l27-cPQwAdXU,6912
|
|
100
|
+
runtime/mcp/config.py,sha256=CqDFZ4bxUI1XzOPyXuwsIAs7i8r5YGr9Ebcvww_Y0QU,1759
|
|
101
|
+
runtime/mcp/policy.py,sha256=3I2HQ0JO1BUXVOVh2Izug5feD7zjSQzFMGdutRb-1EI,2962
|
|
102
|
+
runtime/mcp/proxy.py,sha256=wfG2xx23PitQIq7izc1IDV3zNN6L5lKvCtzbhl0lNoE,1662
|
|
103
|
+
runtime/mcp/server.py,sha256=uYKAKrDHwaluMAWEocBeGi4nDxd4oY6i_7b55n9jkJM,5012
|
|
104
|
+
runtime/mcp/session.py,sha256=-yVuLPSSTfStYY8n2Ounc93D4qacnafXF_nQq270Rfk,835
|
|
105
|
+
runtime/model/__init__.py,sha256=xZK9YeuhXqbU2TH3ek36COu9tBARdyMYy5Psqg4CUO4,185
|
|
106
|
+
runtime/model/ai_runtime.py,sha256=Z3M5SL-KZcmlOPGLBf3c3TEdPd1GjOJvV7Lq0U_P5zo,5151
|
|
107
|
+
runtime/model/cli.py,sha256=2bgUBgdhVIz7lPv2uuBIsXLeiZhMsbF9ZruHlFjGP7o,1608
|
|
108
|
+
runtime/model/config.py,sha256=7yFBv3LW5rYVlj55gPqm1VQHBVeLGzYp-bElY4ICHsA,3391
|
|
109
|
+
runtime/model/credentials.py,sha256=PA6HRSx91qNzrNw1XXJz7WllUR8NGQSbm0q3Vvck5EE,1255
|
|
110
|
+
runtime/model/factory.py,sha256=fYylUKaGlpMgTVxv1sIHQrEWRZYDWnqbJcps17dHlsE,3201
|
|
111
|
+
runtime/model/http.py,sha256=UX2V6dyM4Yi1ukVlZkuerORpb4cMPNh9dCdP3ncG8OI,2933
|
|
112
|
+
runtime/model/invoker.py,sha256=k4wFSsYAeTCapwHOf1euDfsHrulD_q0n7Nx9t72RVBY,679
|
|
113
|
+
runtime/model/materializer.py,sha256=uwBwOEv11iT704pPk5jzM8TQB1BOs6Nl-o0Uuy-DVBY,4084
|
|
114
|
+
runtime/model/native.py,sha256=54KqxPt9TH6T4KHb_TinsJTjHxlqOOfFT6YCZtPsQOM,14147
|
|
115
|
+
runtime/model/providers.py,sha256=7mWTL8tx4oqeA4vmyB9YFxB1n31qCBvIfHCPWk7X8Io,2050
|
|
116
|
+
runtime/model/registry.py,sha256=ZlLxKhEDtiNh03weL0cAU4fh82TYC64602rE-03dmlM,947
|
|
117
|
+
runtime/model/runtime_loader.py,sha256=aeK3MISBTBSN3pmKCzh_wTqFe6_zCwLAZCD2Qvu_QkA,1706
|
|
118
|
+
multiagentos-0.4.0.dist-info/METADATA,sha256=XWf5m0oIs42U8mRtF0SKf0Guxhqd5oFHdhtjm7_Ux5g,236
|
|
119
|
+
multiagentos-0.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
120
|
+
multiagentos-0.4.0.dist-info/entry_points.txt,sha256=nm1yOCYxb6I5ACZHfl6gUOqrJuy7cAWhBKtwTaUEGK4,55
|
|
121
|
+
multiagentos-0.4.0.dist-info/top_level.txt,sha256=4sxE8X-XOTUs2_SEwTG6LNfrwmqT1DbqqhXylXQLsNg,65
|
|
122
|
+
multiagentos-0.4.0.dist-info/RECORD,,
|
profiles/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Technology profiles supported by VYRELON."""
|
profiles/common.py
ADDED
profiles/detector.py
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""Project profile detection based on repository evidence."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from core.contracts.profile import DetectionResult, ProfileSpec
|
|
9
|
+
from profiles.registry import ProfileRegistry
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
_IGNORED_DIRS = {".git", "node_modules", "Pods", ".gradle", "build", "dist", "venv", ".venv"}
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ProfileDetector:
|
|
16
|
+
def __init__(self, registry: ProfileRegistry | None = None) -> None:
|
|
17
|
+
self.registry = registry or ProfileRegistry()
|
|
18
|
+
|
|
19
|
+
def detect(self, project_root: Path) -> tuple[DetectionResult, ...]:
|
|
20
|
+
results = []
|
|
21
|
+
for profile in self.registry.list():
|
|
22
|
+
evidence = self._evidence(project_root, profile)
|
|
23
|
+
if evidence:
|
|
24
|
+
confidence = min(
|
|
25
|
+
1.0,
|
|
26
|
+
len(evidence) / max(1, len(profile.detect_files) + len(profile.detect_markers)),
|
|
27
|
+
)
|
|
28
|
+
results.append(DetectionResult(profile.id, confidence, tuple(evidence)))
|
|
29
|
+
return tuple(sorted(results, key=lambda result: (-result.confidence, result.profile_id)))
|
|
30
|
+
|
|
31
|
+
def _evidence(self, root: Path, profile: ProfileSpec) -> list[str]:
|
|
32
|
+
evidence = [name for name in profile.detect_files if (root / name).exists()]
|
|
33
|
+
|
|
34
|
+
package = root / "package.json"
|
|
35
|
+
if package.exists() and "react-native" in profile.detect_markers:
|
|
36
|
+
try:
|
|
37
|
+
data = json.loads(package.read_text(encoding="utf-8"))
|
|
38
|
+
except (OSError, json.JSONDecodeError):
|
|
39
|
+
data = {}
|
|
40
|
+
dependencies = {
|
|
41
|
+
**data.get("dependencies", {}),
|
|
42
|
+
**data.get("devDependencies", {}),
|
|
43
|
+
}
|
|
44
|
+
if "react-native" in dependencies:
|
|
45
|
+
evidence.append("package.json:react-native")
|
|
46
|
+
|
|
47
|
+
for marker in profile.detect_markers:
|
|
48
|
+
if marker.startswith("."):
|
|
49
|
+
if any(root.glob(f"*{marker}")):
|
|
50
|
+
evidence.append(marker)
|
|
51
|
+
elif self._contains_marker(root, marker):
|
|
52
|
+
evidence.append(marker)
|
|
53
|
+
|
|
54
|
+
return list(dict.fromkeys(evidence))
|
|
55
|
+
|
|
56
|
+
def _contains_marker(self, root: Path, marker: str) -> bool:
|
|
57
|
+
candidate_names = {"settings.gradle", "settings.gradle.kts", "build.gradle", "build.gradle.kts", "Package.swift"}
|
|
58
|
+
for path in root.rglob("*"):
|
|
59
|
+
if any(part in _IGNORED_DIRS for part in path.parts):
|
|
60
|
+
continue
|
|
61
|
+
if path.is_file() and (path.name in candidate_names or path.suffix in {".gradle", ".kts", ".swift"}):
|
|
62
|
+
try:
|
|
63
|
+
if marker in path.read_text(encoding="utf-8", errors="ignore")[:20000]:
|
|
64
|
+
return True
|
|
65
|
+
except OSError:
|
|
66
|
+
continue
|
|
67
|
+
return False
|
profiles/registry.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Built-in VYRELON technology profile registry."""
|
|
2
|
+
|
|
3
|
+
from core.contracts.profile import ProfileSpec
|
|
4
|
+
from profiles.common import COMMON_ROLES
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
PROFILES = (
|
|
8
|
+
ProfileSpec(
|
|
9
|
+
id="react-native",
|
|
10
|
+
display_name="React Native",
|
|
11
|
+
detect_files=frozenset({"package.json"}),
|
|
12
|
+
detect_markers=frozenset({"react-native"}),
|
|
13
|
+
roles=COMMON_ROLES + (
|
|
14
|
+
"architect", "developer", "ui", "navigation", "state-management",
|
|
15
|
+
),
|
|
16
|
+
),
|
|
17
|
+
ProfileSpec(
|
|
18
|
+
id="android-native",
|
|
19
|
+
display_name="Android Native",
|
|
20
|
+
detect_files=frozenset({"settings.gradle", "settings.gradle.kts"}),
|
|
21
|
+
detect_markers=frozenset({"com.android.application", "com.android.library"}),
|
|
22
|
+
roles=COMMON_ROLES + (
|
|
23
|
+
"android-architect", "kotlin-developer", "jetpack-compose", "gradle",
|
|
24
|
+
),
|
|
25
|
+
),
|
|
26
|
+
ProfileSpec(
|
|
27
|
+
id="ios-native",
|
|
28
|
+
display_name="iOS Native",
|
|
29
|
+
detect_files=frozenset({"Package.swift"}),
|
|
30
|
+
detect_markers=frozenset({".xcodeproj", ".xcworkspace"}),
|
|
31
|
+
roles=COMMON_ROLES + (
|
|
32
|
+
"ios-architect", "swift-developer", "swiftui", "xcode",
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ProfileRegistry:
|
|
39
|
+
def __init__(self, profiles: tuple[ProfileSpec, ...] = PROFILES) -> None:
|
|
40
|
+
self._profiles = {profile.id: profile for profile in profiles}
|
|
41
|
+
|
|
42
|
+
def get(self, profile_id: str) -> ProfileSpec:
|
|
43
|
+
return self._profiles[profile_id]
|
|
44
|
+
|
|
45
|
+
def list(self) -> tuple[ProfileSpec, ...]:
|
|
46
|
+
return tuple(self._profiles.values())
|
profiles/resolver.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Resolve technology detections into stable VYRELON project and agent profiles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from agents.catalog import build_agent_catalog
|
|
8
|
+
from core.contracts.profile import AgentProfile, DetectionResult, ProjectProfile
|
|
9
|
+
from profiles.detector import ProfileDetector
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ProfileResolver:
|
|
13
|
+
"""Build a deterministic ProjectProfile and AgentProfile set for a project."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, detector: ProfileDetector | None = None) -> None:
|
|
16
|
+
self.detector = detector or ProfileDetector()
|
|
17
|
+
|
|
18
|
+
def resolve(self, project_root: Path) -> tuple[ProjectProfile, tuple[AgentProfile, ...]]:
|
|
19
|
+
detections = self.detector.detect(project_root)
|
|
20
|
+
return self.resolve_detections(project_root, detections)
|
|
21
|
+
|
|
22
|
+
def resolve_detections(
|
|
23
|
+
self,
|
|
24
|
+
project_root: Path,
|
|
25
|
+
detections: tuple[DetectionResult, ...],
|
|
26
|
+
) -> tuple[ProjectProfile, tuple[AgentProfile, ...]]:
|
|
27
|
+
profile_ids = tuple(result.profile_id for result in detections)
|
|
28
|
+
contracts = build_agent_catalog(profile_ids)
|
|
29
|
+
agents = tuple(
|
|
30
|
+
AgentProfile(
|
|
31
|
+
id=agent.id,
|
|
32
|
+
role=agent.role,
|
|
33
|
+
profile_ids=profile_ids,
|
|
34
|
+
capabilities=agent.capabilities,
|
|
35
|
+
tools=agent.tools,
|
|
36
|
+
permissions=agent.permissions,
|
|
37
|
+
model_ids=agent.model_ids,
|
|
38
|
+
metadata=dict(agent.metadata),
|
|
39
|
+
)
|
|
40
|
+
for agent in contracts
|
|
41
|
+
)
|
|
42
|
+
project = ProjectProfile(
|
|
43
|
+
id=self._project_id(project_root),
|
|
44
|
+
root=str(project_root),
|
|
45
|
+
technology_profile_ids=profile_ids,
|
|
46
|
+
agent_profile_ids=tuple(agent.id for agent in agents),
|
|
47
|
+
metadata={
|
|
48
|
+
"detection": [
|
|
49
|
+
{
|
|
50
|
+
"profile": result.profile_id,
|
|
51
|
+
"confidence": result.confidence,
|
|
52
|
+
"evidence": list(result.evidence),
|
|
53
|
+
}
|
|
54
|
+
for result in detections
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
)
|
|
58
|
+
return project, agents
|
|
59
|
+
|
|
60
|
+
@staticmethod
|
|
61
|
+
def _project_id(project_root: Path) -> str:
|
|
62
|
+
name = project_root.name.strip()
|
|
63
|
+
return name or "project"
|
runtime/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Agent runtime adapters."""
|
runtime/agent/ide.py
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""Agent execution helpers for IDE-originated coding work."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from core.contracts.agent import AgentContract
|
|
9
|
+
from core.contracts.execution import AgentExecutor
|
|
10
|
+
from core.contracts.work_unit import WorkUnit
|
|
11
|
+
from core.contracts.model_runtime import ModelResponse
|
|
12
|
+
from runtime.tool_calling import ToolRuntime
|
|
13
|
+
from runtime.policy import ExecutionPolicy
|
|
14
|
+
from runtime.validation import ValidationReport, ValidationRuntime, ValidationStep
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass
|
|
18
|
+
class IDECodingExecutor:
|
|
19
|
+
"""Execute a model request and optionally materialize its patch into the project."""
|
|
20
|
+
|
|
21
|
+
delegate: AgentExecutor
|
|
22
|
+
project_root: Path
|
|
23
|
+
apply_changes: bool = False
|
|
24
|
+
policy: ExecutionPolicy | None = None
|
|
25
|
+
tool_runtime: ToolRuntime | None = None
|
|
26
|
+
|
|
27
|
+
def execute(self, *, agent: AgentContract, model_id: str, work_unit: WorkUnit) -> object:
|
|
28
|
+
execute_with_tools = getattr(self.delegate, "execute_with_tools", None)
|
|
29
|
+
if self.tool_runtime is not None and callable(execute_with_tools):
|
|
30
|
+
execution = execute_with_tools(
|
|
31
|
+
agent=agent,
|
|
32
|
+
model_id=model_id,
|
|
33
|
+
work_unit=work_unit,
|
|
34
|
+
tool_runtime=self.tool_runtime,
|
|
35
|
+
approved=self.apply_changes,
|
|
36
|
+
)
|
|
37
|
+
output = execution.response
|
|
38
|
+
changed = any(
|
|
39
|
+
result.tool_id == "patch.apply" and result.ok
|
|
40
|
+
for result in execution.tool_results
|
|
41
|
+
)
|
|
42
|
+
work_unit.metadata["code_change"] = changed
|
|
43
|
+
work_unit.metadata["patch_applied"] = changed
|
|
44
|
+
return output
|
|
45
|
+
|
|
46
|
+
output = self.delegate.execute(agent=agent, model_id=model_id, work_unit=work_unit)
|
|
47
|
+
if not isinstance(output, ModelResponse):
|
|
48
|
+
return output
|
|
49
|
+
work_unit.metadata["code_change"] = False
|
|
50
|
+
return output
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class IDEValidationVerifier:
|
|
55
|
+
"""Validate an IDE-originated code change using VYRELON's local validation boundary."""
|
|
56
|
+
|
|
57
|
+
project_root: Path
|
|
58
|
+
commands: tuple[str, ...]
|
|
59
|
+
policy: ExecutionPolicy | None = None
|
|
60
|
+
|
|
61
|
+
def verify(self, *, work_unit: WorkUnit, output: object) -> bool:
|
|
62
|
+
if not self.commands:
|
|
63
|
+
work_unit.metadata["validation_skipped"] = True
|
|
64
|
+
return True
|
|
65
|
+
report: ValidationReport = ValidationRuntime(self.policy).run(
|
|
66
|
+
self.project_root,
|
|
67
|
+
(
|
|
68
|
+
ValidationStep(id=f"ide-validation-{index}", command=command)
|
|
69
|
+
for index, command in enumerate(self.commands, start=1)
|
|
70
|
+
),
|
|
71
|
+
)
|
|
72
|
+
work_unit.metadata["validation_passed"] = report.passed
|
|
73
|
+
work_unit.metadata["validation_evidence"] = report.evidence
|
|
74
|
+
return report.passed
|
runtime/agent/model.py
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"""Model-backed AgentExecutor for provider-neutral VYRELON agents."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from core.contracts.agent import AgentContract
|
|
6
|
+
from core.contracts.ai import ModelSpec
|
|
7
|
+
from core.contracts.execution import AgentExecutor
|
|
8
|
+
from core.contracts.model_runtime import ModelAdapter, ModelRequest, ModelResponse
|
|
9
|
+
from runtime.quota import QuotaIntelligence
|
|
10
|
+
from runtime.capability import CapabilityRegistry
|
|
11
|
+
from runtime.health import ModelHealthRegistry
|
|
12
|
+
from runtime.model_control import ModelControlPlane
|
|
13
|
+
from runtime.tool_calling import ToolCallingExecution, ToolCallingRuntime, ToolRuntime
|
|
14
|
+
from core.contracts.work_unit import WorkUnit
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ModelAgentExecutor(AgentExecutor):
|
|
18
|
+
"""Turn a WorkUnit into a model request and return the model response."""
|
|
19
|
+
|
|
20
|
+
def __init__(
|
|
21
|
+
self,
|
|
22
|
+
adapters: dict[str, ModelAdapter],
|
|
23
|
+
models: list[ModelSpec],
|
|
24
|
+
system_prompt: str | None = None,
|
|
25
|
+
fallback_model_ids: tuple[str, ...] = (),
|
|
26
|
+
quota_intelligence: QuotaIntelligence | None = None,
|
|
27
|
+
health_registry: ModelHealthRegistry | None = None,
|
|
28
|
+
model_control: ModelControlPlane | None = None,
|
|
29
|
+
capability_registry: CapabilityRegistry | None = None,
|
|
30
|
+
):
|
|
31
|
+
self.adapters = dict(adapters)
|
|
32
|
+
self.models = {model.id: model for model in models}
|
|
33
|
+
self.system_prompt = system_prompt
|
|
34
|
+
self.fallback_model_ids = tuple(fallback_model_ids)
|
|
35
|
+
self.quota_intelligence = quota_intelligence
|
|
36
|
+
self.health_registry = health_registry
|
|
37
|
+
self.model_control = model_control
|
|
38
|
+
self.capability_registry = capability_registry
|
|
39
|
+
|
|
40
|
+
def _candidate_model_ids(self, model_id: str) -> tuple[str, ...]:
|
|
41
|
+
return tuple(dict.fromkeys((model_id, *self.fallback_model_ids)))
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def _is_failover_error(exc: Exception) -> bool:
|
|
45
|
+
"""Return True for errors where another model/provider may succeed."""
|
|
46
|
+
status = getattr(exc, "status_code", getattr(exc, "status", None))
|
|
47
|
+
code = str(getattr(exc, "code", "")).lower()
|
|
48
|
+
message = str(exc).lower()
|
|
49
|
+
if status in {408, 429, 500, 502, 503, 504}:
|
|
50
|
+
return True
|
|
51
|
+
transient_codes = (
|
|
52
|
+
"rate_limit", "rate-limit", "quota", "resource_exhausted",
|
|
53
|
+
"too_many_requests", "temporarily_unavailable",
|
|
54
|
+
"service_unavailable", "unavailable", "overloaded", "timeout",
|
|
55
|
+
)
|
|
56
|
+
return any(token in code or token in message for token in transient_codes)
|
|
57
|
+
|
|
58
|
+
def execute(
|
|
59
|
+
self, *, agent: AgentContract, model_id: str, work_unit: WorkUnit
|
|
60
|
+
) -> ModelResponse:
|
|
61
|
+
attempts: list[str] = []
|
|
62
|
+
last_error: Exception | None = None
|
|
63
|
+
for candidate_id in self._candidate_model_ids(model_id):
|
|
64
|
+
if agent.model_ids and candidate_id not in agent.model_ids:
|
|
65
|
+
continue
|
|
66
|
+
try:
|
|
67
|
+
model = self.models[candidate_id]
|
|
68
|
+
adapter_id = str(model.metadata.get("adapter_id", model.provider_id))
|
|
69
|
+
adapter = self.adapters[adapter_id]
|
|
70
|
+
system = self.system_prompt or str(agent.metadata.get("system_prompt", "")) or None
|
|
71
|
+
request = ModelRequest(
|
|
72
|
+
prompt=work_unit.objective,
|
|
73
|
+
system=system,
|
|
74
|
+
metadata={"agent_id": agent.id, "work_unit_id": work_unit.id, "attempts": tuple(attempts)},
|
|
75
|
+
)
|
|
76
|
+
response = adapter.generate(model, request)
|
|
77
|
+
attempts.append(candidate_id)
|
|
78
|
+
metadata = dict(response.metadata)
|
|
79
|
+
metadata["attempts"] = tuple(attempts)
|
|
80
|
+
response = ModelResponse(
|
|
81
|
+
text=response.text,
|
|
82
|
+
model_id=response.model_id or candidate_id,
|
|
83
|
+
metadata=metadata,
|
|
84
|
+
)
|
|
85
|
+
work_unit.metadata["model_response"] = response.text
|
|
86
|
+
work_unit.metadata["model_id"] = response.model_id
|
|
87
|
+
work_unit.metadata["model_adapter"] = adapter_id
|
|
88
|
+
work_unit.metadata["model_attempts"] = tuple(attempts)
|
|
89
|
+
if self.capability_registry is not None:
|
|
90
|
+
self.capability_registry.observe_response(model, metadata)
|
|
91
|
+
if self.quota_intelligence is not None:
|
|
92
|
+
snapshot = self.quota_intelligence.observe_response(model, metadata)
|
|
93
|
+
work_unit.metadata["quota_snapshot"] = {
|
|
94
|
+
"confidence": snapshot.confidence.value,
|
|
95
|
+
"dimensions": {
|
|
96
|
+
item.name: {"remaining": item.remaining, "limit": item.limit}
|
|
97
|
+
for item in snapshot.dimensions
|
|
98
|
+
},
|
|
99
|
+
}
|
|
100
|
+
if self.model_control is not None:
|
|
101
|
+
self.model_control.record_success(model, metadata)
|
|
102
|
+
elif self.health_registry is not None:
|
|
103
|
+
self.health_registry.record_success(candidate_id, model.provider_id)
|
|
104
|
+
return response
|
|
105
|
+
except Exception as exc:
|
|
106
|
+
attempts.append(candidate_id)
|
|
107
|
+
last_error = exc
|
|
108
|
+
if self.model_control is not None and candidate_id in self.models:
|
|
109
|
+
self.model_control.record_failure(self.models[candidate_id], exc)
|
|
110
|
+
elif self.health_registry is not None and candidate_id in self.models:
|
|
111
|
+
self.health_registry.record_failure(candidate_id, self.models[candidate_id].provider_id, exc)
|
|
112
|
+
if not self._is_failover_error(exc):
|
|
113
|
+
raise
|
|
114
|
+
if last_error is not None:
|
|
115
|
+
raise last_error
|
|
116
|
+
raise LookupError(f"No executable model available for agent {agent.id}")
|
|
117
|
+
|
|
118
|
+
def execute_with_tools(
|
|
119
|
+
self,
|
|
120
|
+
*,
|
|
121
|
+
agent: AgentContract,
|
|
122
|
+
model_id: str,
|
|
123
|
+
work_unit: WorkUnit,
|
|
124
|
+
tool_runtime: ToolRuntime,
|
|
125
|
+
approved: bool = False,
|
|
126
|
+
) -> ToolCallingExecution:
|
|
127
|
+
"""Execute the selected model through Tool Calling with ordered fallback."""
|
|
128
|
+
attempts: list[str] = []
|
|
129
|
+
last_error: Exception | None = None
|
|
130
|
+
for candidate_id in self._candidate_model_ids(model_id):
|
|
131
|
+
if agent.model_ids and candidate_id not in agent.model_ids:
|
|
132
|
+
continue
|
|
133
|
+
try:
|
|
134
|
+
model = self.models.get(candidate_id)
|
|
135
|
+
if model is None:
|
|
136
|
+
raise LookupError(f"Model not registered: {candidate_id}")
|
|
137
|
+
adapter_id = str(model.metadata.get("adapter_id", model.provider_id))
|
|
138
|
+
adapter = self.adapters.get(adapter_id)
|
|
139
|
+
if adapter is None:
|
|
140
|
+
raise LookupError(f"Model adapter not registered: {adapter_id}")
|
|
141
|
+
request = ModelRequest(
|
|
142
|
+
prompt=work_unit.objective,
|
|
143
|
+
system=self.system_prompt or str(agent.metadata.get("system_prompt", "")) or None,
|
|
144
|
+
metadata={
|
|
145
|
+
"agent_id": agent.id,
|
|
146
|
+
"work_unit_id": work_unit.id,
|
|
147
|
+
"attempts": tuple(attempts),
|
|
148
|
+
},
|
|
149
|
+
)
|
|
150
|
+
runtime = ToolCallingRuntime(
|
|
151
|
+
models={candidate_id: model},
|
|
152
|
+
adapters={candidate_id: adapter},
|
|
153
|
+
tools=tool_runtime,
|
|
154
|
+
)
|
|
155
|
+
result = runtime.execute(
|
|
156
|
+
request,
|
|
157
|
+
model_id=candidate_id,
|
|
158
|
+
work_unit_id=work_unit.id,
|
|
159
|
+
granted_permissions=agent.permissions,
|
|
160
|
+
approved=approved,
|
|
161
|
+
)
|
|
162
|
+
attempts.append(candidate_id)
|
|
163
|
+
work_unit.metadata["model_response"] = result.response.text
|
|
164
|
+
work_unit.metadata["model_id"] = result.model_id
|
|
165
|
+
work_unit.metadata["model_adapter"] = adapter_id
|
|
166
|
+
work_unit.metadata["tool_rounds"] = result.rounds
|
|
167
|
+
work_unit.metadata["tool_results"] = tuple(result.tool_results)
|
|
168
|
+
work_unit.metadata["model_attempts"] = tuple(attempts)
|
|
169
|
+
if self.capability_registry is not None:
|
|
170
|
+
self.capability_registry.observe_response(model, dict(result.response.metadata))
|
|
171
|
+
if self.quota_intelligence is not None:
|
|
172
|
+
snapshot = self.quota_intelligence.observe_response(model, dict(result.response.metadata))
|
|
173
|
+
work_unit.metadata["quota_snapshot"] = {
|
|
174
|
+
"confidence": snapshot.confidence.value,
|
|
175
|
+
"dimensions": {
|
|
176
|
+
item.name: {"remaining": item.remaining, "limit": item.limit}
|
|
177
|
+
for item in snapshot.dimensions
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
if self.model_control is not None:
|
|
181
|
+
self.model_control.record_success(model, dict(result.response.metadata))
|
|
182
|
+
elif self.health_registry is not None:
|
|
183
|
+
self.health_registry.record_success(candidate_id, model.provider_id)
|
|
184
|
+
return result
|
|
185
|
+
except Exception as exc:
|
|
186
|
+
attempts.append(candidate_id)
|
|
187
|
+
last_error = exc
|
|
188
|
+
if self.model_control is not None and candidate_id in self.models:
|
|
189
|
+
self.model_control.record_failure(self.models[candidate_id], exc)
|
|
190
|
+
elif self.health_registry is not None and candidate_id in self.models:
|
|
191
|
+
self.health_registry.record_failure(candidate_id, self.models[candidate_id].provider_id, exc)
|
|
192
|
+
if not self._is_failover_error(exc):
|
|
193
|
+
raise
|
|
194
|
+
if last_error is not None:
|
|
195
|
+
raise last_error
|
|
196
|
+
raise LookupError(f"No executable tool-calling model available for agent {agent.id}")
|
|
197
|
+
|