compound-engineering-pi 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/bin/compound-engineering-pi +12 -0
- package/bin/compound-plugin +12 -0
- package/compound-engineering-pi +12 -0
- package/compound-plugin +5 -0
- package/docs/pi.md +152 -0
- package/extensions/compound-engineering-compat.ts +452 -0
- package/package.json +84 -0
- package/pi-resources/compound-engineering/mcporter.json +7 -0
- package/plugins/coding-tutor/.claude-plugin/plugin.json +9 -0
- package/plugins/coding-tutor/README.md +37 -0
- package/plugins/coding-tutor/commands/quiz-me.md +1 -0
- package/plugins/coding-tutor/commands/sync-tutorials.md +25 -0
- package/plugins/coding-tutor/commands/teach-me.md +1 -0
- package/plugins/coding-tutor/skills/coding-tutor/SKILL.md +214 -0
- package/plugins/coding-tutor/skills/coding-tutor/scripts/create_tutorial.py +207 -0
- package/plugins/coding-tutor/skills/coding-tutor/scripts/index_tutorials.py +193 -0
- package/plugins/coding-tutor/skills/coding-tutor/scripts/quiz_priority.py +190 -0
- package/plugins/coding-tutor/skills/coding-tutor/scripts/setup_tutorials.py +118 -0
- package/plugins/compound-engineering/.claude-plugin/plugin.json +33 -0
- package/plugins/compound-engineering/CHANGELOG.md +457 -0
- package/plugins/compound-engineering/CLAUDE.md +89 -0
- package/plugins/compound-engineering/LICENSE +21 -0
- package/plugins/compound-engineering/README.md +232 -0
- package/plugins/compound-engineering/agents/design/design-implementation-reviewer.md +109 -0
- package/plugins/compound-engineering/agents/design/design-iterator.md +224 -0
- package/plugins/compound-engineering/agents/design/figma-design-sync.md +190 -0
- package/plugins/compound-engineering/agents/docs/ankane-readme-writer.md +65 -0
- package/plugins/compound-engineering/agents/research/best-practices-researcher.md +126 -0
- package/plugins/compound-engineering/agents/research/framework-docs-researcher.md +106 -0
- package/plugins/compound-engineering/agents/research/git-history-analyzer.md +59 -0
- package/plugins/compound-engineering/agents/research/learnings-researcher.md +264 -0
- package/plugins/compound-engineering/agents/research/repo-research-analyst.md +135 -0
- package/plugins/compound-engineering/agents/review/agent-native-reviewer.md +261 -0
- package/plugins/compound-engineering/agents/review/architecture-strategist.md +67 -0
- package/plugins/compound-engineering/agents/review/code-simplicity-reviewer.md +101 -0
- package/plugins/compound-engineering/agents/review/data-integrity-guardian.md +85 -0
- package/plugins/compound-engineering/agents/review/data-migration-expert.md +112 -0
- package/plugins/compound-engineering/agents/review/deployment-verification-agent.md +174 -0
- package/plugins/compound-engineering/agents/review/dhh-rails-reviewer.md +66 -0
- package/plugins/compound-engineering/agents/review/julik-frontend-races-reviewer.md +221 -0
- package/plugins/compound-engineering/agents/review/kieran-python-reviewer.md +133 -0
- package/plugins/compound-engineering/agents/review/kieran-rails-reviewer.md +115 -0
- package/plugins/compound-engineering/agents/review/kieran-typescript-reviewer.md +124 -0
- package/plugins/compound-engineering/agents/review/pattern-recognition-specialist.md +72 -0
- package/plugins/compound-engineering/agents/review/performance-oracle.md +137 -0
- package/plugins/compound-engineering/agents/review/schema-drift-detector.md +154 -0
- package/plugins/compound-engineering/agents/review/security-sentinel.md +114 -0
- package/plugins/compound-engineering/agents/workflow/bug-reproduction-validator.md +82 -0
- package/plugins/compound-engineering/agents/workflow/every-style-editor.md +64 -0
- package/plugins/compound-engineering/agents/workflow/lint.md +16 -0
- package/plugins/compound-engineering/agents/workflow/pr-comment-resolver.md +84 -0
- package/plugins/compound-engineering/agents/workflow/spec-flow-analyzer.md +134 -0
- package/plugins/compound-engineering/commands/agent-native-audit.md +278 -0
- package/plugins/compound-engineering/commands/changelog.md +138 -0
- package/plugins/compound-engineering/commands/create-agent-skill.md +9 -0
- package/plugins/compound-engineering/commands/deepen-plan.md +546 -0
- package/plugins/compound-engineering/commands/deploy-docs.md +113 -0
- package/plugins/compound-engineering/commands/feature-video.md +342 -0
- package/plugins/compound-engineering/commands/generate_command.md +163 -0
- package/plugins/compound-engineering/commands/heal-skill.md +143 -0
- package/plugins/compound-engineering/commands/lfg.md +20 -0
- package/plugins/compound-engineering/commands/release-docs.md +212 -0
- package/plugins/compound-engineering/commands/report-bug.md +151 -0
- package/plugins/compound-engineering/commands/reproduce-bug.md +100 -0
- package/plugins/compound-engineering/commands/resolve_parallel.md +35 -0
- package/plugins/compound-engineering/commands/resolve_todo_parallel.md +37 -0
- package/plugins/compound-engineering/commands/slfg.md +32 -0
- package/plugins/compound-engineering/commands/technical_review.md +8 -0
- package/plugins/compound-engineering/commands/test-browser.md +339 -0
- package/plugins/compound-engineering/commands/test-xcode.md +332 -0
- package/plugins/compound-engineering/commands/triage.md +311 -0
- package/plugins/compound-engineering/commands/workflows/brainstorm.md +124 -0
- package/plugins/compound-engineering/commands/workflows/compound.md +239 -0
- package/plugins/compound-engineering/commands/workflows/plan.md +551 -0
- package/plugins/compound-engineering/commands/workflows/review.md +526 -0
- package/plugins/compound-engineering/commands/workflows/work.md +433 -0
- package/plugins/compound-engineering/skills/agent-browser/SKILL.md +223 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/SKILL.md +435 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/product-implications.md +443 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/self-modification.md +269 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
- package/plugins/compound-engineering/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/SKILL.md +184 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/resources.md +119 -0
- package/plugins/compound-engineering/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/plugins/compound-engineering/skills/brainstorming/SKILL.md +190 -0
- package/plugins/compound-engineering/skills/compound-docs/SKILL.md +511 -0
- package/plugins/compound-engineering/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/plugins/compound-engineering/skills/compound-docs/assets/resolution-template.md +93 -0
- package/plugins/compound-engineering/skills/compound-docs/references/yaml-schema.md +65 -0
- package/plugins/compound-engineering/skills/compound-docs/schema.yaml +176 -0
- package/plugins/compound-engineering/skills/create-agent-skills/SKILL.md +275 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/api-security.md +226 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/best-practices.md +404 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/common-patterns.md +595 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/core-principles.md +437 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/executable-code.md +175 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/official-spec.md +134 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/recommended-structure.md +168 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/skill-structure.md +152 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/using-scripts.md +113 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/using-templates.md +112 -0
- package/plugins/compound-engineering/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
- package/plugins/compound-engineering/skills/create-agent-skills/templates/router-skill.md +73 -0
- package/plugins/compound-engineering/skills/create-agent-skills/templates/simple-skill.md +33 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-reference.md +96 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-script.md +93 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-template.md +74 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/add-workflow.md +120 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/audit-skill.md +138 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/get-guidance.md +121 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
- package/plugins/compound-engineering/skills/create-agent-skills/workflows/verify-skill.md +204 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/SKILL.md +185 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/architecture.md +653 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/controllers.md +303 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/frontend.md +510 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/gems.md +266 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/models.md +359 -0
- package/plugins/compound-engineering/skills/dhh-rails-style/references/testing.md +338 -0
- package/plugins/compound-engineering/skills/document-review/SKILL.md +87 -0
- package/plugins/compound-engineering/skills/dspy-ruby/SKILL.md +737 -0
- package/plugins/compound-engineering/skills/dspy-ruby/assets/config-template.rb +187 -0
- package/plugins/compound-engineering/skills/dspy-ruby/assets/module-template.rb +300 -0
- package/plugins/compound-engineering/skills/dspy-ruby/assets/signature-template.rb +221 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/core-concepts.md +674 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/observability.md +366 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/optimization.md +603 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/providers.md +418 -0
- package/plugins/compound-engineering/skills/dspy-ruby/references/toolsets.md +502 -0
- package/plugins/compound-engineering/skills/every-style-editor/SKILL.md +134 -0
- package/plugins/compound-engineering/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/plugins/compound-engineering/skills/file-todos/SKILL.md +252 -0
- package/plugins/compound-engineering/skills/file-todos/assets/todo-template.md +155 -0
- package/plugins/compound-engineering/skills/frontend-design/SKILL.md +42 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/SKILL.md +237 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/requirements.txt +2 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/scripts/compose_images.py +157 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/scripts/edit_image.py +144 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/scripts/gemini_images.py +263 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/scripts/generate_image.py +133 -0
- package/plugins/compound-engineering/skills/gemini-imagegen/scripts/multi_turn_chat.py +216 -0
- package/plugins/compound-engineering/skills/git-worktree/SKILL.md +302 -0
- package/plugins/compound-engineering/skills/git-worktree/scripts/worktree-manager.sh +337 -0
- package/plugins/compound-engineering/skills/orchestrating-swarms/SKILL.md +1718 -0
- package/plugins/compound-engineering/skills/rclone/SKILL.md +150 -0
- package/plugins/compound-engineering/skills/rclone/scripts/check_setup.sh +60 -0
- package/plugins/compound-engineering/skills/resolve-pr-parallel/SKILL.md +89 -0
- package/plugins/compound-engineering/skills/resolve-pr-parallel/scripts/get-pr-comments +68 -0
- package/plugins/compound-engineering/skills/resolve-pr-parallel/scripts/resolve-pr-thread +23 -0
- package/plugins/compound-engineering/skills/skill-creator/SKILL.md +210 -0
- package/plugins/compound-engineering/skills/skill-creator/scripts/init_skill.py +303 -0
- package/plugins/compound-engineering/skills/skill-creator/scripts/package_skill.py +110 -0
- package/plugins/compound-engineering/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/prompts/deepen-plan.md +549 -0
- package/prompts/feature-video.md +341 -0
- package/prompts/resolve_todo_parallel.md +36 -0
- package/prompts/test-browser.md +342 -0
- package/prompts/workflows-brainstorm.md +123 -0
- package/prompts/workflows-compound.md +238 -0
- package/prompts/workflows-plan.md +550 -0
- package/prompts/workflows-review.md +529 -0
- package/prompts/workflows-work.md +432 -0
- package/skills/agent-browser/SKILL.md +223 -0
- package/skills/agent-native-architecture/SKILL.md +435 -0
- package/skills/agent-native-architecture/references/action-parity-discipline.md +409 -0
- package/skills/agent-native-architecture/references/agent-execution-patterns.md +467 -0
- package/skills/agent-native-architecture/references/agent-native-testing.md +582 -0
- package/skills/agent-native-architecture/references/architecture-patterns.md +478 -0
- package/skills/agent-native-architecture/references/dynamic-context-injection.md +338 -0
- package/skills/agent-native-architecture/references/files-universal-interface.md +301 -0
- package/skills/agent-native-architecture/references/from-primitives-to-domain-tools.md +359 -0
- package/skills/agent-native-architecture/references/mcp-tool-design.md +506 -0
- package/skills/agent-native-architecture/references/mobile-patterns.md +871 -0
- package/skills/agent-native-architecture/references/product-implications.md +443 -0
- package/skills/agent-native-architecture/references/refactoring-to-prompt-native.md +317 -0
- package/skills/agent-native-architecture/references/self-modification.md +269 -0
- package/skills/agent-native-architecture/references/shared-workspace-architecture.md +680 -0
- package/skills/agent-native-architecture/references/system-prompt-design.md +250 -0
- package/skills/agent-native-reviewer/SKILL.md +260 -0
- package/skills/andrew-kane-gem-writer/SKILL.md +184 -0
- package/skills/andrew-kane-gem-writer/references/database-adapters.md +231 -0
- package/skills/andrew-kane-gem-writer/references/module-organization.md +121 -0
- package/skills/andrew-kane-gem-writer/references/rails-integration.md +183 -0
- package/skills/andrew-kane-gem-writer/references/resources.md +119 -0
- package/skills/andrew-kane-gem-writer/references/testing-patterns.md +261 -0
- package/skills/ankane-readme-writer/SKILL.md +63 -0
- package/skills/architecture-strategist/SKILL.md +66 -0
- package/skills/best-practices-researcher/SKILL.md +125 -0
- package/skills/brainstorming/SKILL.md +190 -0
- package/skills/bug-reproduction-validator/SKILL.md +81 -0
- package/skills/code-simplicity-reviewer/SKILL.md +100 -0
- package/skills/compound-docs/SKILL.md +511 -0
- package/skills/compound-docs/assets/critical-pattern-template.md +34 -0
- package/skills/compound-docs/assets/resolution-template.md +93 -0
- package/skills/compound-docs/references/yaml-schema.md +65 -0
- package/skills/compound-docs/schema.yaml +176 -0
- package/skills/create-agent-skills/SKILL.md +275 -0
- package/skills/create-agent-skills/references/api-security.md +226 -0
- package/skills/create-agent-skills/references/be-clear-and-direct.md +531 -0
- package/skills/create-agent-skills/references/best-practices.md +404 -0
- package/skills/create-agent-skills/references/common-patterns.md +595 -0
- package/skills/create-agent-skills/references/core-principles.md +437 -0
- package/skills/create-agent-skills/references/executable-code.md +175 -0
- package/skills/create-agent-skills/references/iteration-and-testing.md +474 -0
- package/skills/create-agent-skills/references/official-spec.md +134 -0
- package/skills/create-agent-skills/references/recommended-structure.md +168 -0
- package/skills/create-agent-skills/references/skill-structure.md +152 -0
- package/skills/create-agent-skills/references/using-scripts.md +113 -0
- package/skills/create-agent-skills/references/using-templates.md +112 -0
- package/skills/create-agent-skills/references/workflows-and-validation.md +510 -0
- package/skills/create-agent-skills/templates/router-skill.md +73 -0
- package/skills/create-agent-skills/templates/simple-skill.md +33 -0
- package/skills/create-agent-skills/workflows/add-reference.md +96 -0
- package/skills/create-agent-skills/workflows/add-script.md +93 -0
- package/skills/create-agent-skills/workflows/add-template.md +74 -0
- package/skills/create-agent-skills/workflows/add-workflow.md +120 -0
- package/skills/create-agent-skills/workflows/audit-skill.md +138 -0
- package/skills/create-agent-skills/workflows/create-domain-expertise-skill.md +605 -0
- package/skills/create-agent-skills/workflows/create-new-skill.md +191 -0
- package/skills/create-agent-skills/workflows/get-guidance.md +121 -0
- package/skills/create-agent-skills/workflows/upgrade-to-router.md +161 -0
- package/skills/create-agent-skills/workflows/verify-skill.md +204 -0
- package/skills/data-integrity-guardian/SKILL.md +84 -0
- package/skills/data-migration-expert/SKILL.md +111 -0
- package/skills/deployment-verification-agent/SKILL.md +173 -0
- package/skills/design-implementation-reviewer/SKILL.md +107 -0
- package/skills/design-iterator/SKILL.md +222 -0
- package/skills/dhh-rails-reviewer/SKILL.md +65 -0
- package/skills/dhh-rails-style/SKILL.md +185 -0
- package/skills/dhh-rails-style/references/architecture.md +653 -0
- package/skills/dhh-rails-style/references/controllers.md +303 -0
- package/skills/dhh-rails-style/references/frontend.md +510 -0
- package/skills/dhh-rails-style/references/gems.md +266 -0
- package/skills/dhh-rails-style/references/models.md +359 -0
- package/skills/dhh-rails-style/references/testing.md +338 -0
- package/skills/document-review/SKILL.md +87 -0
- package/skills/dspy-ruby/SKILL.md +737 -0
- package/skills/dspy-ruby/assets/config-template.rb +187 -0
- package/skills/dspy-ruby/assets/module-template.rb +300 -0
- package/skills/dspy-ruby/assets/signature-template.rb +221 -0
- package/skills/dspy-ruby/references/core-concepts.md +674 -0
- package/skills/dspy-ruby/references/observability.md +366 -0
- package/skills/dspy-ruby/references/optimization.md +603 -0
- package/skills/dspy-ruby/references/providers.md +418 -0
- package/skills/dspy-ruby/references/toolsets.md +502 -0
- package/skills/every-style-editor/SKILL.md +134 -0
- package/skills/every-style-editor/references/EVERY_WRITE_STYLE.md +529 -0
- package/skills/every-style-editor-2/SKILL.md +62 -0
- package/skills/figma-design-sync/SKILL.md +188 -0
- package/skills/file-todos/SKILL.md +252 -0
- package/skills/file-todos/assets/todo-template.md +155 -0
- package/skills/framework-docs-researcher/SKILL.md +105 -0
- package/skills/frontend-design/SKILL.md +42 -0
- package/skills/gemini-imagegen/SKILL.md +237 -0
- package/skills/gemini-imagegen/requirements.txt +2 -0
- package/skills/gemini-imagegen/scripts/compose_images.py +157 -0
- package/skills/gemini-imagegen/scripts/edit_image.py +144 -0
- package/skills/gemini-imagegen/scripts/gemini_images.py +263 -0
- package/skills/gemini-imagegen/scripts/generate_image.py +133 -0
- package/skills/gemini-imagegen/scripts/multi_turn_chat.py +216 -0
- package/skills/git-history-analyzer/SKILL.md +58 -0
- package/skills/git-worktree/SKILL.md +302 -0
- package/skills/git-worktree/scripts/worktree-manager.sh +337 -0
- package/skills/julik-frontend-races-reviewer/SKILL.md +220 -0
- package/skills/kieran-python-reviewer/SKILL.md +132 -0
- package/skills/kieran-rails-reviewer/SKILL.md +114 -0
- package/skills/kieran-typescript-reviewer/SKILL.md +123 -0
- package/skills/learnings-researcher/SKILL.md +263 -0
- package/skills/lint/SKILL.md +14 -0
- package/skills/orchestrating-swarms/SKILL.md +1718 -0
- package/skills/pattern-recognition-specialist/SKILL.md +71 -0
- package/skills/performance-oracle/SKILL.md +136 -0
- package/skills/pr-comment-resolver/SKILL.md +82 -0
- package/skills/rclone/SKILL.md +150 -0
- package/skills/rclone/scripts/check_setup.sh +60 -0
- package/skills/repo-research-analyst/SKILL.md +134 -0
- package/skills/resolve_pr_parallel/SKILL.md +89 -0
- package/skills/resolve_pr_parallel/scripts/get-pr-comments +68 -0
- package/skills/resolve_pr_parallel/scripts/resolve-pr-thread +23 -0
- package/skills/schema-drift-detector/SKILL.md +153 -0
- package/skills/security-sentinel/SKILL.md +113 -0
- package/skills/skill-creator/SKILL.md +210 -0
- package/skills/skill-creator/scripts/init_skill.py +303 -0
- package/skills/skill-creator/scripts/package_skill.py +110 -0
- package/skills/skill-creator/scripts/quick_validate.py +65 -0
- package/skills/spec-flow-analyzer/SKILL.md +133 -0
- package/src/commands/convert.ts +183 -0
- package/src/commands/install.ts +273 -0
- package/src/commands/list.ts +37 -0
- package/src/commands/sync.ts +89 -0
- package/src/converters/claude-to-codex.ts +182 -0
- package/src/converters/claude-to-opencode.ts +395 -0
- package/src/converters/claude-to-pi.ts +205 -0
- package/src/index.ts +22 -0
- package/src/parsers/claude-home.ts +65 -0
- package/src/parsers/claude.ts +252 -0
- package/src/sync/codex.ts +92 -0
- package/src/sync/opencode.ts +75 -0
- package/src/sync/pi.ts +88 -0
- package/src/targets/codex.ts +96 -0
- package/src/targets/index.ts +38 -0
- package/src/targets/opencode.ts +57 -0
- package/src/targets/pi.ts +131 -0
- package/src/templates/pi/compat-extension.ts +452 -0
- package/src/types/claude.ts +90 -0
- package/src/types/codex.ts +23 -0
- package/src/types/opencode.ts +54 -0
- package/src/types/pi.ts +40 -0
- package/src/utils/codex-agents.ts +64 -0
- package/src/utils/files.ts +77 -0
- package/src/utils/frontmatter.ts +65 -0
- package/src/utils/symlink.ts +43 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# DSPy.rb Configuration Template — v0.34.3 API
|
|
5
|
+
#
|
|
6
|
+
# Rails initializer patterns for DSPy.rb with RubyLLM, observability,
|
|
7
|
+
# and feature-flagged model selection.
|
|
8
|
+
#
|
|
9
|
+
# Key patterns:
|
|
10
|
+
# - Use after_initialize for Rails setup
|
|
11
|
+
# - Use dspy-ruby_llm for multi-provider routing
|
|
12
|
+
# - Use structured_outputs: true for reliable parsing
|
|
13
|
+
# - Use dspy-o11y + dspy-o11y-langfuse for observability
|
|
14
|
+
# - Use ENV-based feature flags for model selection
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
# =============================================================================
|
|
18
|
+
# Gemfile Dependencies
|
|
19
|
+
# =============================================================================
|
|
20
|
+
#
|
|
21
|
+
# # Core
|
|
22
|
+
# gem 'dspy'
|
|
23
|
+
#
|
|
24
|
+
# # Provider adapter (choose one strategy):
|
|
25
|
+
#
|
|
26
|
+
# # Strategy A: Unified adapter via RubyLLM (recommended)
|
|
27
|
+
# gem 'dspy-ruby_llm'
|
|
28
|
+
# gem 'ruby_llm'
|
|
29
|
+
#
|
|
30
|
+
# # Strategy B: Per-provider adapters (direct SDK access)
|
|
31
|
+
# gem 'dspy-openai' # OpenAI, OpenRouter, Ollama
|
|
32
|
+
# gem 'dspy-anthropic' # Claude
|
|
33
|
+
# gem 'dspy-gemini' # Gemini
|
|
34
|
+
#
|
|
35
|
+
# # Observability (optional)
|
|
36
|
+
# gem 'dspy-o11y'
|
|
37
|
+
# gem 'dspy-o11y-langfuse'
|
|
38
|
+
#
|
|
39
|
+
# # Optimization (optional)
|
|
40
|
+
# gem 'dspy-miprov2' # MIPROv2 optimizer
|
|
41
|
+
# gem 'dspy-gepa' # GEPA optimizer
|
|
42
|
+
#
|
|
43
|
+
# # Schema formats (optional)
|
|
44
|
+
# gem 'sorbet-baml' # BAML schema format (84% token reduction)
|
|
45
|
+
|
|
46
|
+
# =============================================================================
|
|
47
|
+
# Rails Initializer — config/initializers/dspy.rb
|
|
48
|
+
# =============================================================================
|
|
49
|
+
|
|
50
|
+
Rails.application.config.after_initialize do
|
|
51
|
+
# Skip in test unless explicitly enabled
|
|
52
|
+
next if Rails.env.test? && ENV["DSPY_ENABLE_IN_TEST"].blank?
|
|
53
|
+
|
|
54
|
+
# Configure RubyLLM provider credentials
|
|
55
|
+
RubyLLM.configure do |config|
|
|
56
|
+
config.gemini_api_key = ENV["GEMINI_API_KEY"] if ENV["GEMINI_API_KEY"].present?
|
|
57
|
+
config.anthropic_api_key = ENV["ANTHROPIC_API_KEY"] if ENV["ANTHROPIC_API_KEY"].present?
|
|
58
|
+
config.openai_api_key = ENV["OPENAI_API_KEY"] if ENV["OPENAI_API_KEY"].present?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Configure DSPy with unified RubyLLM adapter
|
|
62
|
+
model = ENV.fetch("DSPY_MODEL", "ruby_llm/gemini-2.5-flash")
|
|
63
|
+
DSPy.configure do |config|
|
|
64
|
+
config.lm = DSPy::LM.new(model, structured_outputs: true)
|
|
65
|
+
config.logger = Rails.logger
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Enable Langfuse observability (optional)
|
|
69
|
+
if ENV["LANGFUSE_PUBLIC_KEY"].present? && ENV["LANGFUSE_SECRET_KEY"].present?
|
|
70
|
+
DSPy::Observability.configure!
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# =============================================================================
|
|
75
|
+
# Feature Flags — config/initializers/feature_flags.rb
|
|
76
|
+
# =============================================================================
|
|
77
|
+
|
|
78
|
+
# Use different models for different roles:
|
|
79
|
+
# - Fast/cheap for classification, routing, simple tasks
|
|
80
|
+
# - Powerful for synthesis, reasoning, complex analysis
|
|
81
|
+
|
|
82
|
+
module FeatureFlags
|
|
83
|
+
SELECTOR_MODEL = ENV.fetch("DSPY_SELECTOR_MODEL", "ruby_llm/gemini-2.5-flash-lite")
|
|
84
|
+
SYNTHESIZER_MODEL = ENV.fetch("DSPY_SYNTHESIZER_MODEL", "ruby_llm/gemini-2.5-flash")
|
|
85
|
+
REASONING_MODEL = ENV.fetch("DSPY_REASONING_MODEL", "ruby_llm/claude-sonnet-4-20250514")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Usage in tools/modules:
|
|
89
|
+
#
|
|
90
|
+
# class ClassifyTool < DSPy::Tools::Base
|
|
91
|
+
# def call(query:)
|
|
92
|
+
# predictor = DSPy::Predict.new(ClassifySignature)
|
|
93
|
+
# predictor.configure { |c| c.lm = DSPy::LM.new(FeatureFlags::SELECTOR_MODEL, structured_outputs: true) }
|
|
94
|
+
# predictor.call(query: query)
|
|
95
|
+
# end
|
|
96
|
+
# end
|
|
97
|
+
|
|
98
|
+
# =============================================================================
|
|
99
|
+
# Environment Variables — .env
|
|
100
|
+
# =============================================================================
|
|
101
|
+
#
|
|
102
|
+
# # Provider API keys (set the ones you need)
|
|
103
|
+
# GEMINI_API_KEY=...
|
|
104
|
+
# ANTHROPIC_API_KEY=...
|
|
105
|
+
# OPENAI_API_KEY=...
|
|
106
|
+
#
|
|
107
|
+
# # DSPy model configuration
|
|
108
|
+
# DSPY_MODEL=ruby_llm/gemini-2.5-flash
|
|
109
|
+
# DSPY_SELECTOR_MODEL=ruby_llm/gemini-2.5-flash-lite
|
|
110
|
+
# DSPY_SYNTHESIZER_MODEL=ruby_llm/gemini-2.5-flash
|
|
111
|
+
# DSPY_REASONING_MODEL=ruby_llm/claude-sonnet-4-20250514
|
|
112
|
+
#
|
|
113
|
+
# # Langfuse observability (optional)
|
|
114
|
+
# LANGFUSE_PUBLIC_KEY=pk-...
|
|
115
|
+
# LANGFUSE_SECRET_KEY=sk-...
|
|
116
|
+
# DSPY_TELEMETRY_BATCH_SIZE=5
|
|
117
|
+
#
|
|
118
|
+
# # Test environment
|
|
119
|
+
# DSPY_ENABLE_IN_TEST=1 # Set to enable DSPy in test env
|
|
120
|
+
|
|
121
|
+
# =============================================================================
|
|
122
|
+
# Per-Provider Configuration (without RubyLLM)
|
|
123
|
+
# =============================================================================
|
|
124
|
+
|
|
125
|
+
# OpenAI (dspy-openai gem)
|
|
126
|
+
# DSPy.configure do |c|
|
|
127
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini', api_key: ENV['OPENAI_API_KEY'])
|
|
128
|
+
# end
|
|
129
|
+
|
|
130
|
+
# Anthropic (dspy-anthropic gem)
|
|
131
|
+
# DSPy.configure do |c|
|
|
132
|
+
# c.lm = DSPy::LM.new('anthropic/claude-sonnet-4-20250514', api_key: ENV['ANTHROPIC_API_KEY'])
|
|
133
|
+
# end
|
|
134
|
+
|
|
135
|
+
# Gemini (dspy-gemini gem)
|
|
136
|
+
# DSPy.configure do |c|
|
|
137
|
+
# c.lm = DSPy::LM.new('gemini/gemini-2.5-flash', api_key: ENV['GEMINI_API_KEY'])
|
|
138
|
+
# end
|
|
139
|
+
|
|
140
|
+
# Ollama (dspy-openai gem, local models)
|
|
141
|
+
# DSPy.configure do |c|
|
|
142
|
+
# c.lm = DSPy::LM.new('ollama/llama3.2', base_url: 'http://localhost:11434')
|
|
143
|
+
# end
|
|
144
|
+
|
|
145
|
+
# OpenRouter (dspy-openai gem, 200+ models)
|
|
146
|
+
# DSPy.configure do |c|
|
|
147
|
+
# c.lm = DSPy::LM.new('openrouter/anthropic/claude-3.5-sonnet',
|
|
148
|
+
# api_key: ENV['OPENROUTER_API_KEY'],
|
|
149
|
+
# base_url: 'https://openrouter.ai/api/v1')
|
|
150
|
+
# end
|
|
151
|
+
|
|
152
|
+
# =============================================================================
|
|
153
|
+
# VCR Test Configuration — spec/support/dspy.rb
|
|
154
|
+
# =============================================================================
|
|
155
|
+
|
|
156
|
+
# VCR.configure do |config|
|
|
157
|
+
# config.cassette_library_dir = "spec/vcr_cassettes"
|
|
158
|
+
# config.hook_into :webmock
|
|
159
|
+
# config.configure_rspec_metadata!
|
|
160
|
+
# config.filter_sensitive_data('<GEMINI_API_KEY>') { ENV['GEMINI_API_KEY'] }
|
|
161
|
+
# config.filter_sensitive_data('<OPENAI_API_KEY>') { ENV['OPENAI_API_KEY'] }
|
|
162
|
+
# config.filter_sensitive_data('<ANTHROPIC_API_KEY>') { ENV['ANTHROPIC_API_KEY'] }
|
|
163
|
+
# end
|
|
164
|
+
|
|
165
|
+
# =============================================================================
|
|
166
|
+
# Schema Format Configuration (optional)
|
|
167
|
+
# =============================================================================
|
|
168
|
+
|
|
169
|
+
# BAML schema format — 84% token reduction for Enhanced Prompting mode
|
|
170
|
+
# DSPy.configure do |c|
|
|
171
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
172
|
+
# api_key: ENV['OPENAI_API_KEY'],
|
|
173
|
+
# schema_format: :baml # Requires sorbet-baml gem
|
|
174
|
+
# )
|
|
175
|
+
# end
|
|
176
|
+
|
|
177
|
+
# TOON schema + data format — table-oriented format
|
|
178
|
+
# DSPy.configure do |c|
|
|
179
|
+
# c.lm = DSPy::LM.new('openai/gpt-4o-mini',
|
|
180
|
+
# api_key: ENV['OPENAI_API_KEY'],
|
|
181
|
+
# schema_format: :toon, # How DSPy describes the signature
|
|
182
|
+
# data_format: :toon # How inputs/outputs are rendered in prompts
|
|
183
|
+
# )
|
|
184
|
+
# end
|
|
185
|
+
#
|
|
186
|
+
# Note: BAML and TOON apply only when structured_outputs: false.
|
|
187
|
+
# With structured_outputs: true, the provider receives JSON Schema directly.
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# DSPy.rb Module Template — v0.34.3 API
|
|
5
|
+
#
|
|
6
|
+
# Modules orchestrate predictors, tools, and business logic.
|
|
7
|
+
#
|
|
8
|
+
# Key patterns:
|
|
9
|
+
# - Use .call() to invoke (not .forward())
|
|
10
|
+
# - Access results with result.field (not result[:field])
|
|
11
|
+
# - Use DSPy::Tools::Base for tools (not DSPy::Tool)
|
|
12
|
+
# - Use lifecycle callbacks (before/around/after) for cross-cutting concerns
|
|
13
|
+
# - Use DSPy.with_lm for temporary model overrides
|
|
14
|
+
# - Use configure_predictor for fine-grained agent control
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
# --- Basic Module ---
|
|
18
|
+
|
|
19
|
+
class BasicClassifier < DSPy::Module
|
|
20
|
+
def initialize
|
|
21
|
+
super
|
|
22
|
+
@predictor = DSPy::Predict.new(ClassificationSignature)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def forward(text:)
|
|
26
|
+
@predictor.call(text: text)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Usage:
|
|
31
|
+
# classifier = BasicClassifier.new
|
|
32
|
+
# result = classifier.call(text: "This is a test")
|
|
33
|
+
# result.category # => "technical"
|
|
34
|
+
# result.confidence # => 0.95
|
|
35
|
+
|
|
36
|
+
# --- Module with Chain of Thought ---
|
|
37
|
+
|
|
38
|
+
class ReasoningClassifier < DSPy::Module
|
|
39
|
+
def initialize
|
|
40
|
+
super
|
|
41
|
+
@predictor = DSPy::ChainOfThought.new(ClassificationSignature)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def forward(text:)
|
|
45
|
+
result = @predictor.call(text: text)
|
|
46
|
+
# ChainOfThought adds result.reasoning automatically
|
|
47
|
+
result
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# --- Module with Lifecycle Callbacks ---
|
|
52
|
+
|
|
53
|
+
class InstrumentedModule < DSPy::Module
|
|
54
|
+
before :setup_metrics
|
|
55
|
+
around :manage_context
|
|
56
|
+
after :log_completion
|
|
57
|
+
|
|
58
|
+
def initialize
|
|
59
|
+
super
|
|
60
|
+
@predictor = DSPy::Predict.new(AnalysisSignature)
|
|
61
|
+
@start_time = nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def forward(query:)
|
|
65
|
+
@predictor.call(query: query)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private
|
|
69
|
+
|
|
70
|
+
# Runs before forward
|
|
71
|
+
def setup_metrics
|
|
72
|
+
@start_time = Time.now
|
|
73
|
+
Rails.logger.info "Starting prediction"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Wraps forward — must call yield
|
|
77
|
+
def manage_context
|
|
78
|
+
load_user_context
|
|
79
|
+
result = yield
|
|
80
|
+
save_updated_context(result)
|
|
81
|
+
result
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Runs after forward completes
|
|
85
|
+
def log_completion
|
|
86
|
+
duration = Time.now - @start_time
|
|
87
|
+
Rails.logger.info "Prediction completed in #{duration}s"
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def load_user_context = nil
|
|
91
|
+
def save_updated_context(_result) = nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Execution order: before → around (before yield) → forward → around (after yield) → after
|
|
95
|
+
# Callbacks are inherited from parent classes and execute in registration order.
|
|
96
|
+
|
|
97
|
+
# --- Module with Tools ---
|
|
98
|
+
|
|
99
|
+
class SearchTool < DSPy::Tools::Base
|
|
100
|
+
tool_name "search"
|
|
101
|
+
tool_description "Search for information by query"
|
|
102
|
+
|
|
103
|
+
sig { params(query: String, max_results: Integer).returns(T::Array[T::Hash[Symbol, String]]) }
|
|
104
|
+
def call(query:, max_results: 5)
|
|
105
|
+
# Implementation here
|
|
106
|
+
[{ title: "Result 1", url: "https://example.com" }]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
class FinishTool < DSPy::Tools::Base
|
|
111
|
+
tool_name "finish"
|
|
112
|
+
tool_description "Submit the final answer"
|
|
113
|
+
|
|
114
|
+
sig { params(answer: String).returns(String) }
|
|
115
|
+
def call(answer:)
|
|
116
|
+
answer
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
class ResearchAgent < DSPy::Module
|
|
121
|
+
def initialize
|
|
122
|
+
super
|
|
123
|
+
tools = [SearchTool.new, FinishTool.new]
|
|
124
|
+
@agent = DSPy::ReAct.new(
|
|
125
|
+
ResearchSignature,
|
|
126
|
+
tools: tools,
|
|
127
|
+
max_iterations: 5
|
|
128
|
+
)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def forward(question:)
|
|
132
|
+
@agent.call(question: question)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# --- Module with Per-Task Model Selection ---
|
|
137
|
+
|
|
138
|
+
class SmartRouter < DSPy::Module
|
|
139
|
+
def initialize
|
|
140
|
+
super
|
|
141
|
+
@classifier = DSPy::Predict.new(RouteSignature)
|
|
142
|
+
@analyzer = DSPy::ChainOfThought.new(AnalysisSignature)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def forward(text:)
|
|
146
|
+
# Use fast model for classification
|
|
147
|
+
DSPy.with_lm(fast_model) do
|
|
148
|
+
route = @classifier.call(text: text)
|
|
149
|
+
|
|
150
|
+
if route.requires_deep_analysis
|
|
151
|
+
# Switch to powerful model for analysis
|
|
152
|
+
DSPy.with_lm(powerful_model) do
|
|
153
|
+
@analyzer.call(text: text)
|
|
154
|
+
end
|
|
155
|
+
else
|
|
156
|
+
route
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def fast_model
|
|
164
|
+
@fast_model ||= DSPy::LM.new(
|
|
165
|
+
ENV.fetch("DSPY_SELECTOR_MODEL", "ruby_llm/gemini-2.5-flash-lite"),
|
|
166
|
+
structured_outputs: true
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def powerful_model
|
|
171
|
+
@powerful_model ||= DSPy::LM.new(
|
|
172
|
+
ENV.fetch("DSPY_SYNTHESIZER_MODEL", "ruby_llm/gemini-2.5-flash"),
|
|
173
|
+
structured_outputs: true
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
# --- Module with configure_predictor ---
|
|
179
|
+
|
|
180
|
+
class ConfiguredAgent < DSPy::Module
|
|
181
|
+
def initialize
|
|
182
|
+
super
|
|
183
|
+
tools = [SearchTool.new, FinishTool.new]
|
|
184
|
+
@agent = DSPy::ReAct.new(ResearchSignature, tools: tools)
|
|
185
|
+
|
|
186
|
+
# Set default model for all internal predictors
|
|
187
|
+
@agent.configure { |c| c.lm = DSPy::LM.new('ruby_llm/gemini-2.5-flash', structured_outputs: true) }
|
|
188
|
+
|
|
189
|
+
# Override specific predictor with a more capable model
|
|
190
|
+
@agent.configure_predictor('thought_generator') do |c|
|
|
191
|
+
c.lm = DSPy::LM.new('ruby_llm/claude-sonnet-4-20250514', structured_outputs: true)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def forward(question:)
|
|
196
|
+
@agent.call(question: question)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Available internal predictors by agent type:
|
|
201
|
+
# DSPy::ReAct → thought_generator, observation_processor
|
|
202
|
+
# DSPy::CodeAct → code_generator, observation_processor
|
|
203
|
+
# DSPy::DeepSearch → seed_predictor, search_predictor, reader_predictor, reason_predictor
|
|
204
|
+
|
|
205
|
+
# --- Module with Event Subscriptions ---
|
|
206
|
+
|
|
207
|
+
class TokenTrackingModule < DSPy::Module
|
|
208
|
+
subscribe 'lm.tokens', :track_tokens, scope: :descendants
|
|
209
|
+
|
|
210
|
+
def initialize
|
|
211
|
+
super
|
|
212
|
+
@predictor = DSPy::Predict.new(AnalysisSignature)
|
|
213
|
+
@total_tokens = 0
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def forward(query:)
|
|
217
|
+
@predictor.call(query: query)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def track_tokens(_event, attrs)
|
|
221
|
+
@total_tokens += attrs.fetch(:total_tokens, 0)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def token_usage
|
|
225
|
+
@total_tokens
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Module-scoped subscriptions automatically scope to the module instance and descendants.
|
|
230
|
+
# Use scope: :self_only to restrict delivery to the module itself (ignoring children).
|
|
231
|
+
|
|
232
|
+
# --- Tool That Wraps a Prediction ---
|
|
233
|
+
|
|
234
|
+
class RerankTool < DSPy::Tools::Base
|
|
235
|
+
tool_name "rerank"
|
|
236
|
+
tool_description "Score and rank search results by relevance"
|
|
237
|
+
|
|
238
|
+
MAX_ITEMS = 200
|
|
239
|
+
MIN_ITEMS_FOR_LLM = 5
|
|
240
|
+
|
|
241
|
+
sig { params(query: String, items: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Hash[Symbol, T.untyped]) }
|
|
242
|
+
def call(query:, items: [])
|
|
243
|
+
# Short-circuit: skip LLM for small sets
|
|
244
|
+
return { scored_items: items, reranked: false } if items.size < MIN_ITEMS_FOR_LLM
|
|
245
|
+
|
|
246
|
+
# Cap to prevent token overflow
|
|
247
|
+
capped_items = items.first(MAX_ITEMS)
|
|
248
|
+
|
|
249
|
+
predictor = DSPy::Predict.new(RerankSignature)
|
|
250
|
+
predictor.configure { |c| c.lm = DSPy::LM.new("ruby_llm/gemini-2.5-flash", structured_outputs: true) }
|
|
251
|
+
|
|
252
|
+
result = predictor.call(query: query, items: capped_items)
|
|
253
|
+
{ scored_items: result.scored_items, reranked: true }
|
|
254
|
+
rescue => e
|
|
255
|
+
Rails.logger.warn "[RerankTool] LLM rerank failed: #{e.message}"
|
|
256
|
+
{ error: "Rerank failed: #{e.message}", scored_items: items, reranked: false }
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
# Key patterns for tools wrapping predictions:
|
|
261
|
+
# - Short-circuit LLM calls when unnecessary (small data, trivial cases)
|
|
262
|
+
# - Cap input size to prevent token overflow
|
|
263
|
+
# - Per-tool model selection via configure
|
|
264
|
+
# - Graceful error handling with fallback data
|
|
265
|
+
|
|
266
|
+
# --- Multi-Step Pipeline ---
|
|
267
|
+
|
|
268
|
+
class AnalysisPipeline < DSPy::Module
|
|
269
|
+
def initialize
|
|
270
|
+
super
|
|
271
|
+
@classifier = DSPy::Predict.new(ClassifySignature)
|
|
272
|
+
@analyzer = DSPy::ChainOfThought.new(AnalyzeSignature)
|
|
273
|
+
@summarizer = DSPy::Predict.new(SummarizeSignature)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def forward(text:)
|
|
277
|
+
classification = @classifier.call(text: text)
|
|
278
|
+
analysis = @analyzer.call(text: text, category: classification.category)
|
|
279
|
+
@summarizer.call(analysis: analysis.reasoning, category: classification.category)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
# --- Observability with Spans ---
|
|
284
|
+
|
|
285
|
+
class TracedModule < DSPy::Module
|
|
286
|
+
def initialize
|
|
287
|
+
super
|
|
288
|
+
@predictor = DSPy::Predict.new(AnalysisSignature)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def forward(query:)
|
|
292
|
+
DSPy::Context.with_span(
|
|
293
|
+
operation: "traced_module.analyze",
|
|
294
|
+
"dspy.module" => self.class.name,
|
|
295
|
+
"query.length" => query.length.to_s
|
|
296
|
+
) do
|
|
297
|
+
@predictor.call(query: query)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# DSPy.rb Signature Template — v0.34.3 API
|
|
5
|
+
#
|
|
6
|
+
# Signatures define the interface between your application and LLMs.
|
|
7
|
+
# They specify inputs, outputs, and task descriptions using Sorbet types.
|
|
8
|
+
#
|
|
9
|
+
# Key patterns:
|
|
10
|
+
# - Use T::Enum classes for controlled outputs (not inline T.enum([...]))
|
|
11
|
+
# - Use description: kwarg on fields to guide the LLM
|
|
12
|
+
# - Use default values for optional fields
|
|
13
|
+
# - Use Date/DateTime/Time for temporal data (auto-converted)
|
|
14
|
+
# - Access results with result.field (not result[:field])
|
|
15
|
+
# - Invoke with predictor.call() (not predictor.forward())
|
|
16
|
+
# =============================================================================
|
|
17
|
+
|
|
18
|
+
# --- Basic Signature ---
|
|
19
|
+
|
|
20
|
+
class SentimentAnalysis < DSPy::Signature
|
|
21
|
+
description "Analyze sentiment of text"
|
|
22
|
+
|
|
23
|
+
class Sentiment < T::Enum
|
|
24
|
+
enums do
|
|
25
|
+
Positive = new('positive')
|
|
26
|
+
Negative = new('negative')
|
|
27
|
+
Neutral = new('neutral')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
input do
|
|
32
|
+
const :text, String
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
output do
|
|
36
|
+
const :sentiment, Sentiment
|
|
37
|
+
const :score, Float, description: "Confidence score from 0.0 to 1.0"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Usage:
|
|
42
|
+
# predictor = DSPy::Predict.new(SentimentAnalysis)
|
|
43
|
+
# result = predictor.call(text: "This product is amazing!")
|
|
44
|
+
# result.sentiment # => Sentiment::Positive
|
|
45
|
+
# result.score # => 0.92
|
|
46
|
+
|
|
47
|
+
# --- Signature with Date/Time Types ---
|
|
48
|
+
|
|
49
|
+
class EventScheduler < DSPy::Signature
|
|
50
|
+
description "Schedule events based on requirements"
|
|
51
|
+
|
|
52
|
+
input do
|
|
53
|
+
const :event_name, String
|
|
54
|
+
const :start_date, Date # ISO 8601: YYYY-MM-DD
|
|
55
|
+
const :end_date, T.nilable(Date) # Optional date
|
|
56
|
+
const :preferred_time, DateTime # ISO 8601 with timezone
|
|
57
|
+
const :deadline, Time # Stored as UTC
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
output do
|
|
61
|
+
const :scheduled_date, Date # LLM returns ISO string, auto-converted
|
|
62
|
+
const :event_datetime, DateTime # Preserves timezone
|
|
63
|
+
const :created_at, Time # Converted to UTC
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# Date/Time format handling:
|
|
68
|
+
# Date → ISO 8601 (YYYY-MM-DD)
|
|
69
|
+
# DateTime → ISO 8601 with timezone (YYYY-MM-DDTHH:MM:SS+00:00)
|
|
70
|
+
# Time → ISO 8601, automatically converted to UTC
|
|
71
|
+
|
|
72
|
+
# --- Signature with Default Values ---
|
|
73
|
+
|
|
74
|
+
class SmartSearch < DSPy::Signature
|
|
75
|
+
description "Search with intelligent defaults"
|
|
76
|
+
|
|
77
|
+
input do
|
|
78
|
+
const :query, String
|
|
79
|
+
const :max_results, Integer, default: 10
|
|
80
|
+
const :language, String, default: "English"
|
|
81
|
+
const :include_metadata, T::Boolean, default: false
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
output do
|
|
85
|
+
const :results, T::Array[String]
|
|
86
|
+
const :total_found, Integer
|
|
87
|
+
const :search_time_ms, Float, default: 0.0 # Fallback if LLM omits
|
|
88
|
+
const :cached, T::Boolean, default: false
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Input defaults reduce boilerplate:
|
|
93
|
+
# search = DSPy::Predict.new(SmartSearch)
|
|
94
|
+
# result = search.call(query: "Ruby programming")
|
|
95
|
+
# # max_results=10, language="English", include_metadata=false are applied
|
|
96
|
+
|
|
97
|
+
# --- Signature with Nested Structs and Field Descriptions ---
|
|
98
|
+
|
|
99
|
+
class EntityExtraction < DSPy::Signature
|
|
100
|
+
description "Extract named entities from text"
|
|
101
|
+
|
|
102
|
+
class EntityType < T::Enum
|
|
103
|
+
enums do
|
|
104
|
+
Person = new('person')
|
|
105
|
+
Organization = new('organization')
|
|
106
|
+
Location = new('location')
|
|
107
|
+
DateEntity = new('date')
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
class Entity < T::Struct
|
|
112
|
+
const :name, String, description: "The entity text as it appears in the source"
|
|
113
|
+
const :type, EntityType
|
|
114
|
+
const :confidence, Float, description: "Extraction confidence from 0.0 to 1.0"
|
|
115
|
+
const :start_offset, Integer, default: 0
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
input do
|
|
119
|
+
const :text, String
|
|
120
|
+
const :entity_types, T::Array[EntityType], default: [],
|
|
121
|
+
description: "Filter to these entity types; empty means all types"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
output do
|
|
125
|
+
const :entities, T::Array[Entity]
|
|
126
|
+
const :total_found, Integer
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# --- Signature with Union Types ---
|
|
131
|
+
|
|
132
|
+
class FlexibleClassification < DSPy::Signature
|
|
133
|
+
description "Classify input with flexible result type"
|
|
134
|
+
|
|
135
|
+
class Category < T::Enum
|
|
136
|
+
enums do
|
|
137
|
+
Technical = new('technical')
|
|
138
|
+
Business = new('business')
|
|
139
|
+
Personal = new('personal')
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
input do
|
|
144
|
+
const :text, String
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
output do
|
|
148
|
+
const :category, Category
|
|
149
|
+
const :result, T.any(Float, String),
|
|
150
|
+
description: "Numeric score or text explanation depending on classification"
|
|
151
|
+
const :confidence, Float
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# --- Signature with Recursive Types ---
|
|
156
|
+
|
|
157
|
+
class DocumentParser < DSPy::Signature
|
|
158
|
+
description "Parse document into tree structure"
|
|
159
|
+
|
|
160
|
+
class NodeType < T::Enum
|
|
161
|
+
enums do
|
|
162
|
+
Heading = new('heading')
|
|
163
|
+
Paragraph = new('paragraph')
|
|
164
|
+
List = new('list')
|
|
165
|
+
CodeBlock = new('code_block')
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
class TreeNode < T::Struct
|
|
170
|
+
const :node_type, NodeType, description: "The type of document element"
|
|
171
|
+
const :text, String, default: "", description: "Text content of the node"
|
|
172
|
+
const :level, Integer, default: 0
|
|
173
|
+
const :children, T::Array[TreeNode], default: [] # Self-reference → $defs in JSON Schema
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
input do
|
|
177
|
+
const :html, String, description: "Raw HTML to parse"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
output do
|
|
181
|
+
const :root, TreeNode
|
|
182
|
+
const :word_count, Integer
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
# The schema generator creates #/$defs/TreeNode references for recursive types,
|
|
187
|
+
# compatible with OpenAI and Gemini structured outputs.
|
|
188
|
+
# Use `default: []` instead of `T.nilable(T::Array[...])` for OpenAI compatibility.
|
|
189
|
+
|
|
190
|
+
# --- Vision Signature ---
|
|
191
|
+
|
|
192
|
+
class ImageAnalysis < DSPy::Signature
|
|
193
|
+
description "Analyze an image and answer questions about its content"
|
|
194
|
+
|
|
195
|
+
input do
|
|
196
|
+
const :image, DSPy::Image, description: "The image to analyze"
|
|
197
|
+
const :question, String, description: "Question about the image content"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
output do
|
|
201
|
+
const :answer, String
|
|
202
|
+
const :confidence, Float, description: "Confidence in the answer (0.0-1.0)"
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# Vision usage:
|
|
207
|
+
# predictor = DSPy::Predict.new(ImageAnalysis)
|
|
208
|
+
# result = predictor.call(
|
|
209
|
+
# image: DSPy::Image.from_file("path/to/image.jpg"),
|
|
210
|
+
# question: "What objects are visible?"
|
|
211
|
+
# )
|
|
212
|
+
# result.answer # => "The image shows..."
|
|
213
|
+
|
|
214
|
+
# --- Accessing Schemas Programmatically ---
|
|
215
|
+
#
|
|
216
|
+
# SentimentAnalysis.input_json_schema # => { type: "object", properties: { ... } }
|
|
217
|
+
# SentimentAnalysis.output_json_schema # => { type: "object", properties: { ... } }
|
|
218
|
+
#
|
|
219
|
+
# # Field descriptions propagate to JSON Schema
|
|
220
|
+
# Entity.field_descriptions[:name] # => "The entity text as it appears in the source"
|
|
221
|
+
# Entity.field_descriptions[:confidence] # => "Extraction confidence from 0.0 to 1.0"
|