agent-toolkit-cli 1.0.3__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.
Files changed (310) hide show
  1. agent_toolkit/__init__.py +4 -0
  2. agent_toolkit/__main__.py +3 -0
  3. agent_toolkit/_paths.py +64 -0
  4. agent_toolkit/cli/__init__.py +0 -0
  5. agent_toolkit/cli/doctor.py +453 -0
  6. agent_toolkit/cli/install.py +445 -0
  7. agent_toolkit/cli/main.py +66 -0
  8. agent_toolkit/cli/mcp.py +418 -0
  9. agent_toolkit/cli/plugin.py +213 -0
  10. agent_toolkit/cli/skills.py +421 -0
  11. agent_toolkit/loop/__init__.py +0 -0
  12. agent_toolkit/loop/gh_gate.py +626 -0
  13. agent_toolkit/loop/runner.py +1548 -0
  14. agent_toolkit/runner/__init__.py +0 -0
  15. agent_toolkit/runner/dispatcher.py +164 -0
  16. agent_toolkit/runner/policy.py +345 -0
  17. agent_toolkit/runner/providers/__init__.py +21 -0
  18. agent_toolkit/runner/providers/anthropic_provider.py +109 -0
  19. agent_toolkit/runner/providers/base.py +53 -0
  20. agent_toolkit/runner/providers/ollama_provider.py +108 -0
  21. agent_toolkit/runner/providers/openai_provider.py +105 -0
  22. agent_toolkit/runner/providers/opencode_provider.py +127 -0
  23. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/architect/AGENT.md +30 -0
  24. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/assistant/AGENT.md +59 -0
  25. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/build-error-resolver/AGENT.md +30 -0
  26. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/client-workflow-bootstrap/AGENT.md +60 -0
  27. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/code-reviewer/AGENT.md +49 -0
  28. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/database-reviewer/AGENT.md +44 -0
  29. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/docs-lookup/AGENT.md +28 -0
  30. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/e2e-runner/AGENT.md +38 -0
  31. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/performance-optimizer/AGENT.md +52 -0
  32. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/planner/AGENT.md +41 -0
  33. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/refactor-cleaner/AGENT.md +43 -0
  34. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/reference-lookup/AGENT.md +33 -0
  35. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/security-reviewer/AGENT.md +47 -0
  36. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/tdd-guide/AGENT.md +58 -0
  37. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/tech-assistant/AGENT.md +11 -0
  38. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/agents/typescript-reviewer/AGENT.md +61 -0
  39. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/agent-catalog.yaml +202 -0
  40. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/loop-catalog.yaml +165 -0
  41. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/skill-catalog.yaml +699 -0
  42. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/catalogs/skills-layout.json +337 -0
  43. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/changelog-drafter/loop.yaml +40 -0
  44. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/ci-sweeper/loop.yaml +53 -0
  45. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/daily-triage/loop.yaml +47 -0
  46. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/dep-sweeper/loop.yaml +46 -0
  47. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/issue-triage/loop.yaml +40 -0
  48. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-daily-briefing/loop.yaml +65 -0
  49. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-pr-monitor/loop.yaml +85 -0
  50. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/oss-triage/loop.yaml +67 -0
  51. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/post-merge-cleanup/loop.yaml +44 -0
  52. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/loops/pr-babysitter/loop.yaml +46 -0
  53. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/README.md +45 -0
  54. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/config.template.json +7 -0
  55. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/clickup/wrapper.sh +23 -0
  56. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/figma/README.md +56 -0
  57. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/figma/config.template.json +9 -0
  58. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/README.md +11 -0
  59. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/config.template.json +7 -0
  60. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/github/wrapper.sh +23 -0
  61. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/linear/README.md +49 -0
  62. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/linear/config.template.json +10 -0
  63. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/README.md +7 -0
  64. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/config.template.json +7 -0
  65. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/notion/wrapper.sh +23 -0
  66. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/README.md +8 -0
  67. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/config.template.json +8 -0
  68. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/mcp/templates/slack/wrapper.sh +23 -0
  69. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/CLAUDE.md +66 -0
  70. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/assistant.md +59 -0
  71. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/build-error-resolver.md +30 -0
  72. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/client-workflow-bootstrap.md +60 -0
  73. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/contribution-planner.md +39 -0
  74. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/database-reviewer.md +44 -0
  75. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/docs-lookup.md +28 -0
  76. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/e2e-runner.md +38 -0
  77. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/performance-optimizer.md +52 -0
  78. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/planner.md +41 -0
  79. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/refactor-cleaner.md +43 -0
  80. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/reference-lookup.md +33 -0
  81. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/security-reviewer.md +47 -0
  82. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/tdd-guide.md +58 -0
  83. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/agents/typescript-reviewer.md +61 -0
  84. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/claude-code/settings.json +87 -0
  85. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/copilot/copilot-instructions.md +15 -0
  86. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/README.md +33 -0
  87. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/architect.mdc +23 -0
  88. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/assistant.mdc +25 -0
  89. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/build-error-resolver.mdc +20 -0
  90. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/code-reviewer.mdc +21 -0
  91. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/database-reviewer.mdc +29 -0
  92. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/docs-lookup.mdc +15 -0
  93. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/e2e-runner.mdc +30 -0
  94. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/performance-optimizer.mdc +27 -0
  95. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/planner.mdc +28 -0
  96. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/refactor-cleaner.mdc +26 -0
  97. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/reference-lookup.mdc +20 -0
  98. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/security-reviewer.mdc +20 -0
  99. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/tdd-guide.mdc +26 -0
  100. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/cursor/rules/typescript-reviewer.mdc +28 -0
  101. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/architect.md +30 -0
  102. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/assistant.md +52 -0
  103. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/build-error-resolver.md +31 -0
  104. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/client-workflow-bootstrap.md +66 -0
  105. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/code-reviewer.md +47 -0
  106. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/contribution-planner.md +44 -0
  107. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/database-reviewer.md +43 -0
  108. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/docs-lookup.md +28 -0
  109. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/e2e-runner.md +33 -0
  110. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/performance-optimizer.md +34 -0
  111. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/planner.md +27 -0
  112. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/refactor-cleaner.md +27 -0
  113. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/reference-lookup.md +27 -0
  114. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/security-reviewer.md +27 -0
  115. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/tdd-guide.md +27 -0
  116. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/agents/typescript-reviewer.md +30 -0
  117. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/opencode/opencode.json +37 -0
  118. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/architect/skill.md +5 -0
  119. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/assistant/skill.md +3 -0
  120. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/code-reviewer/skill.md +5 -0
  121. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/planner/skill.md +3 -0
  122. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/pi/skills/security-reviewer/skill.md +3 -0
  123. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/memories/global_rules.md +74 -0
  124. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/architect.mdc +23 -0
  125. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/build-error-resolver.mdc +20 -0
  126. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/code-reviewer.mdc +21 -0
  127. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/database-reviewer.mdc +29 -0
  128. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/docs-lookup.mdc +15 -0
  129. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/e2e-runner.mdc +30 -0
  130. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/performance-optimizer.mdc +27 -0
  131. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/planner.mdc +28 -0
  132. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/refactor-cleaner.mdc +26 -0
  133. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/security-reviewer.mdc +20 -0
  134. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/tdd-guide.mdc +26 -0
  135. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/profiles/windsurf/rules/typescript-reviewer.mdc +28 -0
  136. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/SKILL.md +213 -0
  137. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/AGENTS_TEMPLATE.md +0 -0
  138. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/ORCHESTRATION.md +0 -0
  139. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/assistant/references/REPO_INSPECTION.md +0 -0
  140. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/dev-companion/SKILL.md +65 -0
  141. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/dev-companion/references/LOOP_GUARDRAILS.md +0 -0
  142. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/onboarding/SKILL.md +119 -0
  143. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/output-handshake/SKILL.md +24 -0
  144. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/pr-fallback/SKILL.md +33 -0
  145. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/pr-fallback/references/pr-body-default.md +0 -0
  146. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/core/workspace-knowledge-sync/SKILL.md +141 -0
  147. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/data/dbt-validation/SKILL.md +41 -0
  148. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/data/snowflake-validation/SKILL.md +38 -0
  149. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/SKILL.md +46 -0
  150. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/references/default-template.md +0 -0
  151. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/adr/references/example-001-graphql-adoption.md +66 -0
  152. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/SKILL.md +23 -0
  153. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/references/default-template.md +0 -0
  154. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/agreement/references/example-api-versioning.md +29 -0
  155. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/SKILL.md +25 -0
  156. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/references/default-template.md +0 -0
  157. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/bug/references/example-search-filter-bug.md +58 -0
  158. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/SKILL.md +27 -0
  159. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/references/default-template.md +0 -0
  160. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/decision-log/references/example-repository-pattern.md +27 -0
  161. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/SKILL.md +33 -0
  162. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/references/default-template.md +0 -0
  163. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/development-workflow/references/default-workflow-checklist.md +44 -0
  164. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/SKILL.md +21 -0
  165. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/references/default-template.md +0 -0
  166. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/epic/references/example-unified-dashboard.md +40 -0
  167. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/SKILL.md +23 -0
  168. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/references/default-template.md +0 -0
  169. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/incident/references/example-payment-outage.md +62 -0
  170. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/SKILL.md +105 -0
  171. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/references/default-template.md +0 -0
  172. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/management-unit-assessment/references/example-team-assessment.md +126 -0
  173. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/SKILL.md +24 -0
  174. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/references/default-template.md +0 -0
  175. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/meeting-minutes/references/example-weekly-sync.md +72 -0
  176. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/SKILL.md +30 -0
  177. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/references/default-template.md +0 -0
  178. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/planning/references/example-sprint-planning.md +62 -0
  179. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/SKILL.md +44 -0
  180. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/references/default-template.md +0 -0
  181. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/prd/references/example-unified-api.md +71 -0
  182. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/SKILL.md +90 -0
  183. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/references/default-template.md +0 -0
  184. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment/references/example-platform-assessment.md +122 -0
  185. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/SKILL.md +88 -0
  186. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/references/default-template.md +0 -0
  187. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/project-assessment-evidence/references/example-evidence-map.md +46 -0
  188. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/SKILL.md +23 -0
  189. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/references/default-template.md +0 -0
  190. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/spike/references/example-graphql-federation.md +79 -0
  191. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/SKILL.md +20 -0
  192. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/references/default-template.md +0 -0
  193. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/task/references/example-nav-system.md +33 -0
  194. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/SKILL.md +58 -0
  195. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/default-template.md +0 -0
  196. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/example-frontend-assessment.md +112 -0
  197. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/technical-unit-assessment/references/indicator-groups.md +65 -0
  198. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/SKILL.md +47 -0
  199. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/references/default-template.md +0 -0
  200. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/trd/references/example-api-migration.md +122 -0
  201. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/SKILL.md +20 -0
  202. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/references/default-template.md +0 -0
  203. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/user-story/references/example-advanced-filtering.md +37 -0
  204. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/SKILL.md +30 -0
  205. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/references/default-template.md +0 -0
  206. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/work-item/references/example-routing-dashboard.md +23 -0
  207. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-client-bootstrap/SKILL.md +148 -0
  208. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-client-bootstrap/questions.yaml +165 -0
  209. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/delivery/workflow-generic-project/SKILL.md +78 -0
  210. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/LICENSE.txt +2 -0
  211. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/NOTICE.txt +25 -0
  212. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/SKILL.md +95 -0
  213. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/references/figma-mcp-config.md +82 -0
  214. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma/references/figma-tools-and-prompts.md +34 -0
  215. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/LICENSE.txt +2 -0
  216. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/NOTICE.txt +18 -0
  217. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/SKILL.md +350 -0
  218. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/references/mapping-checklist.md +7 -0
  219. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-code-connect-components/scripts/normalize_node_id.py +25 -0
  220. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/LICENSE.txt +2 -0
  221. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/NOTICE.txt +19 -0
  222. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/SKILL.md +550 -0
  223. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/references/rule-template.md +15 -0
  224. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -0
  225. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/LICENSE.txt +2 -0
  226. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/NOTICE.txt +17 -0
  227. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-create-new-file/SKILL.md +69 -0
  228. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/LICENSE.txt +2 -0
  229. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/NOTICE.txt +19 -0
  230. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/figma-implement-design/SKILL.md +264 -0
  231. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/SKILL.md +60 -0
  232. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/charts.csv +26 -0
  233. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/colors.csv +97 -0
  234. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/icons.csv +101 -0
  235. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/landing.csv +31 -0
  236. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/products.csv +97 -0
  237. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/react-performance.csv +45 -0
  238. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  239. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  240. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  241. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  242. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  243. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  244. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  245. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  246. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/react.csv +54 -0
  247. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  248. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  249. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  250. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  251. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/styles.csv +68 -0
  252. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/typography.csv +58 -0
  253. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  254. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  255. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/data/web-interface.csv +31 -0
  256. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/pre-delivery-checklist.md +39 -0
  257. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/search-reference.md +44 -0
  258. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/references/ui-rules.md +35 -0
  259. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/core.py +253 -0
  260. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/design_system.py +1067 -0
  261. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/design/ui-ux-pro-max/scripts/search.py +114 -0
  262. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/LICENSE.txt +202 -0
  263. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/NOTICE.txt +20 -0
  264. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/SKILL.md +69 -0
  265. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-address-comments/scripts/fetch_comments.py +237 -0
  266. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-contribution-planner/SKILL.md +157 -0
  267. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-contribution-planner/scripts/inspect_contributions.py +800 -0
  268. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/LICENSE.txt +201 -0
  269. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/NOTICE.txt +20 -0
  270. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/SKILL.md +71 -0
  271. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gh-fix-ci/scripts/inspect_pr_checks.py +509 -0
  272. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/github-cli-workflow/SKILL.md +49 -0
  273. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/gitlab-cli-workflow/SKILL.md +44 -0
  274. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/workflow-client-bootstrap/SKILL.md +14 -0
  275. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/forge/workflow-generic-project/SKILL.md +14 -0
  276. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/SKILL.md +75 -0
  277. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/docs-management.md +57 -0
  278. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/task-management.md +131 -0
  279. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/clickup-cli/references/time-tracking.md +38 -0
  280. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/LICENSE.txt +202 -0
  281. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/NOTICE.txt +23 -0
  282. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/linear/SKILL.md +131 -0
  283. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-assistant/SKILL.md +134 -0
  284. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-cli/SKILL.md +105 -0
  285. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/integrations/slack-cli/references/INSTALLATION.md +42 -0
  286. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/loops/loop-runner/SKILL.md +90 -0
  287. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/docs-generator/SKILL.md +81 -0
  288. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/llm-cost-advisor/SKILL.md +83 -0
  289. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/ops/triage/SKILL.md +117 -0
  290. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/LICENSE.txt +201 -0
  291. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/NOTICE.txt +27 -0
  292. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/SKILL.md +142 -0
  293. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/assets/experiment-template.ipynb +110 -0
  294. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/assets/tutorial-template.ipynb +107 -0
  295. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/experiment-patterns.md +10 -0
  296. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/notebook-structure.md +17 -0
  297. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/quality-checklist.md +11 -0
  298. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/references/tutorial-patterns.md +9 -0
  299. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/jupyter-notebook/scripts/new_notebook.py +130 -0
  300. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/LICENSE.txt +201 -0
  301. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/NOTICE.txt +29 -0
  302. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/SKILL.md +151 -0
  303. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/references/cli.md +116 -0
  304. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/references/workflows.md +98 -0
  305. agent_toolkit_cli-1.0.3.data/data/agent_toolkit/data/skills/tooling/playwright-cli/scripts/executable_playwright_cli.sh +25 -0
  306. agent_toolkit_cli-1.0.3.dist-info/METADATA +411 -0
  307. agent_toolkit_cli-1.0.3.dist-info/RECORD +310 -0
  308. agent_toolkit_cli-1.0.3.dist-info/WHEEL +4 -0
  309. agent_toolkit_cli-1.0.3.dist-info/entry_points.txt +2 -0
  310. agent_toolkit_cli-1.0.3.dist-info/licenses/LICENSE +21 -0
File without changes
@@ -0,0 +1,164 @@
1
+ """LLM dispatcher for the dev-companion runner.
2
+
3
+ Selects the best available LLM provider, constrained by an :class:`LLMPolicy`
4
+ that captures client-driven privacy/billing requirements (allowlist, denylist,
5
+ pinned provider/model, fail-closed ``strict`` mode).
6
+
7
+ When no policy is supplied, behaviour is backwards-compatible: providers are
8
+ ordered by their hard-coded ``get_priority()`` and the first available one is
9
+ selected.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import logging
15
+ import os
16
+ from pathlib import Path
17
+ from typing import Optional
18
+
19
+ import sys
20
+ from pathlib import Path as _Path
21
+
22
+ sys.path.insert(0, str(_Path(__file__).parent))
23
+
24
+ from policy import LLMPolicy
25
+ from providers import (
26
+ AnthropicProvider,
27
+ LLMProvider,
28
+ LLMResponse,
29
+ OllamaProvider,
30
+ OpenAIProvider,
31
+ OpenCodeProvider,
32
+ )
33
+
34
+ logger = logging.getLogger(__name__)
35
+
36
+
37
+ class LLMDispatcher:
38
+ """Pick a provider that satisfies the active :class:`LLMPolicy`.
39
+
40
+ The dispatcher never silently falls back to a denied provider: if the
41
+ policy filters every provider out and ``strict`` is set, the caller gets
42
+ an explicit ``policy_no_provider_available`` error. Non-strict mode keeps
43
+ the previous behaviour (returns ``None``; caller can use a skeleton plan).
44
+ """
45
+
46
+ POLICY_VIOLATION = "policy_no_provider_available"
47
+
48
+ def __init__(self, policy: LLMPolicy | None = None) -> None:
49
+ self._policy: LLMPolicy = policy or LLMPolicy.empty()
50
+ self._providers: list[LLMProvider] = []
51
+ self._candidates: list[LLMProvider] = []
52
+ self._selected: Optional[LLMProvider] = None
53
+ self._initialize_providers()
54
+
55
+ @property
56
+ def policy(self) -> LLMPolicy:
57
+ return self._policy
58
+
59
+ def _initialize_providers(self) -> None:
60
+ all_providers: list[LLMProvider] = [
61
+ OpenCodeProvider(),
62
+ OllamaProvider(),
63
+ AnthropicProvider(),
64
+ OpenAIProvider(),
65
+ ]
66
+ # Stable hard-coded ordering for the unfiltered case.
67
+ all_providers.sort(key=lambda p: p.get_priority())
68
+ self._providers = all_providers
69
+ self._candidates = self._policy.filter(all_providers)
70
+
71
+ def list_candidates(self) -> list[dict]:
72
+ """Detailed status for every candidate after policy filtering, without
73
+ executing the model. Used by the ``llm-status`` diagnostic."""
74
+ return [
75
+ {
76
+ "name": p.name,
77
+ "model": p.get_model_name(),
78
+ "available": p.is_available(),
79
+ "is_local": getattr(p, "is_local", False),
80
+ "is_free": getattr(p, "is_free", False),
81
+ "priority": p.get_priority(),
82
+ }
83
+ for p in self._candidates
84
+ ]
85
+
86
+ def list_all_providers(self) -> list[dict]:
87
+ """Status for every known provider, regardless of policy. Useful for
88
+ operators who need to see what was filtered out and why."""
89
+ candidate_names = {p.name for p in self._candidates}
90
+ return [
91
+ {
92
+ "name": p.name,
93
+ "model": p.get_model_name(),
94
+ "available": p.is_available(),
95
+ "is_local": getattr(p, "is_local", False),
96
+ "is_free": getattr(p, "is_free", False),
97
+ "priority": p.get_priority(),
98
+ "in_policy": p.name in candidate_names,
99
+ }
100
+ for p in self._providers
101
+ ]
102
+
103
+ def get_available_provider(self) -> Optional[LLMProvider]:
104
+ if not self._candidates:
105
+ logger.warning(
106
+ "LLM policy filtered out every provider (allowlist=%s, deny=%s, pinned=%s)",
107
+ list(self._policy.allowlist) if self._policy.allowlist else None,
108
+ list(self._policy.denylist),
109
+ self._policy.pinned_provider,
110
+ )
111
+ return None
112
+ for provider in self._candidates:
113
+ if provider.is_available():
114
+ logger.info(
115
+ "Selected provider: %s (model: %s)",
116
+ provider.name,
117
+ provider.get_model_name(),
118
+ )
119
+ self._selected = provider
120
+ return provider
121
+ logger.warning(
122
+ "No allowed LLM provider is available (strict=%s)",
123
+ self._policy.strict,
124
+ )
125
+ return None
126
+
127
+ def get_selected(self) -> Optional[LLMProvider]:
128
+ return self._selected
129
+
130
+ def list_providers(self) -> list[dict]:
131
+ # Backwards-compatible alias used by ``dots_ai_devcompanion_runner``.
132
+ return self.list_candidates() or self.list_all_providers()
133
+
134
+ def generate(
135
+ self,
136
+ prompt: str,
137
+ system_prompt: Optional[str] = None,
138
+ repo_path: Optional[Path] = None,
139
+ timeout_sec: int = 300,
140
+ ) -> tuple[Optional[LLMResponse], Optional[str]]:
141
+ provider = self.get_selected()
142
+ if not provider:
143
+ if self._policy.strict:
144
+ return None, self.POLICY_VIOLATION
145
+ return None, "no_provider"
146
+
147
+ try:
148
+ response = provider.generate(
149
+ prompt=prompt,
150
+ system_prompt=system_prompt,
151
+ repo_path=repo_path,
152
+ timeout_sec=timeout_sec,
153
+ )
154
+ return response, None
155
+ except Exception as exc: # pragma: no cover - safety net
156
+ logger.error("Provider %s failed: %s", provider.name, exc)
157
+ return None, str(exc)
158
+
159
+
160
+ def create_dispatcher(policy: LLMPolicy | None = None) -> LLMDispatcher:
161
+ debug = os.environ.get("DOTS_WORKSTATION_LLM_DEBUG", "").lower() in ("1", "true", "yes", "on")
162
+ if debug:
163
+ logging.basicConfig(level=logging.DEBUG)
164
+ return LLMDispatcher(policy=policy)
@@ -0,0 +1,345 @@
1
+ """LLM execution policy for the agent-toolkit dev-companion runner.
2
+
3
+ Defines which LLM providers are allowed to run, in what order, and whether
4
+ the runner is required to fail closed when no allowed provider is available
5
+ (for client engagements that mandate a single billing/data identity).
6
+
7
+ Policy sources, in order of precedence — each layer can only RESTRICT the
8
+ prior one, never widen it:
9
+
10
+ 1. Global environment variables (machine baseline / engagement env file).
11
+ 2. Optional JSON config file at ``~/.config/agent-toolkit/devcompanion-llm.json``
12
+ (path overridable with ``DOTS_WORKSTATION_DEVCOMPANION_LLM_CONFIG``).
13
+ 3. Per-job ``llm`` object inside the ``.job`` JSON.
14
+
15
+ A job may further restrict (subset of ``allowlist``, additional ``denylist``
16
+ entries, ``strict: true``) but cannot expand the global allowlist or relax
17
+ strict mode that was set globally.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import json
23
+ import logging
24
+ import os
25
+ from dataclasses import dataclass, field
26
+ from pathlib import Path
27
+ from typing import Any, Iterable, Mapping
28
+
29
+ logger = logging.getLogger(__name__)
30
+
31
+ KNOWN_PROVIDERS: tuple[str, ...] = ("opencode", "ollama", "anthropic", "openai")
32
+ DEFAULT_CONFIG_PATH = Path.home() / ".config" / "agent-toolkit" / "devcompanion-llm.json"
33
+
34
+
35
+ class PolicyError(ValueError):
36
+ """Raised when policy values are inconsistent (for example a job tries to widen
37
+ the globally allowed set, or a pinned provider is denied)."""
38
+
39
+
40
+ def _truthy(value: Any) -> bool:
41
+ if isinstance(value, bool):
42
+ return value
43
+ if value is None:
44
+ return False
45
+ return str(value).strip().lower() in ("1", "true", "yes", "on")
46
+
47
+
48
+ def _split_list(value: Any) -> tuple[str, ...]:
49
+ if value is None:
50
+ return ()
51
+ if isinstance(value, str):
52
+ items: list[str] = [s.strip() for s in value.split(",")]
53
+ elif isinstance(value, Iterable) and not isinstance(value, (bytes, bytearray)):
54
+ items = [str(s).strip() for s in value]
55
+ else:
56
+ return ()
57
+ return tuple(item.lower() for item in items if item)
58
+
59
+
60
+ def _normalize_name(name: Any) -> str | None:
61
+ if name is None:
62
+ return None
63
+ text = str(name).strip().lower()
64
+ return text or None
65
+
66
+
67
+ @dataclass(frozen=True)
68
+ class LLMPolicy:
69
+ """Effective execution policy for the LLM dispatcher.
70
+
71
+ ``allowlist`` preserves order: when set, the dispatcher keeps providers in
72
+ that order rather than the implementation's hard-coded priority. This lets
73
+ operators express "prefer Anthropic first, then OpenAI" explicitly.
74
+
75
+ ``sources`` is for audit only; it lists which layers contributed to the
76
+ effective policy (``env``, ``file``, ``job``).
77
+ """
78
+
79
+ allowlist: tuple[str, ...] | None = None
80
+ denylist: tuple[str, ...] = ()
81
+ pinned_provider: str | None = None
82
+ pinned_model: str | None = None
83
+ strict: bool = False
84
+ sources: tuple[str, ...] = ()
85
+ warnings: tuple[str, ...] = field(default_factory=tuple)
86
+
87
+ # ── loaders ────────────────────────────────────────────────────────────
88
+ @classmethod
89
+ def empty(cls) -> "LLMPolicy":
90
+ return cls()
91
+
92
+ @classmethod
93
+ def from_env(cls, env: Mapping[str, str] | None = None) -> "LLMPolicy":
94
+ env = os.environ if env is None else env
95
+ allow = _split_list(env.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_ALLOWLIST"))
96
+ deny = _split_list(env.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_DENYLIST"))
97
+ pinned = _normalize_name(env.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_PINNED_PROVIDER"))
98
+ pinned_model_raw = env.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_PINNED_MODEL")
99
+ pinned_model = (
100
+ pinned_model_raw.strip() if isinstance(pinned_model_raw, str) and pinned_model_raw.strip() else None
101
+ )
102
+ strict = _truthy(env.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_STRICT"))
103
+
104
+ warnings = list(_unknown_warnings("env", allow, deny, pinned))
105
+ sources = ("env",) if (allow or deny or pinned or pinned_model or strict) else ()
106
+ return cls(
107
+ allowlist=allow or None,
108
+ denylist=deny,
109
+ pinned_provider=pinned,
110
+ pinned_model=pinned_model,
111
+ strict=strict,
112
+ sources=sources,
113
+ warnings=tuple(warnings),
114
+ )
115
+
116
+ @classmethod
117
+ def from_file(cls, path: Path | str | None = None) -> "LLMPolicy":
118
+ env_override = os.environ.get("DOTS_WORKSTATION_DEVCOMPANION_LLM_CONFIG")
119
+ if path is None:
120
+ path = Path(env_override) if env_override else DEFAULT_CONFIG_PATH
121
+ path = Path(path).expanduser()
122
+ if not path.is_file():
123
+ return cls.empty()
124
+
125
+ try:
126
+ data = json.loads(path.read_text(encoding="utf-8"))
127
+ except Exception as exc:
128
+ return cls(
129
+ warnings=(f"failed to parse policy file {path}: {exc}",),
130
+ )
131
+
132
+ if not isinstance(data, Mapping):
133
+ return cls(
134
+ warnings=(f"policy file {path} must contain a JSON object",),
135
+ )
136
+
137
+ allow = _split_list(data.get("allowlist"))
138
+ deny = _split_list(data.get("denylist"))
139
+ pinned = _normalize_name(data.get("pinned_provider") or data.get("provider"))
140
+ pinned_model = data.get("pinned_model") or data.get("model")
141
+ if isinstance(pinned_model, str):
142
+ pinned_model = pinned_model.strip() or None
143
+ else:
144
+ pinned_model = None
145
+ strict = _truthy(data.get("strict"))
146
+ warnings = list(_unknown_warnings(f"file {path}", allow, deny, pinned))
147
+ sources = (f"file:{path}",) if (allow or deny or pinned or pinned_model or strict) else ()
148
+ return cls(
149
+ allowlist=allow or None,
150
+ denylist=deny,
151
+ pinned_provider=pinned,
152
+ pinned_model=pinned_model,
153
+ strict=strict,
154
+ sources=sources,
155
+ warnings=tuple(warnings),
156
+ )
157
+
158
+ @classmethod
159
+ def from_job(cls, job_llm: Any) -> "LLMPolicy":
160
+ if job_llm is None or isinstance(job_llm, bool):
161
+ return cls.empty()
162
+ if not isinstance(job_llm, Mapping):
163
+ return cls.empty()
164
+
165
+ allow = _split_list(job_llm.get("allowlist"))
166
+ deny = _split_list(job_llm.get("denylist"))
167
+ pinned = _normalize_name(job_llm.get("provider") or job_llm.get("pinned_provider"))
168
+ pinned_model = job_llm.get("model") or job_llm.get("pinned_model")
169
+ if isinstance(pinned_model, str):
170
+ pinned_model = pinned_model.strip() or None
171
+ else:
172
+ pinned_model = None
173
+ strict = _truthy(job_llm.get("strict"))
174
+ warnings = list(_unknown_warnings("job", allow, deny, pinned))
175
+ sources = ("job",) if (allow or deny or pinned or pinned_model or strict) else ()
176
+ return cls(
177
+ allowlist=allow or None,
178
+ denylist=deny,
179
+ pinned_provider=pinned,
180
+ pinned_model=pinned_model,
181
+ strict=strict,
182
+ sources=sources,
183
+ warnings=tuple(warnings),
184
+ )
185
+
186
+ @classmethod
187
+ def load(
188
+ cls,
189
+ *,
190
+ env: Mapping[str, str] | None = None,
191
+ config_path: Path | str | None = None,
192
+ job_llm: Any | None = None,
193
+ ) -> "LLMPolicy":
194
+ """Compose ``env`` → ``file`` → ``job`` and validate that later layers only
195
+ restrict (never widen) earlier ones. Raises :class:`PolicyError` when a job
196
+ tries to escape the global allowlist."""
197
+ base = merge_policies(cls.from_env(env), cls.from_file(config_path))
198
+ if job_llm is None:
199
+ return base
200
+ job = cls.from_job(job_llm)
201
+ return merge_policies(base, job, _validate_restriction=True)
202
+
203
+ # ── filtering ──────────────────────────────────────────────────────────
204
+ def filter(self, providers: Iterable[Any]) -> list[Any]:
205
+ """Return providers permitted by the policy, ordered by preference.
206
+
207
+ Mutates the ``model`` attribute on a pinned provider when ``pinned_model``
208
+ is set, so the caller can use the pinned model without changing the
209
+ provider classes.
210
+ """
211
+ by_name: dict[str, Any] = {}
212
+ for p in providers:
213
+ name = _provider_name(p)
214
+ if name:
215
+ by_name[name] = p
216
+
217
+ if self.pinned_provider:
218
+ if self.pinned_provider in self.denylist:
219
+ return []
220
+ provider = by_name.get(self.pinned_provider)
221
+ if provider is None:
222
+ return []
223
+ if self.pinned_model and hasattr(provider, "model"):
224
+ try:
225
+ setattr(provider, "model", self.pinned_model)
226
+ except Exception:
227
+ logger.debug("Could not set pinned model on provider %s", self.pinned_provider)
228
+ return [provider]
229
+
230
+ denied = set(self.denylist)
231
+ if self.allowlist:
232
+ ordered: list[Any] = []
233
+ for name in self.allowlist:
234
+ if name in denied:
235
+ continue
236
+ provider = by_name.get(name)
237
+ if provider is not None:
238
+ ordered.append(provider)
239
+ return ordered
240
+
241
+ sorted_providers = sorted(by_name.values(), key=lambda p: getattr(p, "get_priority", lambda: 100)())
242
+ return [p for p in sorted_providers if _provider_name(p) not in denied]
243
+
244
+ # ── audit ──────────────────────────────────────────────────────────────
245
+ def to_audit(self) -> dict[str, Any]:
246
+ return {
247
+ "allowlist": list(self.allowlist) if self.allowlist else None,
248
+ "denylist": list(self.denylist),
249
+ "pinned_provider": self.pinned_provider,
250
+ "pinned_model": self.pinned_model,
251
+ "strict": self.strict,
252
+ "sources": list(self.sources),
253
+ "warnings": list(self.warnings),
254
+ }
255
+
256
+
257
+ def _provider_name(provider: Any) -> str:
258
+ return str(getattr(provider, "name", "")).strip().lower()
259
+
260
+
261
+ def _unknown_warnings(
262
+ layer: str,
263
+ allow: tuple[str, ...],
264
+ deny: tuple[str, ...],
265
+ pinned: str | None,
266
+ ) -> Iterable[str]:
267
+ for name in allow:
268
+ if name not in KNOWN_PROVIDERS:
269
+ yield f"{layer}: allowlist contains unknown provider '{name}'"
270
+ for name in deny:
271
+ if name not in KNOWN_PROVIDERS:
272
+ yield f"{layer}: denylist contains unknown provider '{name}'"
273
+ if pinned and pinned not in KNOWN_PROVIDERS:
274
+ yield f"{layer}: pinned provider '{pinned}' is unknown"
275
+
276
+
277
+ def merge_policies(
278
+ base: LLMPolicy,
279
+ overlay: LLMPolicy,
280
+ *,
281
+ _validate_restriction: bool = False,
282
+ ) -> LLMPolicy:
283
+ """Merge ``overlay`` on top of ``base``.
284
+
285
+ When ``_validate_restriction`` is true (job over global), ``overlay`` may only
286
+ restrict ``base``. Attempting to widen raises :class:`PolicyError`.
287
+ """
288
+ # Allowlist
289
+ if overlay.allowlist is None:
290
+ merged_allow = base.allowlist
291
+ elif base.allowlist is None:
292
+ merged_allow = overlay.allowlist
293
+ else:
294
+ if _validate_restriction:
295
+ extras = [name for name in overlay.allowlist if name not in base.allowlist]
296
+ if extras:
297
+ raise PolicyError(
298
+ "job allowlist tries to add provider(s) not allowed globally: "
299
+ + ", ".join(extras)
300
+ )
301
+ # Keep overlay order, but only entries also in base.
302
+ merged_allow = tuple(name for name in overlay.allowlist if name in base.allowlist)
303
+ if not merged_allow:
304
+ raise PolicyError(
305
+ "job allowlist is empty after intersecting with global allowlist"
306
+ )
307
+
308
+ # Denylist (always additive)
309
+ merged_deny = tuple(sorted(set(base.denylist) | set(overlay.denylist)))
310
+
311
+ # Pinned provider/model
312
+ merged_pin_provider = overlay.pinned_provider or base.pinned_provider
313
+ merged_pin_model = overlay.pinned_model or base.pinned_model
314
+
315
+ if _validate_restriction and overlay.pinned_provider:
316
+ if base.allowlist and overlay.pinned_provider not in base.allowlist:
317
+ raise PolicyError(
318
+ f"job pins provider '{overlay.pinned_provider}' but it is not in the global allowlist"
319
+ )
320
+ if overlay.pinned_provider in merged_deny:
321
+ raise PolicyError(
322
+ f"job pins provider '{overlay.pinned_provider}' but it is denied by policy"
323
+ )
324
+
325
+ # Strict can only escalate (False -> True). A job cannot lower a globally-strict policy.
326
+ merged_strict = base.strict or overlay.strict
327
+ if _validate_restriction and base.strict and overlay.strict is False and "job" in overlay.sources:
328
+ # Job explicitly set strict=false but base is strict: warn, keep True.
329
+ warnings = list(base.warnings) + list(overlay.warnings) + [
330
+ "job tried to set strict=false while global policy is strict; keeping strict=true",
331
+ ]
332
+ else:
333
+ warnings = list(base.warnings) + list(overlay.warnings)
334
+
335
+ sources = tuple(dict.fromkeys(list(base.sources) + list(overlay.sources)))
336
+
337
+ return LLMPolicy(
338
+ allowlist=merged_allow,
339
+ denylist=merged_deny,
340
+ pinned_provider=merged_pin_provider,
341
+ pinned_model=merged_pin_model,
342
+ strict=merged_strict,
343
+ sources=sources,
344
+ warnings=tuple(warnings),
345
+ )
@@ -0,0 +1,21 @@
1
+ """
2
+ agent-toolkit dev-companion LLM providers.
3
+
4
+ Provider-agnostic abstraction layer for LLM generation.
5
+ Supports local (free) and cloud (paid) providers with automatic fallback.
6
+ """
7
+
8
+ from .base import LLMProvider, LLMResponse
9
+ from .opencode_provider import OpenCodeProvider
10
+ from .ollama_provider import OllamaProvider
11
+ from .anthropic_provider import AnthropicProvider
12
+ from .openai_provider import OpenAIProvider
13
+
14
+ __all__ = [
15
+ "LLMProvider",
16
+ "LLMResponse",
17
+ "OpenCodeProvider",
18
+ "OllamaProvider",
19
+ "AnthropicProvider",
20
+ "OpenAIProvider",
21
+ ]
@@ -0,0 +1,109 @@
1
+ """
2
+ Anthropic provider for dev-companion.
3
+
4
+ Uses Anthropic API (Claude) as optional paid provider.
5
+ Requires: ANTHROPIC_API_KEY environment variable.
6
+ """
7
+
8
+ import json
9
+ import os
10
+ import time
11
+ from pathlib import Path
12
+ from typing import Optional
13
+
14
+ from .base import LLMProvider, LLMResponse
15
+
16
+
17
+ class AnthropicProvider(LLMProvider):
18
+ name = "anthropic"
19
+ is_local = False
20
+ is_free = False
21
+
22
+ def __init__(self, model: str = "claude-3-5-haiku-20241022"):
23
+ self.model = model
24
+
25
+ def is_available(self) -> bool:
26
+ return bool(os.environ.get("ANTHROPIC_API_KEY"))
27
+
28
+ def supports_directory_context(self) -> bool:
29
+ return False
30
+
31
+ def get_model_name(self) -> str:
32
+ return self.model
33
+
34
+ def get_priority(self) -> int:
35
+ return 10
36
+
37
+ def generate(
38
+ self,
39
+ prompt: str,
40
+ system_prompt: Optional[str] = None,
41
+ repo_path: Optional[Path] = None,
42
+ timeout_sec: int = 300,
43
+ ) -> LLMResponse:
44
+ import urllib.request
45
+ import urllib.error
46
+
47
+ start_time = time.time()
48
+
49
+ headers = {
50
+ "Content-Type": "application/json",
51
+ "x-api-key": os.environ["ANTHROPIC_API_KEY"],
52
+ "anthropic-version": "2023-06-01",
53
+ }
54
+
55
+ messages = [{"role": "user", "content": prompt}]
56
+ if system_prompt:
57
+ messages[0] = {
58
+ "role": "user",
59
+ "content": f"{system_prompt}\n\n---\n\n{prompt}",
60
+ }
61
+
62
+ data = {
63
+ "model": self.model,
64
+ "messages": messages,
65
+ "max_tokens": 4096,
66
+ }
67
+
68
+ try:
69
+ req = urllib.request.Request(
70
+ "https://api.anthropic.com/v1/messages",
71
+ data=json.dumps(data).encode(),
72
+ headers=headers,
73
+ method="POST",
74
+ )
75
+
76
+ with urllib.request.urlopen(req, timeout=timeout_sec) as response:
77
+ result = json.loads(response.read().decode())
78
+
79
+ duration = time.time() - start_time
80
+
81
+ content = ""
82
+ for block in result.get("content", []):
83
+ if block.get("type") == "text":
84
+ content += block.get("text", "")
85
+
86
+ usage = result.get("usage", {})
87
+
88
+ return LLMResponse(
89
+ content=content,
90
+ model=self.model,
91
+ provider=self.name,
92
+ tokens_used=usage.get("output_tokens"),
93
+ duration_sec=duration,
94
+ )
95
+
96
+ except urllib.error.HTTPError as e:
97
+ return LLMResponse(
98
+ content=f"HTTP Error: {e.code} - {e.reason}",
99
+ model=self.model,
100
+ provider=self.name,
101
+ duration_sec=time.time() - start_time,
102
+ )
103
+ except Exception as e:
104
+ return LLMResponse(
105
+ content=f"Error: {str(e)}",
106
+ model=self.model,
107
+ provider=self.name,
108
+ duration_sec=time.time() - start_time,
109
+ )
@@ -0,0 +1,53 @@
1
+ """
2
+ Base interface for LLM providers.
3
+
4
+ All providers must implement this interface to be used by the dev-companion runner.
5
+ """
6
+
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+ from typing import Optional
11
+
12
+
13
+ @dataclass
14
+ class LLMResponse:
15
+ content: str
16
+ model: str
17
+ provider: str
18
+ tokens_used: Optional[int] = None
19
+ duration_sec: Optional[float] = None
20
+
21
+
22
+ class LLMProvider(ABC):
23
+ name: str
24
+ is_local: bool = False
25
+ is_free: bool = False
26
+
27
+ @abstractmethod
28
+ def is_available(self) -> bool:
29
+ """Check if the provider is available (installed, configured, etc.)"""
30
+ pass
31
+
32
+ @abstractmethod
33
+ def generate(
34
+ self,
35
+ prompt: str,
36
+ system_prompt: Optional[str] = None,
37
+ repo_path: Optional[Path] = None,
38
+ timeout_sec: int = 300,
39
+ ) -> LLMResponse:
40
+ """Generate a response from the LLM"""
41
+ pass
42
+
43
+ def get_priority(self) -> int:
44
+ """Lower = higher priority. Local free providers should have priority over cloud paid ones."""
45
+ return 100
46
+
47
+ def supports_directory_context(self) -> bool:
48
+ """Whether the provider can operate in a specific directory context"""
49
+ return False
50
+
51
+ def get_model_name(self) -> str:
52
+ """Return the model name used by this provider"""
53
+ return "unknown"